From 43bfc8826ac6ea24d735382408821275ad9e8265 Mon Sep 17 00:00:00 2001 From: Balazs Racz Date: Thu, 19 Aug 2021 15:22:04 +0200 Subject: [PATCH] Optimizes includes (#566) Reduces the compilation footprint by optimizing which files include which other files. This enables writing code that compiles faster. === * Makes the compile flag parametrizable for gcc. * Adds commands to generate statistics about includes. * Adds missing include. * Refactors the SNIP static valuesto a separate include file. * Refactors static includes from memoryconfig into a separate file. * Moves out the declaration of conversion helper functions from If.hxx to a new file Convert.hxx. * Makes the traction throttle interface usable without having a class declaration for traction throttle itself. * Separates the traction throttle interface from the implementation. * Fixes whitespace. * fix hanging brace --- etc/freertos.armv7m.mk | 8 +- etc/prog.mk | 11 + src/openlcb/ConfigEntry.hxx | 5 +- src/openlcb/ConfigRenderer.hxx | 2 +- src/openlcb/ConfigRepresentation.hxx | 2 +- src/openlcb/Convert.hxx | 133 +++++++++++ src/openlcb/Defs.hxx | 3 + src/openlcb/If.hxx | 93 +------- src/openlcb/MemoryConfig.hxx | 228 +----------------- src/openlcb/MemoryConfigDefs.hxx | 279 ++++++++++++++++++++++ src/openlcb/SimpleNodeInfo.hxx | 33 +-- src/openlcb/SimpleNodeInfoDefs.hxx | 78 ++++++ src/openlcb/TractionDefs.hxx | 7 - src/openlcb/TractionTestTrain.cxx | 1 + src/openlcb/TractionThrottle.hxx | 177 +------------- src/openlcb/TractionThrottleInterface.hxx | 231 ++++++++++++++++++ src/openlcb/TrainInterface.hxx | 9 +- src/openlcb/Velocity.hxx | 7 + 18 files changed, 773 insertions(+), 534 deletions(-) create mode 100644 src/openlcb/Convert.hxx create mode 100644 src/openlcb/MemoryConfigDefs.hxx create mode 100644 src/openlcb/SimpleNodeInfoDefs.hxx create mode 100644 src/openlcb/TractionThrottleInterface.hxx diff --git a/etc/freertos.armv7m.mk b/etc/freertos.armv7m.mk index 8782b078c..7b4b288fc 100644 --- a/etc/freertos.armv7m.mk +++ b/etc/freertos.armv7m.mk @@ -48,19 +48,21 @@ ifdef DEBUG_MEMORY_USE ARCHFLAGS += -funwind-tables endif -ASFLAGS = -c $(ARCHFLAGS) +COMPILEOPT = -c + +ASFLAGS = $(COMPILEOPT) $(ARCHFLAGS) CORECFLAGS = $(ARCHFLAGS) -Wall -Werror -Wno-unknown-pragmas \ -fdata-sections -ffunction-sections \ -fno-builtin -fno-stack-protector -mfix-cortex-m3-ldrd \ -D__FreeRTOS__ -DGCC_ARMCM3 -specs=nano.specs -CFLAGS += -c $(ARCHOPTIMIZATION) $(CORECFLAGS) -std=c99 \ +CFLAGS += $(COMPILEOPT) $(ARCHOPTIMIZATION) $(CORECFLAGS) -std=c99 \ -Wstrict-prototypes -D_REENT_SMALL \ $(CFLAGSENV) $(CFLAGSEXTRA) \ -CXXFLAGS += -c $(ARCHOPTIMIZATION) $(CORECFLAGS) -std=c++14 \ +CXXFLAGS += $(COMPILEOPT) $(ARCHOPTIMIZATION) $(CORECFLAGS) -std=c++14 \ -D_ISOC99_SOURCE -D__STDC_FORMAT_MACROS \ -fno-exceptions -fno-rtti \ -Wsuggest-override -Wno-psabi \ diff --git a/etc/prog.mk b/etc/prog.mk index 778568048..325e3e693 100644 --- a/etc/prog.mk +++ b/etc/prog.mk @@ -238,6 +238,17 @@ endif cg.svg: $(EXECUTABLE).ndlst $(OPENMRNPATH)/bin/callgraph.py $(OPENMRNPATH)/bin/callgraph.py --max_indep 6 --min_size $(CGMINSIZE) $(CGARGS) --map $(EXECUTABLE).map < $(EXECUTABLE).ndlst 2> cg.debug.txt | tee cg.dot | dot -Tsvg > cg.svg +incstatsprep: + make -j3 clean + $(MAKE) -j9 -k COMPILEOPT=-E || true + +incstats: incstatsprep + $(MAKE) cincstats + +cincstats: + @find . -name "*.o" | xargs cat | wc -l + @find . -name "*.o" | xargs -L 1 parse-gcc-e.awk | sort -k 2 | group.awk | sort -n > /tmp/stats.txt + -include $(OBJS:.o=.d) -include $(TESTOBJS:.o=.d) diff --git a/src/openlcb/ConfigEntry.hxx b/src/openlcb/ConfigEntry.hxx index a0af9ef0c..1891744e5 100644 --- a/src/openlcb/ConfigEntry.hxx +++ b/src/openlcb/ConfigEntry.hxx @@ -35,9 +35,10 @@ #ifndef _OPENLCB_CONFIGENTRY_HXX_ #define _OPENLCB_CONFIGENTRY_HXX_ -#include -#include #include +#include +#include +#include #include diff --git a/src/openlcb/ConfigRenderer.hxx b/src/openlcb/ConfigRenderer.hxx index cfa078d28..5a39225f0 100644 --- a/src/openlcb/ConfigRenderer.hxx +++ b/src/openlcb/ConfigRenderer.hxx @@ -38,7 +38,7 @@ #include #include -#include "openlcb/SimpleNodeInfo.hxx" +#include "openlcb/SimpleNodeInfoDefs.hxx" #include "utils/OptionalArgs.hxx" #include "utils/StringPrintf.hxx" diff --git a/src/openlcb/ConfigRepresentation.hxx b/src/openlcb/ConfigRepresentation.hxx index 7e7e96c22..0b8e1560b 100644 --- a/src/openlcb/ConfigRepresentation.hxx +++ b/src/openlcb/ConfigRepresentation.hxx @@ -36,7 +36,7 @@ #define _OPENLCB_CONFIGREPRESENTATION_HXX_ #include "openlcb/ConfigEntry.hxx" -#include "openlcb/MemoryConfig.hxx" +#include "openlcb/MemoryConfigDefs.hxx" namespace openlcb { diff --git a/src/openlcb/Convert.hxx b/src/openlcb/Convert.hxx new file mode 100644 index 000000000..23f3f0c97 --- /dev/null +++ b/src/openlcb/Convert.hxx @@ -0,0 +1,133 @@ +/** \copyright + * Copyright (c) 2021, Balazs Racz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \file Convert.hxx + * + * Conversion routines for OpenLCB types. + * + * @author Balazs Racz + * @date 17 Aug 2021 + */ + +#ifndef _OPENLCB_CONVERT_HXX_ +#define _OPENLCB_CONVERT_HXX_ + +#include +#include + +#include "openlcb/Defs.hxx" + +namespace openlcb +{ + +/** Convenience function to render a 48-bit NMRAnet node ID into a new buffer. + * + * @param id is the 48-bit ID to render. + * @returns a new buffer (from the main pool) with 6 bytes of used space, a + * big-endian representation of the node ID. + */ +extern string node_id_to_buffer(NodeID id); +/** Convenience function to render a 48-bit NMRAnet node ID into an existing + * buffer. + * + * @param id is the 48-bit ID to render. + * @param data is the memory space to write the rendered ID into. There must be + * at least 6 bytes available at this address. + */ +extern void node_id_to_data(NodeID id, void *data); + +/** Converts a 6-byte-long buffer to a node ID. + * + * @param buf is a buffer that has to have exactly 6 bytes used, filled with a + * big-endian node id. + * @returns the node id (in host endian). + */ +extern NodeID buffer_to_node_id(const string &buf); +/** Converts 6 bytes of big-endian data to a node ID. + * + * @param d is a pointer to at least 6 valid bytes. + * @returns the node ID represented by the first 6 bytes of d. + */ +extern NodeID data_to_node_id(const void *d); + +/** Converts an Event ID to a Payload suitable to be sent as an event report. */ +extern Payload eventid_to_buffer(uint64_t eventid); + +/** Takes 8 bytes (big-endian) from *data, and returns the event id they + * represent. */ +inline uint64_t data_to_eventid(const void *data) +{ + uint64_t ret = 0; + memcpy(&ret, data, 8); + return be64toh(ret); +} + +/** Formats a payload for response of error response messages such as OPtioanl + * Interaction Rejected or Terminate Due To Error. */ +extern string error_to_buffer(uint16_t error_code, uint16_t mti); + +/** Formats a payload for response of error response messages such as Datagram + * Rejected. */ +extern string error_to_buffer(uint16_t error_code); + +/** Writes an error code into a payload object at a given pointer. */ +extern void error_to_data(uint16_t error_code, void *data); + +/** Parses an error code from a payload object at a given pointer. */ +extern uint16_t data_to_error(const void *data); + +/** Appends an error to the end of an existing buffer. */ +extern void append_error_to_buffer(uint16_t error_code, Payload *p); + +/** Parses the payload of an Optional Interaction Rejected or Terminate Due To + * Error message. + * @param payload is the contents of the incoming addressed message. + * @param error_code will hold the 2-byte error code, or ERROR_PERMANENT if not + * specified + * @param mti will hold the MTI value, or 0 if not specified + * @param error_message will hold all remaining bytes that came with the error + * message. + */ +extern void buffer_to_error(const Payload &payload, uint16_t *error_code, + uint16_t *mti, string *error_message); + +/** A global class / variable for empty or not-yet-initialized payloads. */ +extern string EMPTY_PAYLOAD; + +/// @return the high 4 bytes of a node ID. @param id is the node ID. +inline unsigned node_high(NodeID id) +{ + return id >> 32; +} +/// @return the low 4 bytes of a node ID. @param id is the node ID. +inline unsigned node_low(NodeID id) +{ + return id & 0xffffffffU; +} + +} // namespace openlcb + +#endif diff --git a/src/openlcb/Defs.hxx b/src/openlcb/Defs.hxx index 855e6bb31..8e047b797 100644 --- a/src/openlcb/Defs.hxx +++ b/src/openlcb/Defs.hxx @@ -47,6 +47,9 @@ typedef uint64_t NodeID; /** Alias to a 48-bit NMRAnet Node ID type */ typedef uint16_t NodeAlias; +/// Container that carries the data bytes in an NMRAnet message. +typedef string Payload; + /// Guard value put into the the internal node alias maps when a node ID could /// not be translated to a valid alias. static const NodeAlias NOT_RESPONDING = 0xF000; diff --git a/src/openlcb/If.hxx b/src/openlcb/If.hxx index f6b181bd6..f76384c2c 100644 --- a/src/openlcb/If.hxx +++ b/src/openlcb/If.hxx @@ -38,104 +38,21 @@ /// @todo(balazs.racz) remove this dep #include -#include "openlcb/Node.hxx" -#include "openlcb/Defs.hxx" #include "executor/Dispatcher.hxx" -#include "executor/Service.hxx" #include "executor/Executor.hxx" +#include "executor/Service.hxx" +#include "openlcb/Convert.hxx" +#include "openlcb/Defs.hxx" +#include "openlcb/Node.hxx" #include "utils/Buffer.hxx" -#include "utils/Queue.hxx" #include "utils/Map.hxx" +#include "utils/Queue.hxx" namespace openlcb { class Node; -/// Container that carries the data bytes in an NMRAnet message. -typedef string Payload; - -/** Convenience function to render a 48-bit NMRAnet node ID into a new buffer. - * - * @param id is the 48-bit ID to render. - * @returns a new buffer (from the main pool) with 6 bytes of used space, a - * big-endian representation of the node ID. - */ -extern string node_id_to_buffer(NodeID id); -/** Convenience function to render a 48-bit NMRAnet node ID into an existing - * buffer. - * - * @param id is the 48-bit ID to render. - * @param data is the memory space to write the rendered ID into. There must be - * at least 6 bytes available at this address. - */ -extern void node_id_to_data(NodeID id, void* data); - -/** Converts a 6-byte-long buffer to a node ID. - * - * @param buf is a buffer that has to have exactly 6 bytes used, filled with a - * big-endian node id. - * @returns the node id (in host endian). - */ -extern NodeID buffer_to_node_id(const string& buf); -/** Converts 6 bytes of big-endian data to a node ID. - * - * @param d is a pointer to at least 6 valid bytes. - * @returns the node ID represented by the first 6 bytes of d. - */ -extern NodeID data_to_node_id(const void* d); - -/** Converts an Event ID to a Payload suitable to be sent as an event report. */ -extern Payload eventid_to_buffer(uint64_t eventid); - -/** Takes 8 bytes (big-endian) from *data, and returns the event id they - * represent. */ -inline uint64_t data_to_eventid(const void* data) { - uint64_t ret = 0; - memcpy(&ret, data, 8); - return be64toh(ret); -} - -/** Formats a payload for response of error response messages such as OPtioanl - * Interaction Rejected or Terminate Due To Error. */ -extern string error_to_buffer(uint16_t error_code, uint16_t mti); - -/** Formats a payload for response of error response messages such as Datagram - * Rejected. */ -extern string error_to_buffer(uint16_t error_code); - -/** Writes an error code into a payload object at a given pointer. */ -extern void error_to_data(uint16_t error_code, void* data); - -/** Parses an error code from a payload object at a given pointer. */ -extern uint16_t data_to_error(const void *data); - -/** Appends an error to the end of an existing buffer. */ -extern void append_error_to_buffer(uint16_t error_code, Payload* p); - -/** Parses the payload of an Optional Interaction Rejected or Terminate Due To - * Error message. - * @param payload is the contents of the incoming addressed message. - * @param error_code will hold the 2-byte error code, or ERROR_PERMANENT if not - * specified - * @param mti will hold the MTI value, or 0 if not specified - * @param error_message will hold all remaining bytes that came with the error - * message. - */ -extern void buffer_to_error(const Payload& payload, uint16_t* error_code, uint16_t* mti, string* error_message); - -/** A global class / variable for empty or not-yet-initialized payloads. */ -extern string EMPTY_PAYLOAD; - -/// @return the high 4 bytes of a node ID. @param id is the node ID. -inline unsigned node_high(NodeID id) { - return id >> 32; -} -/// @return the low 4 bytes of a node ID. @param id is the node ID. -inline unsigned node_low(NodeID id) { - return id & 0xffffffffU; -} - /// Helper function to send an event report to the bus. Performs /// synchronous (dynamic) memory allocation so use it sparingly and when /// there is sufficient amount of RAM available. diff --git a/src/openlcb/MemoryConfig.hxx b/src/openlcb/MemoryConfig.hxx index c205ec083..04dd3cffc 100644 --- a/src/openlcb/MemoryConfig.hxx +++ b/src/openlcb/MemoryConfig.hxx @@ -35,12 +35,12 @@ #ifndef _OPENLCB_MEMORYCONFIG_HXX_ #define _OPENLCB_MEMORYCONFIG_HXX_ -#include "openmrn_features.h" #include "openlcb/DatagramDefs.hxx" #include "openlcb/DatagramHandlerDefault.hxx" -#include "openlcb/MemoryConfig.hxx" -#include "utils/Destructable.hxx" +#include "openlcb/MemoryConfigDefs.hxx" +#include "openmrn_features.h" #include "utils/ConfigUpdateService.hxx" +#include "utils/Destructable.hxx" class Notifiable; @@ -55,228 +55,6 @@ extern void reboot(); namespace openlcb { -/// Static constants and helper functions related to the Memory Configuration -/// Protocol. -struct MemoryConfigDefs { - /** Possible Commands for a configuration datagram. - */ - enum commands - { - COMMAND_MASK = 0xFC, - COMMAND_FLAG_MASK = 0x03, /**< mask for special memory space flags */ - COMMAND_PRESENT_MASK = 0x01, /**< mask for address space present bit */ - COMMAND_REPLY_BIT_FOR_RW = 0x10, /**< This bit is present in REPLY commands for read-write commands. */ - - COMMAND_WRITE = 0x00, /**< command to write data to address space */ - COMMAND_WRITE_UNDER_MASK = 0x08, /**< command to write data under mask */ - COMMAND_WRITE_REPLY = 0x10, /**< reply to write data to address space */ - COMMAND_WRITE_FAILED = 0x18, /**< failed to write data to address space */ - COMMAND_WRITE_STREAM = 0x20, /**< command to write data using a stream */ - COMMAND_WRITE_STREAM_REPLY= 0x30, /**< reply to write data using a stream */ - COMMAND_WRITE_STREAM_FAILED= 0x38, /**< failed to write data using a stream */ - COMMAND_READ = 0x40, /**< command to read data from address space */ - COMMAND_READ_REPLY = 0x50, /**< reply to read data from address space */ - COMMAND_READ_FAILED = 0x58, /**< failed to read data from address space */ - COMMAND_READ_STREAM = 0x60, /**< command to read data using a stream */ - COMMAND_MAX_FOR_RW = 0x80, /**< command <= this value have fixed bit arrangement. */ - COMMAND_OPTIONS = 0x80, - COMMAND_OPTIONS_REPLY = 0x82, - COMMAND_INFORMATION = 0x84, - COMMAND_INFORMATION_REPLY = 0x86, - COMMAND_LOCK = 0x88, /**< lock the configuration space */ - COMMAND_LOCK_REPLY = 0x8A, /**< unlock the configuration space */ - COMMAND_UNIQUE_ID = 0x8C, /**< ask for a node unique id */ - COMMAND_UNIQUE_ID_REPLY = 0x8D, /**< node unique id */ - COMMAND_UPDATE_COMPLETE = 0xA8, /**< indicate that a sequence of commands is complete */ - COMMAND_RESET = 0xA9, /**< reset node to its power on state */ - COMMAND_FACTORY_RESET = 0xAA, /**< reset node to factory defaults */ - COMMAND_ENTER_BOOTLOADER = 0xAB, /**< reset node in bootloader mode */ - COMMAND_FREEZE = 0xA1, /**< freeze operation of node */ - COMMAND_UNFREEZE = 0xA0, /**< unfreeze operation of node */ - - COMMAND_PRESENT = 0x01, /**< address space is present */ - - COMMAND_CDI = 0x03, /**< flags for a CDI space */ - COMMAND_ALL_MEMORY = 0x02, /**< flags for an all memory space */ - COMMAND_CONFIG = 0x01, /**< flags for a config memory space */ - }; - - /** Possible memory spaces. - */ - enum spaces - { - SPACE_SPECIAL = 0xFC, /**< offset for the special memory spaces */ - SPACE_CDI = 0xFF, /**< CDI space */ - SPACE_ALL_MEMORY = 0xFE, /**< all memory space */ - SPACE_CONFIG = 0xFD, /**< config memory space */ - SPACE_ACDI_SYS = 0xFC, /**< read-only ACDI space */ - SPACE_ACDI_USR = 0xFB, /**< read-write ACDI space */ - SPACE_FDI = 0xFA, /**< read-only for function definition XML */ - SPACE_FUNCTION = 0xF9, /**< read-write for function data */ - SPACE_DCC_CV = 0xF8, /**< proxy space for DCC functions */ - SPACE_FIRMWARE = 0xEF, /**< firmware upgrade space */ - }; - - /** Possible available options. - */ - enum available - { - AVAIL_WUM = 0x8000, /**< write under mask supported */ - AVAIL_UR = 0x4000, /**< unaligned reads supported */ - AVAIL_UW = 0x2000, /**< unaligned writes supported */ - AVAIL_R0xFC = 0x0800, /**< read from adddress space 0xFC available */ - AVAIL_R0xFB = 0x0400, /**< read from adddress space 0xFB available */ - AVAIL_W0xFB = 0x0200, /**< write from adddress space 0xFB available */ - }; - - /** Possible supported write lengths. - */ - enum lengths - { - LENGTH_1 = 0x80, /**< write length of 1 supported */ - LENGTH_2 = 0x40, /**< write length of 2 supported */ - LENGTH_4 = 0x20, /**< write length of 4 supported */ - LENGTH_63 = 0x10, /**< write length of 64 supported */ - LENGTH_ARBITRARY = 0x02, /**< arbitrary write of any length supported */ - LENGTH_STREAM = 0x01, /**< stream writes supported */ - }; - - /** Possible address space information flags. - */ - enum flags - { - FLAG_RO = 0x01, /**< space is read only */ - FLAG_NZLA = 0x02, /**< space has a nonzero low address */ - }; - - enum errors - { - ERROR_SPACE_NOT_KNOWN = Defs::ERROR_INVALID_ARGS | 0x0001, - ERROR_OUT_OF_BOUNDS = Defs::ERROR_INVALID_ARGS | 0x0002, - ERROR_WRITE_TO_RO = Defs::ERROR_INVALID_ARGS | 0x0003, - }; - - static constexpr unsigned MAX_DATAGRAM_RW_BYTES = 64; - - static bool is_special_space(uint8_t space) { - return space > SPACE_SPECIAL; - } - - static DatagramPayload write_datagram( - uint8_t space, uint32_t offset, const string &data = "") - { - DatagramPayload p; - p.reserve(7 + data.size()); - p.push_back(DatagramDefs::CONFIGURATION); - p.push_back(COMMAND_WRITE); - p.push_back(0xff & (offset >> 24)); - p.push_back(0xff & (offset >> 16)); - p.push_back(0xff & (offset >> 8)); - p.push_back(0xff & (offset)); - if (is_special_space(space)) { - p[1] |= space & ~SPACE_SPECIAL; - } else { - p.push_back(space); - } - p += data; - return p; - } - - static DatagramPayload read_datagram( - uint8_t space, uint32_t offset, uint8_t length) - { - DatagramPayload p; - p.reserve(7); - p.push_back(DatagramDefs::CONFIGURATION); - p.push_back(COMMAND_READ); - p.push_back(0xff & (offset >> 24)); - p.push_back(0xff & (offset >> 16)); - p.push_back(0xff & (offset >> 8)); - p.push_back(0xff & (offset)); - if (is_special_space(space)) { - p[1] |= space & ~SPACE_SPECIAL; - } else { - p.push_back(space); - } - p.push_back(length); - return p; - } - - /// @return true if the payload has minimum number of bytes you need in a - /// read or write datagram message to cover for the necessary fields - /// (command, offset, space). - /// @param payload is a datagram (read or write, request or response) - /// @param extra is the needed bytes after address and space, usually 0 for - /// write and 1 for read. - static bool payload_min_length_check( - const DatagramPayload &payload, unsigned extra) - { - auto *bytes = payload_bytes(payload); - size_t sz = payload.size(); - if (sz < 6 + extra) - { - return false; - } - if (((bytes[1] & COMMAND_FLAG_MASK) == 0) && (sz < 7 + extra)) - { - return false; - } - return true; - } - - /// @return addressed memory space number. - /// @param payload is a read or write datagram request or response message - static uint8_t get_space(const DatagramPayload &payload) - { - auto *bytes = payload_bytes(payload); - if (bytes[1] & COMMAND_FLAG_MASK) - { - return COMMAND_MASK + (bytes[1] & COMMAND_FLAG_MASK); - } - return bytes[6]; - } - - static unsigned get_payload_offset(const DatagramPayload &payload) - { - auto *bytes = payload_bytes(payload); - if (bytes[1] & COMMAND_FLAG_MASK) - { - return 6; - } - else - { - return 7; - } - } - - /// @param payload is a datagram read or write request or response - /// @return the address field from the datagram - static uint32_t get_address(const DatagramPayload &payload) - { - auto *bytes = payload_bytes(payload); - uint32_t a = bytes[2]; - a <<= 8; - a |= bytes[3]; - a <<= 8; - a |= bytes[4]; - a <<= 8; - a |= bytes[5]; - return a; - } - - /// Type casts a DatagramPayload to an array of bytes. - /// @param payload datagram - /// @return byte array pointing to the same memory - static const uint8_t *payload_bytes(const DatagramPayload &payload) - { - return (uint8_t *)payload.data(); - } - -private: - /** Do not instantiate this class. */ - MemoryConfigDefs(); -}; - /// Abstract base class for the address spaces exported via the Memory Config /// Protocol. /// diff --git a/src/openlcb/MemoryConfigDefs.hxx b/src/openlcb/MemoryConfigDefs.hxx new file mode 100644 index 000000000..34432e537 --- /dev/null +++ b/src/openlcb/MemoryConfigDefs.hxx @@ -0,0 +1,279 @@ +/** \copyright + * Copyright (c) 2021, Balazs Racz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \file MemoryConfigDefs.hxx + * + * Declarations related to the memory config protocol + * + * @author Balazs Racz + * @date 17 Aug 2021 + */ + +#ifndef _OPENLCB_MEMORYCONFIGDEFS_HXX_ +#define _OPENLCB_MEMORYCONFIGDEFS_HXX_ + +#include "openlcb/DatagramDefs.hxx" +#include "openlcb/Defs.hxx" +#include "utils/macros.h" + +namespace openlcb +{ + +/// Static constants and helper functions related to the Memory Configuration +/// Protocol. +struct MemoryConfigDefs +{ + using DatagramPayload = string; + + /** Possible Commands for a configuration datagram. + */ + enum commands + { + COMMAND_MASK = 0xFC, + COMMAND_FLAG_MASK = 0x03, /**< mask for special memory space flags */ + COMMAND_PRESENT_MASK = 0x01, /**< mask for address space present bit */ + COMMAND_REPLY_BIT_FOR_RW = 0x10, /**< This bit is present in REPLY commands for read-write commands. */ + + COMMAND_WRITE = 0x00, /**< command to write data to address space */ + COMMAND_WRITE_UNDER_MASK = 0x08, /**< command to write data under mask */ + COMMAND_WRITE_REPLY = 0x10, /**< reply to write data to address space */ + COMMAND_WRITE_FAILED = 0x18, /**< failed to write data to address space */ + COMMAND_WRITE_STREAM = 0x20, /**< command to write data using a stream */ + COMMAND_WRITE_STREAM_REPLY= 0x30, /**< reply to write data using a stream */ + COMMAND_WRITE_STREAM_FAILED= 0x38, /**< failed to write data using a stream */ + COMMAND_READ = 0x40, /**< command to read data from address space */ + COMMAND_READ_REPLY = 0x50, /**< reply to read data from address space */ + COMMAND_READ_FAILED = 0x58, /**< failed to read data from address space */ + COMMAND_READ_STREAM = 0x60, /**< command to read data using a stream */ + COMMAND_MAX_FOR_RW = 0x80, /**< command <= this value have fixed bit arrangement. */ + COMMAND_OPTIONS = 0x80, + COMMAND_OPTIONS_REPLY = 0x82, + COMMAND_INFORMATION = 0x84, + COMMAND_INFORMATION_REPLY = 0x86, + COMMAND_LOCK = 0x88, /**< lock the configuration space */ + COMMAND_LOCK_REPLY = 0x8A, /**< unlock the configuration space */ + COMMAND_UNIQUE_ID = 0x8C, /**< ask for a node unique id */ + COMMAND_UNIQUE_ID_REPLY = 0x8D, /**< node unique id */ + COMMAND_UPDATE_COMPLETE = 0xA8, /**< indicate that a sequence of commands is complete */ + COMMAND_RESET = 0xA9, /**< reset node to its power on state */ + COMMAND_FACTORY_RESET = 0xAA, /**< reset node to factory defaults */ + COMMAND_ENTER_BOOTLOADER = 0xAB, /**< reset node in bootloader mode */ + COMMAND_FREEZE = 0xA1, /**< freeze operation of node */ + COMMAND_UNFREEZE = 0xA0, /**< unfreeze operation of node */ + + COMMAND_PRESENT = 0x01, /**< address space is present */ + + COMMAND_CDI = 0x03, /**< flags for a CDI space */ + COMMAND_ALL_MEMORY = 0x02, /**< flags for an all memory space */ + COMMAND_CONFIG = 0x01, /**< flags for a config memory space */ + }; + + /** Possible memory spaces. + */ + enum spaces + { + SPACE_SPECIAL = 0xFC, /**< offset for the special memory spaces */ + SPACE_CDI = 0xFF, /**< CDI space */ + SPACE_ALL_MEMORY = 0xFE, /**< all memory space */ + SPACE_CONFIG = 0xFD, /**< config memory space */ + SPACE_ACDI_SYS = 0xFC, /**< read-only ACDI space */ + SPACE_ACDI_USR = 0xFB, /**< read-write ACDI space */ + SPACE_FDI = 0xFA, /**< read-only for function definition XML */ + SPACE_FUNCTION = 0xF9, /**< read-write for function data */ + SPACE_DCC_CV = 0xF8, /**< proxy space for DCC functions */ + SPACE_FIRMWARE = 0xEF, /**< firmware upgrade space */ + }; + + /** Possible available options. + */ + enum available + { + AVAIL_WUM = 0x8000, /**< write under mask supported */ + AVAIL_UR = 0x4000, /**< unaligned reads supported */ + AVAIL_UW = 0x2000, /**< unaligned writes supported */ + AVAIL_R0xFC = 0x0800, /**< read from adddress space 0xFC available */ + AVAIL_R0xFB = 0x0400, /**< read from adddress space 0xFB available */ + AVAIL_W0xFB = 0x0200, /**< write from adddress space 0xFB available */ + }; + + /** Possible supported write lengths. + */ + enum lengths + { + LENGTH_1 = 0x80, /**< write length of 1 supported */ + LENGTH_2 = 0x40, /**< write length of 2 supported */ + LENGTH_4 = 0x20, /**< write length of 4 supported */ + LENGTH_63 = 0x10, /**< write length of 64 supported */ + LENGTH_ARBITRARY = 0x02, /**< arbitrary write of any length supported */ + LENGTH_STREAM = 0x01, /**< stream writes supported */ + }; + + /** Possible address space information flags. + */ + enum flags + { + FLAG_RO = 0x01, /**< space is read only */ + FLAG_NZLA = 0x02, /**< space has a nonzero low address */ + }; + + enum errors + { + ERROR_SPACE_NOT_KNOWN = Defs::ERROR_INVALID_ARGS | 0x0001, + ERROR_OUT_OF_BOUNDS = Defs::ERROR_INVALID_ARGS | 0x0002, + ERROR_WRITE_TO_RO = Defs::ERROR_INVALID_ARGS | 0x0003, + }; + + static constexpr unsigned MAX_DATAGRAM_RW_BYTES = 64; + + static bool is_special_space(uint8_t space) + { + return space > SPACE_SPECIAL; + } + + static DatagramPayload write_datagram( + uint8_t space, uint32_t offset, const string &data = "") + { + DatagramPayload p; + p.reserve(7 + data.size()); + p.push_back(DatagramDefs::CONFIGURATION); + p.push_back(COMMAND_WRITE); + p.push_back(0xff & (offset >> 24)); + p.push_back(0xff & (offset >> 16)); + p.push_back(0xff & (offset >> 8)); + p.push_back(0xff & (offset)); + if (is_special_space(space)) + { + p[1] |= space & ~SPACE_SPECIAL; + } + else + { + p.push_back(space); + } + p += data; + return p; + } + + static DatagramPayload read_datagram( + uint8_t space, uint32_t offset, uint8_t length) + { + DatagramPayload p; + p.reserve(7); + p.push_back(DatagramDefs::CONFIGURATION); + p.push_back(COMMAND_READ); + p.push_back(0xff & (offset >> 24)); + p.push_back(0xff & (offset >> 16)); + p.push_back(0xff & (offset >> 8)); + p.push_back(0xff & (offset)); + if (is_special_space(space)) + { + p[1] |= space & ~SPACE_SPECIAL; + } + else + { + p.push_back(space); + } + p.push_back(length); + return p; + } + + /// @return true if the payload has minimum number of bytes you need in a + /// read or write datagram message to cover for the necessary fields + /// (command, offset, space). + /// @param payload is a datagram (read or write, request or response) + /// @param extra is the needed bytes after address and space, usually 0 for + /// write and 1 for read. + static bool payload_min_length_check( + const DatagramPayload &payload, unsigned extra) + { + auto *bytes = payload_bytes(payload); + size_t sz = payload.size(); + if (sz < 6 + extra) + { + return false; + } + if (((bytes[1] & COMMAND_FLAG_MASK) == 0) && (sz < 7 + extra)) + { + return false; + } + return true; + } + + /// @return addressed memory space number. + /// @param payload is a read or write datagram request or response message + static uint8_t get_space(const DatagramPayload &payload) + { + auto *bytes = payload_bytes(payload); + if (bytes[1] & COMMAND_FLAG_MASK) + { + return COMMAND_MASK + (bytes[1] & COMMAND_FLAG_MASK); + } + return bytes[6]; + } + + static unsigned get_payload_offset(const DatagramPayload &payload) + { + auto *bytes = payload_bytes(payload); + if (bytes[1] & COMMAND_FLAG_MASK) + { + return 6; + } + else + { + return 7; + } + } + + /// @param payload is a datagram read or write request or response + /// @return the address field from the datagram + static uint32_t get_address(const DatagramPayload &payload) + { + auto *bytes = payload_bytes(payload); + uint32_t a = bytes[2]; + a <<= 8; + a |= bytes[3]; + a <<= 8; + a |= bytes[4]; + a <<= 8; + a |= bytes[5]; + return a; + } + + /// Type casts a DatagramPayload to an array of bytes. + /// @param payload datagram + /// @return byte array pointing to the same memory + static const uint8_t *payload_bytes(const DatagramPayload &payload) + { + return (uint8_t *)payload.data(); + } + +private: + /** Do not instantiate this class. */ + MemoryConfigDefs(); +}; + +} // namespace openlcb + +#endif // _OPENLCB_MEMORYCONFIGDEFS_HXX_ diff --git a/src/openlcb/SimpleNodeInfo.hxx b/src/openlcb/SimpleNodeInfo.hxx index fbd13d018..f8a3a8346 100644 --- a/src/openlcb/SimpleNodeInfo.hxx +++ b/src/openlcb/SimpleNodeInfo.hxx @@ -37,42 +37,11 @@ #include "openlcb/If.hxx" #include "openlcb/SimpleInfoProtocol.hxx" +#include "openlcb/SimpleNodeInfoDefs.hxx" namespace openlcb { -/// Structure representing the layout of the memory space for Simple Node -/// Identification manufacturer-specified data. -struct SimpleNodeStaticValues -{ - const uint8_t version; - const char manufacturer_name[41]; - const char model_name[41]; - const char hardware_version[21]; - const char software_version[21]; -}; - -/// Structure representing the layout of the memory space for Simple Node -/// Identification user-editable data. -struct SimpleNodeDynamicValues -{ - uint8_t version; - char user_name[63]; - char user_description[64]; -}; - -static_assert(sizeof(struct SimpleNodeDynamicValues) == 128, - "SNIP dynamic file is not of the right size in your compiler"); - -static_assert(sizeof(struct SimpleNodeStaticValues) == 125, - "SNIP static file is not of the right size in your compiler"); - -/** This static data will be exported as the first block of SNIP. The version - * field must contain "4". */ -extern const SimpleNodeStaticValues SNIP_STATIC_DATA; -/** The SNIP dynamic data will be read from this file. It should be 128 bytes - * long, and include the version number of "2" at the beginning. */ -extern const char *const SNIP_DYNAMIC_FILENAME; /** Helper function for test nodes. Fills a file with the given SNIP user * values. */ diff --git a/src/openlcb/SimpleNodeInfoDefs.hxx b/src/openlcb/SimpleNodeInfoDefs.hxx new file mode 100644 index 000000000..bbc618831 --- /dev/null +++ b/src/openlcb/SimpleNodeInfoDefs.hxx @@ -0,0 +1,78 @@ +/** \copyright + * Copyright (c) 2021, Balazs Racz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \file SimpleNodeInfoDefs.hxx + * + * Structure definitions for simple node info. + * + * @author Balazs Racz + * @date 17 Aug 2021 + */ + +#ifndef _OPENLCB_SIMPLENODEINFODEFS_HXX_ +#define _OPENLCB_SIMPLENODEINFODEFS_HXX_ + +#include + +namespace openlcb +{ + +/// Structure representing the layout of the memory space for Simple Node +/// Identification manufacturer-specified data. +struct SimpleNodeStaticValues +{ + const uint8_t version; + const char manufacturer_name[41]; + const char model_name[41]; + const char hardware_version[21]; + const char software_version[21]; +}; + +/// Structure representing the layout of the memory space for Simple Node +/// Identification user-editable data. +struct SimpleNodeDynamicValues +{ + uint8_t version; + char user_name[63]; + char user_description[64]; +}; + +static_assert(sizeof(struct SimpleNodeDynamicValues) == 128, + "SNIP dynamic file is not of the right size in your compiler"); + +static_assert(sizeof(struct SimpleNodeStaticValues) == 125, + "SNIP static file is not of the right size in your compiler"); + +/** This static data will be exported as the first block of SNIP. The version + * field must contain "4". */ +extern const SimpleNodeStaticValues SNIP_STATIC_DATA; +/** The SNIP dynamic data will be read from this file. It should be 128 bytes + * long, and include the version number of "2" at the beginning. */ +extern const char *const SNIP_DYNAMIC_FILENAME; + +} // namespace openlcb + +#endif // _OPENLCB_SIMPLENODEINFODEFS_HXX_ diff --git a/src/openlcb/TractionDefs.hxx b/src/openlcb/TractionDefs.hxx index 8992bcd64..afa241c9a 100644 --- a/src/openlcb/TractionDefs.hxx +++ b/src/openlcb/TractionDefs.hxx @@ -63,13 +63,6 @@ SpeedType fp16_to_speed(const void *fp16); * to.*/ void speed_to_fp16(SpeedType speed, void *fp16); -/** @returns NAN as speed. */ -inline SpeedType nan_to_speed() { - SpeedType s; - s.set_wire(0xFFFFU); - return s; -} - /// Static constants and helper functions for the Traciton protocol family. struct TractionDefs { /// This event should be produced by train nodes. diff --git a/src/openlcb/TractionTestTrain.cxx b/src/openlcb/TractionTestTrain.cxx index d847ca29b..5bcb1a1a1 100644 --- a/src/openlcb/TractionTestTrain.cxx +++ b/src/openlcb/TractionTestTrain.cxx @@ -34,6 +34,7 @@ #include "openlcb/TractionTestTrain.hxx" +#include "openlcb/TractionDefs.hxx" #include "utils/logging.h" namespace openlcb diff --git a/src/openlcb/TractionThrottle.hxx b/src/openlcb/TractionThrottle.hxx index a78be880d..f5d271bc8 100644 --- a/src/openlcb/TractionThrottle.hxx +++ b/src/openlcb/TractionThrottle.hxx @@ -35,191 +35,25 @@ #ifndef _OPENLCB_TRACTIONTHROTTLE_HXX_ #define _OPENLCB_TRACTIONTHROTTLE_HXX_ +#include "executor/CallableFlow.hxx" #include "openlcb/TractionClient.hxx" #include "openlcb/TractionDefs.hxx" +#include "openlcb/TractionThrottleInterface.hxx" #include "openlcb/TrainInterface.hxx" -#include "executor/CallableFlow.hxx" namespace openlcb { -struct TractionThrottleInput; - -/// C++ Namespace for collecting all commands that can be sent to the -/// TractionThrottle flow. -struct TractionThrottleCommands -{ - enum SetDst - { - SET_DST, - }; - - enum AssignTrain - { - ASSIGN_TRAIN, - }; - - enum ReleaseTrain - { - RELEASE_TRAIN, - }; - - enum LoadState - { - LOAD_STATE, - }; - - enum ConsistAdd - { - CONSIST_ADD, - }; - - enum ConsistDel - { - CONSIST_DEL, - }; - - enum ConsistQry - { - CONSIST_QRY, - }; -}; - -/// Request structure used to send requests to the TractionThrottle -/// class. Contains parametrized reset calls for properly supporting -/// @ref StateFlowBase::invoke_subflow_and_wait() syntax. -struct TractionThrottleInput : public CallableFlowRequestBase -{ - enum Command - { - CMD_SET_DST, - CMD_ASSIGN_TRAIN, - CMD_RELEASE_TRAIN, - CMD_LOAD_STATE, - CMD_CONSIST_ADD, - CMD_CONSIST_DEL, - CMD_CONSIST_QRY, - }; - - /// Sets the destination node to send messages to without sending assign - /// commands to that train node. - void reset(const TractionThrottleCommands::SetDst &, const NodeID &dst) - { - cmd = CMD_SET_DST; - this->dst = dst; - } - - void reset(const TractionThrottleCommands::AssignTrain &, const NodeID &dst, - bool listen) - { - cmd = CMD_ASSIGN_TRAIN; - this->dst = dst; - this->flags = listen ? 1 : 0; - } - - void reset(const TractionThrottleCommands::ReleaseTrain &) - { - cmd = CMD_RELEASE_TRAIN; - } - - void reset(const TractionThrottleCommands::LoadState &) - { - cmd = CMD_LOAD_STATE; - } - - void reset(const TractionThrottleCommands::ConsistAdd &, NodeID slave, uint8_t flags) - { - cmd = CMD_CONSIST_ADD; - dst = slave; - this->flags = flags; - } - - void reset(const TractionThrottleCommands::ConsistDel &, NodeID slave) - { - cmd = CMD_CONSIST_DEL; - dst = slave; - } - - void reset(const TractionThrottleCommands::ConsistQry &) - { - cmd = CMD_CONSIST_QRY; - replyCause = 0xff; - } - - void reset(const TractionThrottleCommands::ConsistQry &, uint8_t ofs) - { - cmd = CMD_CONSIST_QRY; - consistIndex = ofs; - replyCause = 0; - } - - Command cmd; - /// For assign, this carries the destination node ID. For consisting - /// requests, this is an in-out argument. - NodeID dst; - /// Contains the flags for the consist listener. Specified for Attach - /// requests, and filled for Query responses. - uint8_t flags; - - /// For assign controller reply REJECTED, this is 1 for controller refused - /// connection, 2 fortrain refused connection. - uint8_t replyCause; - /// Total number of entries in the consisting list. - uint8_t consistCount; - /// Index of the entry in the consisting list that needs to be returned. - uint8_t consistIndex; -}; - -class TractionThrottleInterface - : public openlcb::TrainImpl -{ -public: - /// Flips a function on<>off. - virtual void toggle_fn(uint32_t fn) = 0; - - /// Sends a query for a function to the server. The response will be - /// asynchronously reported by the throttle listener update callback. - /// @param fn function number. - virtual void query_fn(uint32_t fn) - { - } - - /// Determine if a train is currently assigned to this trottle. - /// @return true if a train is assigned, else false - virtual bool is_train_assigned() = 0; - - /// @return the controlling node (virtual node of the throttle, i.e., us.) - /// @todo this function should not be here - virtual openlcb::Node* throttle_node() = 0; - - /// Sets up a callback for listening for remote throttle updates. When a - /// different throttle modifies the train node's state, and the - /// ASSIGN_TRAIN command was executed with "listen==true" parameter, we - /// will get notifications about those remote changes. The notifications - /// update the cached state in TractionThrottle, and call this update - /// callback. Repeat with nullptr if the callbacks are not desired anymore. - /// @param update_callback will be executed when a different throttle - /// changes the train state. fn is the function number changed, or -1 for - /// speed update. - virtual void set_throttle_listener(std::function update_callback) = 0; - - /// @return the controlled node (the train node) ID. - /// @todo this function should not be here - virtual openlcb::NodeID target_node() = 0; -}; - /** Interface for a single throttle for running a train node. * */ -class TractionThrottle - : public CallableFlow, - public TractionThrottleInterface +class TractionThrottle : public TractionThrottleBase { public: /// @param node is the openlcb node from which this throttle will be /// sending its messages. TractionThrottle(Node *node) - : CallableFlow(node->iface()) + : TractionThrottleBase(node->iface()) , node_(node) { clear_cache(); @@ -237,9 +71,6 @@ public: { /// Timeout for assign controller request. TIMEOUT_NSEC = SEC_TO_NSEC(2), - /// Returned from get_fn() when we don't have a cahced value for a - /// function. - FN_NOT_KNOWN = 0xffff, /// Upon a load state request, how far do we go into the function list? MAX_FN_QUERY = 28, ERROR_UNASSIGNED = 0x4000000, diff --git a/src/openlcb/TractionThrottleInterface.hxx b/src/openlcb/TractionThrottleInterface.hxx new file mode 100644 index 000000000..7db13ac4a --- /dev/null +++ b/src/openlcb/TractionThrottleInterface.hxx @@ -0,0 +1,231 @@ +/** \copyright + * Copyright (c) 2021, Balazs Racz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \file TractionThrottleInterface.hxx + * + * Client API for the Traction protocol (declarations only). + * + * @author Balazs Racz + * @date 20 May 2014 + */ + +#ifndef _OPENLCB_TRACTIONTHROTTLEINTERFACE_HXX_ +#define _OPENLCB_TRACTIONTHROTTLEINTERFACE_HXX_ + +#include "executor/CallableFlow.hxx" +#include "openlcb/Defs.hxx" +#include "openlcb/TrainInterface.hxx" + +namespace openlcb +{ + +class Node; +struct TractionThrottleInput; + +/// C++ Namespace for collecting all commands that can be sent to the +/// TractionThrottle flow. +struct TractionThrottleCommands +{ + enum SetDst + { + SET_DST, + }; + + enum AssignTrain + { + ASSIGN_TRAIN, + }; + + enum ReleaseTrain + { + RELEASE_TRAIN, + }; + + enum LoadState + { + LOAD_STATE, + }; + + enum ConsistAdd + { + CONSIST_ADD, + }; + + enum ConsistDel + { + CONSIST_DEL, + }; + + enum ConsistQry + { + CONSIST_QRY, + }; +}; + +/// Request structure used to send requests to the TractionThrottle +/// class. Contains parametrized reset calls for properly supporting +/// @ref StateFlowBase::invoke_subflow_and_wait() syntax. +struct TractionThrottleInput : public CallableFlowRequestBase +{ + enum Command + { + CMD_SET_DST, + CMD_ASSIGN_TRAIN, + CMD_RELEASE_TRAIN, + CMD_LOAD_STATE, + CMD_CONSIST_ADD, + CMD_CONSIST_DEL, + CMD_CONSIST_QRY, + }; + + /// Sets the destination node to send messages to without sending assign + /// commands to that train node. + void reset(const TractionThrottleCommands::SetDst &, const NodeID &dst) + { + cmd = CMD_SET_DST; + this->dst = dst; + } + + void reset(const TractionThrottleCommands::AssignTrain &, const NodeID &dst, + bool listen) + { + cmd = CMD_ASSIGN_TRAIN; + this->dst = dst; + this->flags = listen ? 1 : 0; + } + + void reset(const TractionThrottleCommands::ReleaseTrain &) + { + cmd = CMD_RELEASE_TRAIN; + } + + void reset(const TractionThrottleCommands::LoadState &) + { + cmd = CMD_LOAD_STATE; + } + + void reset(const TractionThrottleCommands::ConsistAdd &, NodeID slave, + uint8_t flags) + { + cmd = CMD_CONSIST_ADD; + dst = slave; + this->flags = flags; + } + + void reset(const TractionThrottleCommands::ConsistDel &, NodeID slave) + { + cmd = CMD_CONSIST_DEL; + dst = slave; + } + + void reset(const TractionThrottleCommands::ConsistQry &) + { + cmd = CMD_CONSIST_QRY; + replyCause = 0xff; + } + + void reset(const TractionThrottleCommands::ConsistQry &, uint8_t ofs) + { + cmd = CMD_CONSIST_QRY; + consistIndex = ofs; + replyCause = 0; + } + + Command cmd; + /// For assign, this carries the destination node ID. For consisting + /// requests, this is an in-out argument. + NodeID dst; + /// Contains the flags for the consist listener. Specified for Attach + /// requests, and filled for Query responses. + uint8_t flags; + + /// For assign controller reply REJECTED, this is 1 for controller refused + /// connection, 2 fortrain refused connection. + uint8_t replyCause; + /// Total number of entries in the consisting list. + uint8_t consistCount; + /// Index of the entry in the consisting list that needs to be returned. + uint8_t consistIndex; +}; + +class TractionThrottleInterface : public openlcb::TrainImpl +{ +public: + /// Flips a function on<>off. + virtual void toggle_fn(uint32_t fn) = 0; + + /// Sends a query for a function to the server. The response will be + /// asynchronously reported by the throttle listener update callback. + /// @param fn function number. + virtual void query_fn(uint32_t fn) + { + } + + /// Determine if a train is currently assigned to this trottle. + /// @return true if a train is assigned, else false + virtual bool is_train_assigned() = 0; + + /// @return the controlling node (virtual node of the throttle, i.e., us.) + /// @todo this function should not be here + virtual openlcb::Node *throttle_node() = 0; + + /// Sets up a callback for listening for remote throttle updates. When a + /// different throttle modifies the train node's state, and the + /// ASSIGN_TRAIN command was executed with "listen==true" parameter, we + /// will get notifications about those remote changes. The notifications + /// update the cached state in TractionThrottle, and call this update + /// callback. Repeat with nullptr if the callbacks are not desired anymore. + /// @param update_callback will be executed when a different throttle + /// changes the train state. fn is the function number changed, or -1 for + /// speed update. + virtual void set_throttle_listener( + std::function update_callback) = 0; + + /// @return the controlled node (the train node) ID. + /// @todo this function should not be here + virtual openlcb::NodeID target_node() = 0; +}; + +class TractionThrottleBase : public CallableFlow, + public TractionThrottleInterface +{ +public: + TractionThrottleBase(Service *s) + : CallableFlow(s) + { + } + + enum + { + /// Returned from get_fn() when we don't have a cahced value for a + /// function. + FN_NOT_KNOWN = 0xffff, + }; +}; + +} // namespace openlcb + +#endif // _OPENLCB_TRACTIONTHROTTLEINTERFACE_HXX_ diff --git a/src/openlcb/TrainInterface.hxx b/src/openlcb/TrainInterface.hxx index 74fbd167c..d2ffefaa7 100644 --- a/src/openlcb/TrainInterface.hxx +++ b/src/openlcb/TrainInterface.hxx @@ -35,10 +35,15 @@ #ifndef _OPENLCB_TRAININTERFACE_HXX_ #define _OPENLCB_TRAININTERFACE_HXX_ -#include "openlcb/TractionDefs.hxx" #include "dcc/Defs.hxx" +#include "openlcb/Velocity.hxx" -namespace openlcb { +namespace openlcb +{ + +/// Represents an OpenLCB speed value with accessors to convert to and from +/// various formats. +typedef Velocity SpeedType; /// Abstract base class for train implementations. This interface links the /// OpenLCB trains to the dcc packet sources. diff --git a/src/openlcb/Velocity.hxx b/src/openlcb/Velocity.hxx index 9a5426304..4abbae791 100644 --- a/src/openlcb/Velocity.hxx +++ b/src/openlcb/Velocity.hxx @@ -486,6 +486,13 @@ private: } }; +/** @returns NAN as speed. */ +inline Velocity nan_to_speed() +{ + Velocity s; + s.set_wire(0xFFFFU); + return s; +} }; /* namespace openlcb */