UmberHubManager/api/lib/BrainStem2/BrainStem-core.h

1240 lines
65 KiB
C++

/////////////////////////////////////////////////////////////////////
// //
// 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 <stdint.h>
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#endif//defined(__cplusplus)
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#ifndef in_addr_t
#define in_addr_t uint32_t
#endif
#else // Linux
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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<linkSpec>*) 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<linkSpec>* pSpecs = (std::list<linkSpec>*)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<linkSpec>* 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<uint64_t> 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__