///////////////////////////////////////////////////////////////////// // // // file: aBrainStem-core.h // // // ///////////////////////////////////////////////////////////////////// // // // description: BrainStem API's and support. // // // // // ///////////////////////////////////////////////////////////////////// // // // Copyright (c) 2018 Acroname Inc. - All Rights Reserved // // // // This file is part of the BrainStem release. See the license.txt // // file included with this package or go to // // https://acroname.com/software/brainstem-development-kit // // for full license details. // ///////////////////////////////////////////////////////////////////// #ifndef __BrainStem_core_H__ #define __BrainStem_core_H__ #if defined(__cplusplus) #include #include #include #include #include #include #include #endif//defined(__cplusplus) #ifdef _WIN32 #include #include #ifndef in_addr_t #define in_addr_t uint32_t #endif #else // Linux #include #include #include #endif #include "BrainStem-C.h" #include "aProtocoldefs.h" #if defined(__cplusplus) using std::list; namespace Acroname { namespace BrainStem { /// aEtherConfig Class /// This class provides basic configurations to the underlying Client-Server model. class aEtherConfig { public: /// aEtherConfig Constructor. This configuration will result in the smoothest user experience. /// NOTE: If localOnly == false AND networkInterface is default (0 or LOCALHOST_IP_ADDRESS) /// it will be populated with the auto-selected interface upon successful connection. aEtherConfig() : enabled(true), fallback(true), localOnly(true), assignedPort(0), networkInterface(LOCALHOST_IP_ADDRESS) {} bool enabled; /**< True: Client-Server module is used; False: Direct module control is used.*/ bool fallback; /**< True: If connections fails it will automatically search for network connections; */ bool localOnly; /**< True: Restricts access to localhost; False: Expose device to external network */ uint16_t assignedPort; /**< Server assigned port after successful connection*/ uint32_t networkInterface; /**< Network interface to use for connections.*/ }; /// LinkClass: /// The Link class provides an interface to a BrainStem link. /// The link is used to create interfaces to modules on a BrainStem network. /// The link represents a connection to the BrainStem network from a host computer. /// The link is always associated with a transport (e.g.: USB, Ethernet, etc.) and a /// link module, but there are several ways to make this association.\n /// -# The link can be fully specified with a transport and module serial number /// -# The link can be created by searching a transport and connecting to the first /// module found. /// /// Calling connect on a link will start a connection to the module based on /// The link specification. Calling disconnect will disconnect the link from /// the the current connection. class aLIBEXPORT Link { public: /// Gets the links current aEther configuration /// \param config Pointer to the configuration to be filled /// \return aErrNone on success; aErrParam if config is NULL aErr getConfig(aEtherConfig* config); /// Sets the links aEther configuration. /// Configuration must be applied BEFORE connecting /// \param config Configuration to be applied /// \return aErrNone on success. aErrPermission if the module is currently connected. aErr setConfig(const aEtherConfig config); /// Discover is called with a specified transport to search for /// link modules on that transport. The callback is called with /// a fully filled in specifier for any link module found. The sDiscover returns /// aErrNone if the discovery process is successful, regardless of if any links /// are found. An error is only returned if the link discovery /// process fails. Discovery can take some time. /// The callback will occur in the same thread context as this routine call. /// \param type Transport to search for available BrainStem link modules /// on. See the \ref linkType "transport" enum for supported transports. /// \param cbLinkFound Process that is called when a module is discovered. /// \param vpCBRef This is passed to cbLinkFound when a module is discovered. /// \retval aErrNone on success. /// \retval aErrNotFound if no devices were found. static aErr sDiscover(const linkType type, aDiscoveryModuleFoundProc cbLinkFound, void* vpCBRef, const uint32_t networkInterface = LOCALHOST_IP_ADDRESS) { aErr err = aErrNone; uint8_t count = 0; count = aDiscovery_EnumerateModules(type, cbLinkFound, vpCBRef, networkInterface); if (count == 0) { err = aErrNotFound; } return err; }; /// sFindAll is a callback function which matches any found stem. /// SFindAll is used by sDiscover(const linkType, list*) to /// fill the list provided with any found modules on the specified link /// type. /// \param spec The linkspec pointer for the device currently being /// evaluated. /// \param bSuccess a returned value indicating whether the search has /// succeeded. /// \param vpCBRef Reference pointer to the std::list that was passed in. /// \retval true Caller should continue to call this function. /// \retval false Caller should stop calling this function. static bContinueSearch sFindAll(const linkSpec* spec, bool* bSuccess, void* vpCBRef) { list* pSpecs = (std::list*)vpCBRef; pSpecs->push_back(*spec); *bSuccess = true; return true; } /// Discover is called with a specified transport to search for /// link modules on that transport. The devices list is filled with device /// specifiers. sDiscover returns aErrNone if the discovery process is /// successful, regardless of whether any links /// are found. An error is only returned if the link discovery /// process fails. Discovery can take some time. /// \param type Transport to search for available BrainStem link modules /// on. See the \ref linkType "transport" enum for supported transports. /// \param devices an empty list of specifiers that will be filled in. /// \retval aErrNotFound if no devices were found. /// \retval aErrNone on success. static aErr sDiscover(const linkType type, list* devices, const uint32_t networkInterface = LOCALHOST_IP_ADDRESS) { return sDiscover(type, sFindAll, devices, networkInterface); }; /// Link Constructor. Takes a fully specified linkSpec pointer and creates /// a link instance with this specifier information. /// \param linkSpecifier The connection details for a specific module. /// \param name A name for the link to be created. /// This name can be used to reference the link during later interactions. Link(const linkSpec linkSpecifier, const char* name = "Link"); /// Link constructor without a specifier will most likely use the /// discoverAndConnect call to create a connection to a link module. /// \param name A name for the link to be created. Link(const char* name = "Link"); /// Destructor. ~Link(void); /// A discovery-based connect. /// This member function will connect to the first available BrainStem /// found on the given transport. If the /// serial number is passed, it will only connect to the module with that serial number. /// Passing 0 as the serial number will create a link to the first link module found /// on the specified transport. /// If a link module is found on the specified transport, a connection will be made. /// \param type Transport on which to search for available BrainStem link /// modules. See the \ref linkType "transport" enum for supported transports. /// \param serialNumber Specify a serial number to connect to a specific /// link module. Use 0 to connect to the first link module found. /// \param model Acroname model number for the device. /// \retval aErrBusy if the module is already in use. /// \retval aErrParam if the transport type is undefined. /// \retval aErrNotFound if the module cannot be found or if no modules found. /// \retval aErrNone If the connect was successful. aErr discoverAndConnect(const linkType type, const uint32_t serialNumber = 0, const uint8_t model = 0); /// Connect to a link with a fully defined specifier. /// \retval aErrBusy if the module is running, starting or stopping. Try again in a bit. /// \retval aErrDuplicate If the module is already connected and running. /// \retval aErrConnection If there was an error with the connection. User needs to disconnect, then reconnect. /// \retval aErrConfiguration If the link has an invalid linkSpec. /// \retval aErrNotFound if the module cannot be found. /// \retval aErrNone If the connect was successful. aErr connect(void); /// Connect using a pre-existing link. /// This member function will connect to the same BrainStem used by given Link. /// If a link module is found on the specified transport, a connection will be made. /// \param link - Reference to the link to be used. /// \retval aErrInitialization If the referenced link does not exist yet. /// \retval aErrConnection If the connection could not be made. /// \retval aErrConfiguration If the device or connection is in properly configured. /// \retval aErrNone if the connect was successful. aErr connectThroughLinkModule(Link& link); /// Check to see if a module is connected. /// isConnected looks for a connection to an active module. /// \return true: connected, false: not connected. bool isConnected(void); /// Check the status of the module connection. /// \return linkStatus (see aLink.h for status values) linkStatus getStatus(void); /// Disconnect from the BrainStem module. /// \retval aErrResource If the there is no valid connection. /// \retval aErrConnection If the disconnect failed, due to a /// communication issue. /// \retval aErrNone If the disconnect was successful. aErr disconnect(void); /// Reset The underlying link stream. /// \retval aErrResource If the there is no valid connection. /// \retval aErrConnection If the reset failed, due to a /// communication issue. /// \retval aErrNone If the reset was successful. aErr reset(void); ///////////////////////////////////////////////////////////////////// // // access routines // ///////////////////////////////////////////////////////////////////// /// Accessor for link Name. /// Returns a pointer to the string representing the link. This string /// is part of the link, and will be destroyed with it. If you need access /// to the link name beyond the life of the link, then copy the char* returned. /// \return Pointer to character array containing the name of the link. const char* getName(void); /// Accessor for current link specification. /// \param spec - an allocated empty link spec reference. /// \return aErrNotFound - If no linkSpec set for current link. aErr getLinkSpecifier(linkSpec* spec); /// Accessor Set current link specification. /// \param linkSpecifier - The specifier that will replace the current spec. /// \return aErrBusy - If link is currently connected. aErr setLinkSpecifier(const linkSpec linkSpecifier); /// Gets the module address of the module the link is connected too. /// A zero is returned if no module can not be determined or /// if the link is not connected. aErr getModuleAddress(uint8_t * address); ///////////////////////////////////////////////////////////////////// // // Send/Receive Packets to/from the Brainstem // ///////////////////////////////////////////////////////////////////// /// Sends a BrainStem protocol UEI packet on the link. /// This is an advanced interface, please see the relevant section of the /// reference manual for more information about UEIs. /// \param packet The command UEI packet to send. /// \retval aErrConnection link not connected. /// \retval aErrParam data too long or short. /// \retval aErrPacket invalid module address. /// \retval aErrNone success. aErr sendUEI(const uei packet); /// Sends a BrainStem protocol UEI packet on the link where the packet contains /// a subindex. /// This is an advanced interface, please see the relevant section of the /// reference manual for more information about UEIs. /// \param packet The command UEI packet to send. /// \param subindex The subindex of the command option. /// \retval aErrConnection link not connected. /// \retval aErrParam data too long or short. /// \retval aErrPacket invalid module address. /// \retval aErrNone success. aErr sendUEI(const uei packet, const uint8_t subindex); /// Awaits receipt of the first available matching UEI packet /// from the link. The first four arguments describe the packet to wait for. /// When successful, the supplied uei ref is filled with the received UEI. /// This is an advanced interface, please see the relevant section of the /// reference manual for more information about UEIs. /// \param module The module address. /// \param command The command. /// \param option The uei option. /// \param index The index of the uei entity. /// \param packet The uei packet reference to be filled on success. /// \retval aErrConnection link not connected. /// \retval aErrPacket invalid module address. /// \retval aErrTimeout no packet available. /// \retval aErrNone success. aErr receiveUEI(const uint8_t module, const uint8_t command, const uint8_t option, const uint8_t index, uei* packet); /// Awaits receipt of the first available matching UEI packet /// from the link. The first four arguments and proc describe the packet to wait for. /// When successful, the supplied uei ref is filled with the received UEI. /// This is an advanced interface, please see the relevant section of the /// reference manual for more information about UEIs. /// \param module The module address. /// \param command The command. /// \param option The uei option. /// \param index The index of the uei entity. /// \param packet The uei packet reference to be filled on success. /// \param proc The callback used for determining a matching packet. /// \retval aErrConnection link not connected. /// \retval aErrPacket invalid module address. /// \retval aErrTimeout no packet available. /// \retval aErrNone success. aErr receiveUEI(const uint8_t module, const uint8_t command, const uint8_t option, const uint8_t index, uei* packet, aPacketMatchPacketProc proc); /// Drops all existing queued packets that match. /// from the link. /// The arguments describe the packets to be matched /// This is an advanced interface, please see the relevant section of the /// reference manual for more information about UEIs. /// \param module The module address. /// \param command The command. /// \param option The uei option. /// \param index The index of the uei entity. /// \retval aErrConnection link not connected. /// \retval aErrPacket invalid module address. /// \retval aErrNone success. aErr dropMatchingUEIPackets(const uint8_t module, const uint8_t command, const uint8_t option, const uint8_t index); /// Sends a raw BrainStem protocol packet on the link. /// where the length does not include the module or the command. /// address byte and can be 0 to aBRAINSTEM_MAXPACKETBYTES - 1. /// This is an advanced interface, please see the relevant section of the /// reference manual for more information about BrainStem Packet protocol. /// \param module The address of the destination module. /// \param command The length of the data being sent. /// \param length The length of the data being sent. /// \param data The data to send. /// \retval aErrConnection link not connected. /// \retval aErrParam data too long or short. /// \retval aErrPacket invalid module address. /// \retval aErrNone success. aErr sendPacket(const uint8_t module, const uint8_t command, const uint8_t length, const uint8_t* data); /// Awaits receipt of the first available matching raw BrainStem protocol packet /// from the link where the length does not include the module or command bytes and can be zero. /// The provided module and match array are compared to packets available and the first match is /// returned. The supplied data pointer must point to at least aBRAINSTEM_MAXPACKETBYTES - 1 bytes. /// When successful, the data is filled in with the packet data /// not including the module and command and the length pointer /// is updated with the length of the returned data. /// /// This is an advanced interface, please see the relevant section of the /// reference manual for more information about BrainStem Packet protocol. /// \param module The module address. /// \param match A byte array of the values to match for received packets. /// \param length The length of the match data on entry and length of the returned data filled on success. /// \param data The data filled on success. /// \retval aErrConnection link not connected. /// \retval aErrPacket invalid module address. /// \retval aErrTimeout no packet available. /// \retval aErrNone success. aErr receivePacket(const uint8_t module, const uint8_t* match, uint8_t* length, uint8_t* data); ///////////////////////////////////////////////////////////////////// // // Routines for handling slots at the module // ///////////////////////////////////////////////////////////////////// /// Loads data into a BrainStem Slot. See the relevant section of the BrainStem /// reference for information about BrainStem Slots and Stores. /// \param module - Module address. /// \param store - BrainStem store to access, possibilities include Internal, RAM, and SD. /// \param slot - The Slot within the Brainstem store to place the data. /// \param pData - Pointer to a buffer containing the data to load. /// \param length - The length in bytes of the data buffer to write. /// \retval aErrConnection link not connected. /// \retval aErrParam invalid module address. /// \retval aErrCancel The write process is closing and this call /// was unable to successfully complete. /// \retval aErrNone success. aErr loadStoreSlot(const uint8_t module, const uint8_t store, const uint8_t slot, const uint8_t* pData, const size_t length); /// Unloads data from a BrainStem Slot. If there are no read // errors but the dataLength supplied is less than the actual slot size, // an error of aErrOverrun is returned. See the relevant section of the BrainStem /// reference for information about BrainStem Slots and Stores. /// \param module - Module address. /// \param store - BrainStem store to access, possibilities include Internal, RAM, and SD. /// \param slot - The Slot within the Brainstem store to place the data. /// \param pData - Pointer to a buffer with dataLength space in bytes that will be filled by the call. /// \param dataLength - Expected length of the data, and at most the size of the pData buffer. /// \param pNRead - The number of bytes actually read. /// \retval aErrConnection link not connected. /// \retval aErrParam invalid module address. /// \retval aErrCancel The write process is closing and this call /// was unable to successfully complete. /// \retval aErrOverrun The read would overrun the buffer, i.e there is more data in the slot than the buffer can handle. /// \retval aErrNone success. aErr unloadStoreSlot(const uint8_t module, const uint8_t store, const uint8_t slot, uint8_t* pData, const size_t dataLength, size_t* pNRead); /// Returns the current size of the data loaded in the slot specified. /// \param module - Module address. /// \param store - BrainStem store to access, possibilities include Internal, RAM, and SD. /// \param slot - The Slot within the Brainstem store to place the data. /// \param size - size in bytes of the data stored in the slot. /// \retval aErrConnection link not connected. /// \retval aErrParam invalid module address. /// \retval aErrCancel The write process is closing and this request /// was unable to successfully complete. /// \retval aErrNone success. aErr storeSlotSize(const uint8_t module, const uint8_t store, const uint8_t slot, size_t* size); /// Returns the maximum data capacity of the slot specified. /// \param module - Module address. /// \param store - BrainStem store to access, possibilities include Internal, RAM, and SD. /// \param slot - The Slot within the Brainstem store to place the data. /// \param capacity - size in bytes of the data stored in the slot. /// \retval aErrConnection link not connected. /// \retval aErrParam invalid module address. /// \retval aErrCancel The write process is closing and this request /// was unable to successfully complete. /// \retval aErrNone success. aErr storeSlotCapacity(const uint8_t module, const uint8_t store, const uint8_t slot, size_t* capacity); static const uint8_t STREAM_WILDCARD = 0xFF; /// Enumeration of stream packet types. typedef enum STREAM_PACKET { kSTREAM_PACKET_UNKNOWN, kSTREAM_PACKET_U8, kSTREAM_PACKET_U16, kSTREAM_PACKET_U32, kSTREAM_PACKET_BYTES, kSTREAM_PACKET_SUBINDEX_U8, kSTREAM_PACKET_SUBINDEX_U16, kSTREAM_PACKET_SUBINDEX_U32, kSTREAM_PACKET_LAST } STREAM_PACKET_t; /// Decodes the streaming packet type from a provided packet. /// \param packet - The packet to be interrogated. /// \param type - variable to be populated. Filled with kSTREAM_PACKET_UNKNOWN on failure. /// \return true on success; false on failure. static bool getStreamPacketType(const aPacket* packet, STREAM_PACKET_t* type); /// Helper function for indicating wether the packet is a subindex type. /// The subindex can be queried through Link::getStreamKeyElement /// \param type - The element to evaluate. /// \return true if the type contains a subindex; false if it does not. static bool isSubindexType(STREAM_PACKET_t type); ///Function signature for streaming callbacks. /// \param packet reference to streaming packet /// \param pRef User provided reference /// \return non zero error code on failure. /// Return value is not currently used. typedef std::function< uint8_t(const aPacket* packet, void* pRef) > streamCallback_t; /// Enables streaming for the supplied criteria. /// \param moduleAddress Address to filter on. /// \param cmd cmd to filter by (supports Wildcards) /// \param option option to filter by (supports Wildcards) /// \param index index to filter by (supports Wildcards) /// \param enable True - Enables streaming; False - disables streaming aErr enableStream(const uint8_t moduleAddress, const uint8_t cmd, const uint8_t option, const uint8_t index, const bool enable); /// Determines if the module is actively streaming. /// Does not indicate what is streaming, only if streaming is currently active. /// \param moduleAddress The devices module address. /// \param enabled Variable to be populated. /// \return Returns \ref EntityReturnValues "common entity" return values aErr isLinkStreaming(const uint8_t moduleAddress, uint8_t* enabled); /// Registers a callback function based on a specific module, cmd, option, and index. /// \param moduleAddress Address to filter on (supports Wildcards) /// \param cmd cmd to filter by (supports Wildcards) /// \param option option to filter by (supports Wildcards) /// \param index index to filter by (supports Wildcards) /// \param enable True - installs/updates callback and ref; False - uninstalls callback /// \param cb Callback to be executed when a new packet matching the criteria is received. /// \param pRef Pointer to user reference for use inside the callback function. /// \return aErrNotFound - Item not found (uninstalling only) /// \return aErrNone - success aErr registerStreamCallback(const uint8_t moduleAddress, const uint8_t cmd, const uint8_t option, const uint8_t index, const bool enable, streamCallback_t cb, void* pRef); /// Gets stream value based on the search criteria /// \param moduleAddress Address to filter on (supports Wildcards) /// \param cmd cmd to filter by (supports Wildcards) /// \param option option to filter by (supports Wildcards) /// \param index index to filter by (supports Wildcards) /// \return aErrStreamStale if the value has not been updated since the last read. /// \return aErrNotFound if no such stream element exists. /// \return aErrNone - success aErr getStreamValue(const uint8_t moduleAddress, const uint8_t cmd, const uint8_t option, const uint8_t index, const uint8_t subindex, uint32_t* value); /// StreamStatusEntry structure - It contains members of streaming entries /// in the form of key value pairs. Keys are comprised of the devices module address, /// command, option, index, and subindex API values. typedef struct StreamStatusEntry { uint64_t key; /**< The stream key. */ uint32_t value; /**< The value associated with the key */ } StreamStatusEntry_t; /// Gets all available stream values based on the search criteria. /// \param moduleAddress Address to filter on (supports Wildcards) /// \param cmd cmd to filter by (supports Wildcards) /// \param option option to filter by (supports Wildcards) /// \param index index to filter by (supports Wildcards) /// \param subindex subindex to filter by (supports Wildcards) /// \param buffer Buffer of user allocated memory to be filled with stream data /// Note: Link::getStreamKeyElement should be used to decode the keys /// \param bufferLength Number of elements the buffer can hold. /// \param unloadedSize Number of elements that were placed in the buffer /// \return aErrParam if status or unloadedSize is null /// \return aErrNone - success aErr getStreamStatus(const uint8_t moduleAddress, const uint8_t cmd, const uint8_t option, const uint8_t index, const uint8_t subindex, StreamStatusEntry_t* buffer, const size_t bufferLength, size_t* unloadedSize); /// Provides a list of active stream keys based on the supplied criteria. /// Exposed for unit-testing purposes only. /// \param moduleAddress Address to filter on (supports Wildcards) /// \param cmd cmd to filter by (supports Wildcards) /// \param option option to filter by (supports Wildcards) /// \param index index to filter by (supports Wildcards) /// \param acquireLock Option to acquire mutex before getting list elements. /// \return List of keys meeting the search criteria std::vector filterActiveStreamKeys(const uint8_t moduleAddress, const uint8_t cmd, const uint8_t option, const uint8_t index, const uint8_t subindex, const bool acquireLock); /// Enumeration for element types within a stream key. typedef enum STREAM_KEY { STREAM_KEY_MODULE_ADDRESS, STREAM_KEY_CMD, STREAM_KEY_OPTION, STREAM_KEY_INDEX, STREAM_KEY_SUBINDEX, STREAM_KEY_LAST, } STREAM_KEY_t; static uint64_t createStreamKey(uint8_t moduleAddress, uint8_t cmd, uint8_t option, uint8_t index, uint8_t subindex); /// Convenience function to unpack a stream key. /// Note: This function will assert if an out of range STREAM_KEY_t is used. /// \param key The key to be unpacked /// \param element The element to unpack from the key. /// \return The requested element from the key. static uint8_t getStreamKeyElement(const uint64_t key, STREAM_KEY_t element); ///Convenience function to determine wether the value is a stream packet. /// Stream "Packets" encompass all STREAM_PACKET_t valid elements. /// \param packet UEI stream packet to be checked. /// \return Wether the packet is a stream sample or not static bool isStreamPacket(const aPacket* packet); /// Convenience function to determine wether the value is a stream sample. /// Stream "Sample" encompasses all STREAM_KEY_t except for kSTREAM_PACKET_BYTES /// which have a varied structure and depend on the cmd/option/index. /// Calling isStreamPacket prior is not required as this function will verify the packet type /// \param packet UEI stream packet to be checked. /// \return Wether the packet is a stream sample or not static bool isStreamSample(const aPacket* packet); /// Convenience function to unpack the stream samples timestamp and value. /// Calling isStreamSample prior is not required as this function will verify the packet type. /// \param packet UEI stream packet to be unpacked. /// \param timestamp Variable to be filled with stream sample timestamp. (optional) /// \param value Variable to be filled with the stream sample (optional). /// May require casting to signed value depending on the cmd/option code. /// \retval aErrPacket Not a stream packet /// \retval aErrUnknown Unknown decoding issue. /// \retval aErrNone success. static aErr getStreamSample(const aPacket* packet, uint64_t* timestamp = NULL, uint32_t* value = NULL, uint8_t* subindex = NULL); /// Helper function for extracting the parts of a timestamp. /// \param timestamp - Value acquired from Link::getStreamSample /// \param seconds - Seconds element from timestamp. /// Refers to the seconds since firmware boot. /// \param uSeconds - Micro second element from the timestamp. /// Refers to the micro seconds from firmware boot. /// Micro seconds rolls over to seconds. Value range: 0-99999 static void getTimestampParts(const uint64_t timestamp, uint32_t* seconds, uint32_t* uSeconds); /// Enables pooling of outgoing BrainStem packets. /// Allowing multiple packets to be packed into a single transaction frame. /// \param enable True = Enables; False = Disables aErr enablePooledPackets(const bool enable); ///////////////////////////////////////////////////////////////////// // // Routines to handle packet logging // ///////////////////////////////////////////////////////////////////// /// Enable Packet logging. /// /// Enable packet logging for this link. Enables the packet logging buffer, and writes /// packet traffic out to the file specified by logname. /// \param logname the path and filename indicating where to write the packet log. /// \return aErr returns appropriate errors if it fails to enable the packet log. aErr enablePacketLog(const char* logname); /// Disable Packet logging. /// /// disable packet logging for this link. Disables the packet log. /// \return aErr returns appropriate errors if it fails to disable the debug log. aErr disablePacketLog(void); /// Filter function for Streaming packets. This is used internally whenever streaming /// is enabled. Exposed for unit-testing purposes only. /// \param packet UEI stream packet to be checked/filtered. /// \param ref Opaque reference handle static bool linkStreamFilter(const aPacket* packet, void* ref); /// For Internal use only! aErr getFactoryData(const uint8_t module, const uint8_t command, uint8_t* pData, const size_t dataLength, size_t* unloadedLength); /// For Internal use only! aErr setFactoryData(const uint8_t module, const uint8_t command, const uint8_t* pData, const size_t dataLength); private: class impl; impl* zit; }; /// ModuleClass: /// The Module class provides a generic interface to a BrainStem hardware module. /// The Module class is the parent class for all BrainStem modules. Each module /// inherits from Module and implements its hardware specific features. class aLIBEXPORT Module { public: /// Constructor. Implicitly creates a link object with no specifier. Most often objects /// created with this constructor will use linkDiscoverAndConnect to find and connect to a module. /// \param address The BrainStem network address of the module. The default address /// (or base address for modules that support address offsets) is defined in each /// module's "Defs.h" header. /// \param model Acroname model number. Module(const uint8_t address, const uint8_t model = 0); Module(const uint8_t address, bool bAutoNetworking, const uint8_t model = 0); /// Destructor. virtual ~Module(void); /// Connect using the current link specifier. /// \param type - Transport on which to search for available BrainStem link /// modules. See the \ref linkType "transport" enum for supported transports. /// \param serialNum - Specify a serial number to connect to a specific /// link module. Use 0 to connect to the first link module found. /// \retval aErrBusy if the module is already in use. /// \retval aErrParam if the type is incorrect or serialNum is not specified /// \retval aErrNotFound if the module cannot be found. /// \retval aErrNone If the connect was successful. aErr connect(const linkType type, const uint32_t serialNum); /// Connect to a link with a fully defined specifier. /// \param linkSpecifier - Connect to module with specifier. /// \retval aErrInitialization If there is currently no link object. /// \retval aErrBusy If the link is currently connected. /// \retval aErrParam if the specifier is incorrect. /// \retval aErrNotFound if the module cannot be found. /// \retval aErrNone If the connect was successful. aErr connectFromSpec(const linkSpec linkSpecifier); /// A discovery-based connect. /// This member function will connect to the first available BrainStem /// found on the given transport. If the /// serial number is passed, it will only connect to the module with that serial number. /// Passing 0 as the serial number will create a link to the first link module found /// on the specified transport. /// If a link module is found on the specified transport, a connection will /// \param type - Transport on which to search for available BrainStem link /// modules. See the \ref linkType "transport" enum for supported transports. /// \param serialNum - Specify a serial number to connect to a specific /// link module. Use 0 to connect to the first link module found. /// \retval aErrBusy if the module is already in use. /// \retval aErrParam if the transport type is undefined. /// \retval aErrNotFound if the module cannot be found. /// \retval aErrNone If the connect was successful. aErr discoverAndConnect(linkType type, const uint32_t serialNum = 0); /// Connect using link from another Module. /// This member function will connect to the same BrainStem used by given Module. /// If a link module is found on the specified transport, a connection will be made /// \param pModule - Pointer to a valid Module class object. /// \retval aErrParam if the module is undefined. /// \retval aErrNone if the connect was successful. aErr connectThroughLinkModule(Module* pModule); /// Is the link connected to the BrainStem Module. bool isConnected(void); /// Check the status of the BrainStem module connection. /// \return linkStatus (see aLink.h for status values) linkStatus getStatus(void); /// Disconnect from the BrainStem module. /// \retval aErrResource If the there is no valid connection. /// \retval aErrConnection If the disconnect failed, due to a /// communication issue. /// \retval aErrNone If the disconnect was successful. aErr disconnect(void); /// Reconnect using the current link specifier. /// \retval aErrBusy if the module is already in use. /// \retval aErrParam if the specifier is incorrect. /// \retval aErrNotFound if the module cannot be found. /// \retval aErrNone If the connect was successful. aErr reconnect(); /// Get the current link object. /// \return The link associated with the module. Link* getLink(void) const; /// Gets the links current network configuration /// \param config Variable to be filled with the config /// \return aErrNone on success. /// aErrNotReady if the module does not have a link /// aErrParam if config is NULL aErr getConfig(aEtherConfig* config); /// Sets the links network configuration. /// Configuration must be applied BEFORE connecting /// \param config Configuration to be applied /// \return aErrNone on success. /// aErrPermission if the module is currently connected. /// aErrNotReady if the module does not have a link aErr setConfig(const aEtherConfig config); /// Accessor to get the address of the BrainStem module associated with the instance /// on the host machine. (Not to be confused with the System entity which effects the /// device hardware.) /// \return The module address. uint8_t getModuleAddress(void) const; /// Accessor to set the address of the BrainStem module associated with the instance /// on the host machine. (Not to be confused with the System entity which effects the /// device hardware.) /// \param address The module address. void setModuleAddress(const uint8_t address); /// Get linkSpecifier /// \param spec - allocated linkspec struct will be filled with spec. /// \return aErrNone - If the module does not have a spec. aErr getLinkSpecifier(linkSpec* spec); /// Get the modules firmware build number /// The build number is a unique hash assigned to a specific firmware. /// \param build Variable to be filled with build. aErr getBuild(uint32_t* build); /// Queries the module to determine if it implements a UEI. Each /// UEI has a command, option or variant, index and flag. The hasUEI method /// queries for a fully specified UEI. /// Returns aErrNone if the variation is supported and an appropriate error /// if not. This call is blocking for up to the nMSTimeout period. /// \param command One of the UEI commands (cmdXXX). /// \param option The option or variant of the command. /// \param index The entity index. /// \param flags The flags (ueiOPTION_SET or ueiOPTION_GET). /// \retval aErrNone The module supports this command and access flags. /// \retval aErrMode The module supports the command but not the access /// flag. /// \retval aErrNotFound The module does not support the command, option, /// or index. /// \retval aErrTimeout The request timed out without a response. /// \retval aErrConnection There is no active link aErr hasUEI(const uint8_t command, const uint8_t option, const uint8_t index, const uint8_t flags); /// Queries the module to determine how many entities of the specified /// class are implemented by the module. Zero is a valid return value. /// For example, calling classQuantity with the command parameter of /// cmdANALOG would return the number of analog entities implemented by the module. /// \param command One of UEI commands (cmdXXX). /// \param count When the request is successful count /// is updated with the number of entities found. /// \retval aErrNone Success. /// \retval aErrTimeout The request timed out without a response. /// \retval aErrConnection There is no active link. aErr classQuantity(const uint8_t command, uint8_t* count); /// Queries the module to determine how many subclass entities of the specified /// class are implemented by the module for a given entity index. This is used /// for entities which may be 2-dimensional. E.g. cmdMUX subclasses are the number /// of channels supported by a particular mux type (index); as a specific example, /// a module may support 4 UART channels, so subClassQuantity(cmdMUX, aMUX_UART...) /// could return 4. /// Zero is a valid return value. /// \param command One of the UEI commands (cmdXXX). /// \param index The entity index. /// \param count The number of subclasses found. /// \retval aErrNone Success. /// \retval aErrTimeout The request timed out waiting for response. /// \retval aErrConnection There is no active link. aErr subClassQuantity(const uint8_t command, const uint8_t index, uint8_t* count); /// Queries the module the group assigned to an entity and index. Entities groups /// are used to specify when certain hardware features are fundamentally related. E.g. /// certain hardware modules may have some digital pins associated with an adjustable /// voltage rail; these digitals would be in the same group as the rail. /// Zero is the default group. /// \param command One of the UEI commands (cmdXXX). /// \param index The entity index. /// \param group Upon success, group is filled with the entities group value. /// \retval aErrNone Success. /// \retval aErrTimeout The request timed out without response. /// \retval aErrConnection There is no active link. aErr entityGroup(const uint8_t command, const uint8_t index, uint8_t* group); /// Sends a debug packet to the module containing the provided data. /// Modules receiving debug packets simply echo the packet back to the sender. /// If the round-trip is successful, the reply data will match the data sent. /// This method returns aErrNone when successful, if not successful, /// an appropriate error is returned. /// \param pData A pointer to an array of data to be sent in the debug packet. /// \param length The length of the data array. /// \retval aErrNone Success. /// \retval aErrTimeout Timeout occurred without response. /// \retval aErrConnection No active link exists. aErr debug(const uint8_t* pData, const uint8_t length); /// Sets the networking mode of the module object. /// By default the module object is configure to automatically adjust /// its address based on the devices current module address. So that, /// if the device has a software or hardware offset it will still be /// able to communication with the device. If advanced networking is required /// the auto networking mode can be turned off. /// \param mode True/1 for Auto Networking, False/0 for manual networking void setNetworkingMode(const bool mode); aErr enablePacketLog(const char* packetLogName = "StemDebug"); aErr disablePacketLog(void); private: Module(); Link* m_pLink; uint8_t m_address; bool m_bAutoNetworking; uint8_t m_model; aErr _autoNetwork(void); }; /// \defgroup EntityReturnValues Common EntityClass Return Values /// Common EntityClass Return Values /// @{ /// - ::aErrNone - Action completed successfully. /// - ::aErrTimeout - Request timed out without response. /// - ::aErrConnection - No active link. /// @} /// EntityClass: /// The EntityClass is the base class for interacting with BrainStem UEI entities. /// All BrainStem UEI classes inherit from EntityClass. Advanced users may use /// EntityClass to extend BrainStem functionality specific to their needs. class aLIBEXPORT EntityClass { public: /// Constructor. EntityClass(void); /// Destructor. virtual ~EntityClass(void); /// init. /// /// Initialize the entity class. /// \param pModule The BrainStem module object. /// \param command The command of the UEI. /// \param index The index of the UEI entity. void init(Module* pModule, const uint8_t command, const uint8_t index); /// A callUEI is a setUEI that has no data length. /// \param option An option for the UEI. /// \return Returns \ref EntityReturnValues "common entity" return values aErr callUEI(const uint8_t option); /// Set a byte value. /// \param option The option for the UEI. /// \param byteValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr setUEI8(const uint8_t option, const uint8_t byteValue); /// Set a byte value with a subindex. /// \param option The option for the UEI. /// \param param of the option. /// \param byteValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr setUEI8(const uint8_t option, const uint8_t param, const uint8_t byteValue); /// Get a byte value. /// \param option The option for the UEI. /// \param byteValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEI8(const uint8_t option, uint8_t* byteValue); /// Get a byte value with a parameter. /// \param option The option for the UEI. /// \param param The parameter. /// \param byteValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEI8(const uint8_t option, const uint8_t param, uint8_t* byteValue); /// Set a 2-byte value. /// \param option The option for the UEI. /// \param shortValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr setUEI16(const uint8_t option, const uint16_t shortValue); /// Set a 2-byte value with a parameter. /// \param option The option for the UEI. /// \param param The parameter. /// \param shortValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr setUEI16(const uint8_t option, const uint8_t param, const uint16_t shortValue); /// Get a 2-byte value. /// \param option The option for the UEI. /// \param shortValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEI16(const uint8_t option, uint16_t* shortValue); /// Get a 2-byte value with a parameter. /// \param option The option for the UEI. /// \param param The parameter. /// \param shortValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEI16(const uint8_t option, const uint8_t param, uint16_t* shortValue); /// Set a 4-byte value. /// \param option The option for the UEI. /// \param intValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr setUEI32(const uint8_t option, const uint32_t intValue); /// Set a 4-byte value, with a subindex parameter. /// \param option The option for the UEI. /// \param subIndex The subindex to set. /// \param intValue The value. /// \return Returns \ref EntityReturnValues "common entity" return values aErr setUEI32(const uint8_t option, const uint8_t subIndex, const uint32_t intValue); /// Get a 4-byte value. /// \param option The option for the UEI. /// \param intValue The 4 byte value /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEI32(const uint8_t option, uint32_t* intValue); /// Get a 4-byte value with parameter. /// \param option The option for the UEI. /// \param param The parameter. /// \param intValue The 4 byte value /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEI32(const uint8_t option, const uint8_t param, uint32_t* intValue); /// Set a multi-byte value. /// \param option The option for the UEI. /// \param bufPtr The pointer to a data buffer /// \param bufLen The length of the data buffer /// \return Returns \ref EntityReturnValues "common entity" return values aErr setUEIBytes(const uint8_t option, const uint8_t* bufPtr, const size_t bufLen); /// Unloads UEI Bytes data as byte data /// \param option The option for the UEI. /// \param buf Start of where data should be stored.. /// \param bufLength Size of the buffer /// \param unloadedLength Amount of data unloaded (in bytes) /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEIBytes(const uint8_t option, uint8_t* buf, const size_t bufLength, size_t* unloadedLength); //Helper function for evaluating the sequence byte of a UEI Bytes call. /// \param packet UEI packet to be checked/filtered. /// \return The sequence number of the byte. static uint8_t getUEIBytesSequence(const aPacket* packet); //Helper function for evaluating the continue bit of a UEI Bytes call. /// \param packet UEI packet to be checked/filtered. /// \return True - Continue bit is set (more packets to come); False - Continue bit is not set (first or last packet). static bool getUEIBytesContinue(const aPacket* packet); //Helper function for UEIBytes get checks, specifically checking and fixing unload size /// \param unloadedLength Amount of data unloaded (in bytes) /// \param valueSize The base type size in this array /// \return Returns \ref EntityReturnValues "common entity" return values aErr getUEIBytesCheck(size_t* unloadedLength, const size_t valueSize); /// Get the UEI entity index. /// \return The 1 byte index of the UEI entity. uint8_t getIndex(void) const; /// Drain all packets matching this UEI from the packet fifo. /// /// This functionality is useful in rare cases where packet /// synchronization is lost and a valid return packet is not /// accessible. aErr drainUEI(const uint8_t option); /// Filter function for UEI Bytes calls. Exposed for unit-testing purposes only. /// \param packet UEI packet to be checked/filtered. /// \param ref Opaque reference handle static uint8_t sUEIBytesFilter(const aPacket* packet, const void* ref); /// Enables streaming for all possible option codes within the cmd and index the entity was created for. /// \param enabled The state to be applied. 0 = Disabled; 1 = enabled /// \return Returns \ref EntityReturnValues "common entity" return values aErr setStreamEnabled(uint8_t enabled); /// Registers a callback function based on a specific option code. /// Option code applies to the cmd and index of the called API. /// \param option option to filter by (supports Wildcards) /// \param enable True - installs/updates callback and ref; False - uninstalls callback /// \param cb Callback to be executed when a new packet matching the criteria is received. /// \param pRef Pointer to user reference for use inside the callback function. /// \return aErrNotFound - Item not found (uninstalling only) /// \return aErrNone - success aErr registerOptionCallback(const uint8_t option, const bool enable, Link::streamCallback_t cb, void* pRef); /// Gets all available stream values associated with the cmd and index of the called API. /// Keys can be decoded with Link::getStreamKeyElement. /// \param buffer Buffer of user allocated memory to be filled with stream data /// \param bufferLength Number of elements the buffer can hold. /// \param unloadedSize Number of elements that were placed in the buffer /// \return aErrParam if status or unloadedSize is null /// \return aErrResource - if the link is not valid /// \return aErrNone - success aErr getStreamStatus(Link::StreamStatusEntry_t* buffer, const size_t bufferLength, size_t* unloadedSize); /// Resets the Entity to factory defaults /// \return Returns \ref EntityReturnValues "common entity" return values aErr resetEntityToFactoryDefaults(void); /// Load the Entity from the internal store /// \return Returns \ref EntityReturnValues "common entity" return values aErr loadEntityFromStore(void); /// Saves the Entity to the internal store /// \return Returns \ref EntityReturnValues "common entity" return values aErr saveEntityToStore(void); protected: aErr sendPacket(const uint8_t command, const uint8_t length, const uint8_t* data); aErr receivePacket(const uint8_t* match, uint8_t* length, uint8_t* data); aErr getUEI(const uint8_t option, uei* d); aErr setUEI(const uint8_t option, uei* d); aErr setUEI(const uint8_t option, const uint8_t subIndex, uei* d); aErr awaitUEI32Val(const uint32_t option, uint32_t* intValue, const uint32_t msTimeout); class impl; impl* zit; }; } // namespace BrainStem } // namespace Acroname #endif//defined(__cplusplus) #endif // __BrainStem_core_H__