Library for using the LSR SiFlex/ProFlex RF modules with mbed.
LsrModule.cpp
- Committer:
- Issus
- Date:
- 2016-07-25
- Revision:
- 2:2c0b7246d769
- Parent:
- 0:f9cf4a19bb84
- Child:
- 3:8d794c196710
File content as of revision 2:2c0b7246d769:
/** * @file LsrModule.cpp * @author LS Research LLC * @version 1.0 * * @section LICENSE * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details at * http://www.gnu.org/copyleft/gpl.html * * @section DESCRIPTION * * Implementation of contents in LsrModule.h. */ /** * Modified by Mark Harris at SAIT.ca * Improved functionality for mbed */ #include "LsrModule.h" #include "mbed.h" /** * C function pointer typedef. * */ typedef void (*ptrRxMsgCallback)(void); /** * Table used for subscribing callback functions for * received UART messages. */ ptrRxMsgCallback ptrRxMsgCallbackTable[69]; /** * This table contains the min and max length for each message type. The first array index * is the message type and the second index is the min value (0) or max value (1). */ const uint8_t cau8RxMsgLengthAndTypeTable[69][2] = { {12, 39}, // 0x81 - Query Firmware Version Response {0, 0}, // 0x82 - Invalid message type {0, 0}, // 0x83 - Invalid message type {0, 0}, // 0x84 - Invalid message type {0, 0}, // 0x85 - Invalid message type {0, 0}, // 0x86 - Invalid message type {0, 0}, // 0x87 - Invalid message type {0, 0}, // 0x88 - Invalid message type {0, 0}, // 0x89 - Invalid message type {0, 0}, // 0x8A - Invalid message type {0, 0}, // 0x8B - Invalid message type {5, 5}, // 0x8C - Set Security Transmit Frame Counter Ack {11, 11}, // 0x8D - Query Security Transmit Frame Counter Response {0, 0}, // 0x8E - Invalid message type {0, 0}, // 0x8F - Invalid message type {5, 5}, // 0x90 - Set Basic RF Settings Ack {39, 39}, // 0x91 - Query Basic RF Settings Response {5, 5}, // 0x92 - Save Settings to NV Memory Ack {5, 5}, // 0x93 - Reset Request Ack {9, 9}, // 0x94 - Query Supply Voltage Response {21, 21}, // 0x95 - Query Statistics Response {5, 5}, // 0x96 - Clear Statistics Ack {0, 0}, // 0x97 - Invalid message type {5, 5}, // 0x98 - Set Host Data Rate Ack {0, 0}, // 0x99 - Invalid message type {0, 0}, // 0x9A - Invalid message type {0, 0}, // 0x9B - Invalid message type {0, 0}, // 0x9C - Invalid message type {0, 0}, // 0x9D - Invalid message type {0, 0}, // 0x9E - Invalid message type {0, 0}, // 0x9F - Invalid message type {7, 7}, // 0xA0 - Send Simple Short Address RF Data Packet Ack {17, 115}, // 0xA1 - Received Simple Short Address RF Data Packet {7, 7}, // 0xA2 - Send Advanced Short Address RF Data Packet Ack {21, 119}, // 0xA3 - Received Advanced Short Address RF Data Packet {7, 7}, // 0xA4 - Send Simple Long Address RF Data Packet Ack {29, 127}, // 0xA5 - Received Simple Long Address RF Data Packet {7, 7}, // 0xA6 - Send Advanced Long Address RF Data Packet Ack {33, 131}, // 0xA7 - Received Advanced Long Address RF Data Packet {0, 0}, // 0xA8 - Invalid message type {0, 0}, // 0xA9 - Invalid message type {0, 0}, // 0xAA - Invalid message type {0, 0}, // 0xAB - Invalid message type {0, 0}, // 0xAC - Invalid message type {0, 0}, // 0xAD - Invalid message type {13, 131}, // 0xAE - Received Promiscuous Mode Packet {0, 0}, // 0xAF - Invalid message type {0, 0}, // 0xB0 - Invalid message type {0, 0}, // 0xB1 - Invalid message type {0, 0}, // 0xB2 - Invalid message type {0, 0}, // 0xB3 - Invalid message type {0, 0}, // 0xB4 - Invalid message type {0, 0}, // 0xB5 - Invalid message type {0, 0}, // 0xB6 - Invalid message type {0, 0}, // 0xB7 - Invalid message type {0, 0}, // 0xB8 - Invalid message type {0, 0}, // 0xB9 - Invalid message type {0, 0}, // 0xBA - Invalid message type {0, 0}, // 0xBB - Invalid message type {0, 0}, // 0xBC - Invalid message type {0, 0}, // 0xBD - Invalid message type {0, 0}, // 0xBE - Invalid message type {0, 0}, // 0xBF - Invalid message type {0, 0}, // 0xC0 - Invalid message type {0, 0}, // 0xC1 - Invalid message type {0, 0}, // 0xC2 - Invalid message type {0 ,0}, // 0xC3 - Invalid message type {5, 5}, // 0xC4 - Channel Energy Scan Ack {23, 23} // 0xC5 - Channel Energy Scan Results }; /** * Construnctor. * * Example: * * LsrModule(false, 19200); * */ LsrModule::LsrModule(PinName tx, PinName rx, int baudRate) : Serial(tx, rx) { baud(baudRate); ptrHostState = &LsrModule::HostRxWaitForMsgStartByteState; } /*** End LsrModule ***/ /** * Destructor. Called automatically, de-allocates resources. * */ LsrModule::~LsrModule(void) { pu8RxBuffer = NULL; ptrHostState = NULL; ptrHostProcessCallbackState = NULL; for (u8ForLoopCounter = 0; u8ForLoopCounter < sizeof(ptrRxMsgCallbackTable); u8ForLoopCounter++) { ptrRxMsgCallbackTable[u8ForLoopCounter] = NULL; } } /*** End ~LsrModule ***/ /** * Creates a callback for specific received UART message. Call this function from your main application in * this manner: "SubscribeRxMsgCallback(0xA1, &simpleShortAddrCallback)", where simpleShortAddrCallback is * defined like this: void simpleShortAddrCallback(void) in your main application. * IMPORTANT: All user defined callback methods must return void and take no parameters (void). * * @return True: Subscribed callback. False: Did not subscribe callback. * */ bool LsrModule::SubscribeRxMsgCallback(uint8_t u8RxMsgType ///< The received message for which you want the callback to execute. , void (*callback)(void) ///< C function pointer to the specified callback function. ) { if ((u8RxMsgType > LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE) && (u8RxMsgType < LSR_MODULE_MAX_SERIAL_RX_MSG_TYPE)) { ptrRxMsgCallbackTable[u8RxMsgType- LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE] = callback; return true; } return false; } /*** End SubscribeRxMsgCallback ***/ /** * Removes a callback for specific received UART message. See SubscribeRxMsgCallback's description for * more information. * * @return True: Unsubscribed callback. False: Did not unsubscribed callback. * */ bool LsrModule::UnsubscribeRxMsgCallback(uint8_t u8RxMsgType ///< The received message for which you want the callback to be removed. ) { if ((u8RxMsgType > LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE) && (u8RxMsgType < LSR_MODULE_MAX_SERIAL_RX_MSG_TYPE)) { ptrRxMsgCallbackTable[u8RxMsgType - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE] = NULL; return true; } return false; } /*** End UnsubscribeRxMsgCallback ***/ /** * Executes host RX state machine. This function must be executed continually from the loop function in your main * application. * */ void LsrModule::RunHostRxStateMachine(void) { (this->*ptrHostState)(); } /*** End RunHostRxStateMachine ***/ /** * Flushes appropriate serial port. * */ void LsrModule::SerialFlush(void) { // Serial.flush(); // i think this is meant to clean out the rx buffer /*** End SerialFlush ***/ } /** * Adds header to the UART transmit buffer. * */ void LsrModule::AddSerialMsgHeader(uint8_t u8MsgType, uint8_t u8MsgLength) { SerialFlush(); u8UartTxBufferIndex = LSR_MODULE_MSG_START_BYTE_INDEX; au8UartTxBuffer[u8UartTxBufferIndex++] = LSR_MODULE_SERIAL_MSG_START_BYTE; au8UartTxBuffer[u8UartTxBufferIndex++] = u8MsgLength; au8UartTxBuffer[u8UartTxBufferIndex++] = u8MsgType; u8TxMsgChecksum = (LSR_MODULE_SERIAL_MSG_START_BYTE + u8MsgLength + u8MsgType); } /*** End LsrModuleAddSerialMsgHeader ***/ /** * Adds data bytes to the UART transmit buffer. * */ void LsrModule::AddSerialByteToMsgBuffer(uint8_t u8Data ///< The data to add. ) { au8UartTxBuffer[u8UartTxBufferIndex++] = u8Data; u8TxMsgChecksum += u8Data; } /*** End LsrModuleAddSerialByteToMsgBuffer ***/ /** * Adds message trailer to the UART transmit buffer. * */ void LsrModule::AddSerialMsgTrailer(void) { au8UartTxBuffer[u8UartTxBufferIndex++] = u8TxMsgChecksum; au8UartTxBuffer[u8UartTxBufferIndex] = LSR_MODULE_SERIAL_MSG_END_BYTE; WriteSerialMsg(); } /*** End AddSerialMsgTrailer ***/ /** * Writes the UART transmit buffer using the appropriate serial port. * */ void LsrModule::WriteSerialMsg(void) { //write (const uint8_t *buffer, int length, const event_callback_t &callback, int event=SERIAL_EVENT_TX_COMPLETE) write(au8UartTxBuffer, au8UartTxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX]); } /*** End WriteSerialMsg ***/ /** * Sends message type 0x01 (Query Version) to the module via UART communication. This will spark * a response message from the module to the Arduino of type 0x81. Subscribing to 0x81 in * your main application will allow you to parse the response data. See the description for * SubscribeRxMsgCallback for more information. * */ void LsrModule::QueryVersionMsg(void) { AddSerialMsgHeader(LSR_MODULE_QUERY_VERSION_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End QueryVersionMsg ***/ /** * Sends message type 0x0C (Sets Security Transmit Frame Counter) to the module via UART communication. * This frame counter is used with RF messages transmitted with security to ensure sequential freshness. * This sets the starting frame count and is automatically incremented on every secured packet sent. * This will spark an ACK message from the module to the Arduino of type 0x8C. Subscribing to 0x8C in * your main application will allow you to parse the response data. See the description for * SubscribeRxMsgCallback for more information. * * Example: * * uint32_t u32FrameCounter = 0xAEDFEDFA; * SetSecurityTransmitFrameCounterMsg(&u32FrameCounter); * */ void LsrModule::SetSecurityTransmitFrameCounterMsg(uint32_t* pu32FrameCounter ///< Pointer to 4 byte frame counter (LSB to MSB). ) { DWordu_t dwuFrameCounter; dwuFrameCounter.u32 = *pu32FrameCounter; AddSerialMsgHeader(LSR_MODULE_SET_SECURITY_TX_FRAME_COUNTER_MSG_TYPE, 11); AddSerialByteToMsgBuffer(dwuFrameCounter.dws.lb); AddSerialByteToMsgBuffer(dwuFrameCounter.dws.mlb); AddSerialByteToMsgBuffer(dwuFrameCounter.dws.mhb); AddSerialByteToMsgBuffer(dwuFrameCounter.dws.hb); AddSerialByteToMsgBuffer(0x00); // Add filler byte. AddSerialByteToMsgBuffer(0x00); // Add filler byte. AddSerialMsgTrailer(); } /*** End SetSecurityTransmitFrameCounterMsg ***/ /** * Sends message type 0x0D (Query Security Transmit Frame Counter) to the module via UART communication. This * will spark a response message from the module to the Arduino of type 0x8D. Subscribing to 0x8D in your main * application will allow you to parse the response data. See the description for SubscribeRxMsgCallback * for more information. * */ void LsrModule::QuerySecurityTransmitFrameCounterMsg(void) { AddSerialMsgHeader(LSR_MODULE_QUERY_SECURITY_TX_FRAME_COUNTER_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End QuerySecurityTransmitFrameCounterMsg ***/ /** * Sends message type 0x10 (Set Basic RF Settings) to the module via UART communication. * This will spark an ACK message from the module to the Arduino of type 0x90. Subscribing to 0x90 in * your main application will allow you to parse the response data. See the description for * SubscribeRxMsgCallback for more information. * */ void LsrModule::SetBasicRfSettingsMsg(uint16_t u16PanId ///< Personal Area Network (PAN) ID assigned to module. , uint16_t u16AddrShort ///< 2 byte short address assigned to module. , uint8_t* pu8AddrLong ///< Pointer to 8 byte long address assigned to module. Do not assign a zero, even if using short addressing. , uint8_t u8RfChannel ///< RF channel assigned to module. , uint8_t u8TxPowerLevel ///< Transmit power assigned to module. , uint8_t u8ReceiverConfig ///< 1 byte bitmask of receiver options. , uint8_t* pu8SecurityKey ///< Pointer to 32 byte security key assigned to module. ) { Wordu_t wuPanId; Wordu_t wuShortAddr; wuPanId.u16 = u16PanId; wuShortAddr.u16 = u16AddrShort; if ((u8RfChannel >= LSR_MODULE_RF_CHANNEL_MIN) && (u8RfChannel <= LSR_MODULE_RF_CHANNEL_MAX) && (u8TxPowerLevel <= LSR_MODULE_TX_POWER_LEVEL_MAX) && (u8ReceiverConfig <= LSR_MODULE_RX_CONFIG_MAX)) { AddSerialMsgHeader(LSR_MODULE_SET_BASIC_RF_SETTINGS_MSG_TYPE, 39); AddSerialByteToMsgBuffer(wuPanId.ws.lb); AddSerialByteToMsgBuffer(wuPanId.ws.hb); AddSerialByteToMsgBuffer(wuShortAddr.ws.lb); AddSerialByteToMsgBuffer(wuShortAddr.ws.hb); for (u8ForLoopCounter = 0; u8ForLoopCounter < 8; u8ForLoopCounter++) { AddSerialByteToMsgBuffer(*pu8AddrLong); pu8AddrLong++; } AddSerialByteToMsgBuffer(u8RfChannel); AddSerialByteToMsgBuffer(u8TxPowerLevel); AddSerialByteToMsgBuffer(u8ReceiverConfig); AddSerialByteToMsgBuffer(0x00); // Add filler byte. AddSerialByteToMsgBuffer(0x00); // Add filler byte. AddSerialByteToMsgBuffer(0x00); // Add filler byte. for (u8ForLoopCounter = 0; u8ForLoopCounter < 16; u8ForLoopCounter++) { AddSerialByteToMsgBuffer(*pu8SecurityKey); pu8SecurityKey++; } AddSerialMsgTrailer(); } } /*** End SetBasicRfSettingsMsg ***/ /** * Sends message type 0x11 (Query Basic RF Settings) to the module via UART communication. This will spark * a response message from the module to the Arduino of type 0x91. Subscribing to 0x91 in your main * application will allow you to parse the response data. See the description for SubscribeRxMsgCallback * for more information. * */ void LsrModule::QueryBasicRfSettingsMsg(void) { AddSerialMsgHeader(LSR_MODULE_QUERY_BASIC_RF_SETTINGS_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End QueryBasicRfSettingsMsg ***/ /** * Sends message type 0x12 (Save Settings to non-volatile Memory) to the module via UART communication. Calling * this command will make your module retain all basic configuration settings on boot up. This will spark an ACK * message from the module to the Arduino of type 0x92. Subscribing to 0x92 in your main application will allow * you to parse the response data. See the description for SubscribeRxMsgCallback for more information. * */ void LsrModule::SaveSettingsToNVMemoryMsg(void) { AddSerialMsgHeader(LSR_MODULE_SAVE_SETTINGS_TO_NV_MEMORY_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End SaveSettingsToNVMemoryMsg ***/ /** * Sends message type 0x13 (Reset Request) to the module via UART communication. This will make your module perform * a restart. This will spark an ACK message from the module to the Arduino of type 0x93. Subscribing to 0x93 in * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback * for more information. * */ void LsrModule::ResetRequestMsg(void) { AddSerialMsgHeader(LSR_MODULE_RESET_REQUEST_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End ResetRequestMsg ***/ /** * Sends message type 0x14 (Query Supply Voltage) to the module via UART communication. This will spark a * response message from the module to the Arduino of type 0x94. Subscribing to 0x94 in your main application * will allow you to parse the response data. See the description for SubscribeRxMsgCallback for more information. * */ void LsrModule::QuerySupplyVoltageMsg(void) { AddSerialMsgHeader(LSR_MODULE_QUERY_SUPPLY_VOLTAGE_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End QuerySupplyVoltageMsg ***/ /** * Sends message type 0x15 (Query Statistics) to the module via UART communication. Statistics include packets sent, * acks received, packets received and broadcast packets received. This will spark a response message from the module * to the Arduino of type 0x95. Subscribing to 0x94 in your main application will allow you to parse the response * data. See the description for SubscribeRxMsgCallback for more information. * */ void LsrModule::QueryStatisticsMsg(void) { AddSerialMsgHeader(LSR_MODULE_QUERY_STATISTICS_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End QueryStatisticsMsg ***/ /** * Sends message type 0x16 (Clear Statistics) to the module via UART communication. This will spark an ACK message * from the module to the Arduino of type 0x96. Subscribing to 0x96 in your main application will allow you to * Parse the response data. See the description for SubscribeRxMsgCallback for more information. * */ void LsrModule::ClearStatisticsMsg(void) { AddSerialMsgHeader(LSR_MODULE_CLEAR_STATISTICS_MSG_TYPE, 5); AddSerialMsgTrailer(); } /*** End ClearStatisticsMsg ***/ /** * Sends message type 0x18 (Set Host Data Rate) to the module via UART communication. This will spark an ACK message * from the module to the Arduino of type 0x98. Subscribing to 0x98 in your main application will allow you to parse * the response data. See the description for SubscribeRxMsgCallback for more information. * */ void LsrModule::SetHostDataRateMsg(uint8_t u8HostDataRate ///< Data rate for module to use when communicating via UART: ///< 0 = 1,200 bits/s ///< 1 = 2,400 bits/s ///< 2 = 4,800 bits/s ///< 3 = 9,600 bits/s ///< 4 = 19,200 bits/s ///< 5 = 38,400 bits/s ///< 6 = 57,600 bits/s ///< 7 = 115,200 bits/s ) { if (u8HostDataRate <= LSR_MODULE_HOST_DATA_RATE_MAX) { AddSerialMsgHeader(LSR_MODULE_SET_HOST_DATA_RATE_MSG_TYPE, 6); AddSerialByteToMsgBuffer(u8HostDataRate); AddSerialMsgTrailer(); switch (u8HostDataRate) { case LSR_MODULE_HOST_DATA_RATE_1200: baud(1200); break; case LSR_MODULE_HOST_DATA_RATE_2400: baud(2400); break; case LSR_MODULE_HOST_DATA_RATE_4800: baud(4800); break; case LSR_MODULE_HOST_DATA_RATE_9600: baud(9600); break; case LSR_MODULE_HOST_DATA_RATE_19200: baud(19200); break; case LSR_MODULE_HOST_DATA_RATE_38400: baud(38400); break; case LSR_MODULE_HOST_DATA_RATE_57600: baud(57600); break; case LSR_MODULE_HOST_DATA_RATE_115200: baud(115200); break; case LSR_MODULE_HOST_DATA_RATE_230400: baud(230400); break; case LSR_MODULE_HOST_DATA_RATE_460800: baud(460800); break; case LSR_MODULE_HOST_DATA_RATE_921600: baud(921600); break; } } } /*** End SetHostDataRateMsg ***/ /** * Sends message type 0x20 (Send Simple Short Address RF Data Packet) to the module via UART communication. * This will spark an ACK message from the module to the Arduino of type 0xA0. Subscribing to 0xA0 in * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback * for more information. * * Example: * * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; * uint8_t u8PacketID; * * SendSimpleShortAddrRfDataPacketMsg(&u8Data, sizeof(u8Data, 213, 0, packetID++); * */ void LsrModule::SendSimpleShortAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. , uint8_t u8DataLength ///< Length of data being sent. , uint16_t u16DestAddress ///< 2 byte destination address. , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. , uint8_t u8PacketId ///< ID assigned to packet. ) { if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_SIMPLE_SHORT_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_SIMPLE_SHORT_RF_DATA_LENGTH)))) { AddSerialMsgHeader(LSR_MODULE_SEND_SIMPLE_SHORT_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 9)); AddSerialByteToMsgBuffer(u8TxOptions); AddSerialByteToMsgBuffer(u16DestAddress % 256); AddSerialByteToMsgBuffer(u16DestAddress >> 8); AddSerialByteToMsgBuffer(u8PacketId); while (u8DataLength != 0) { AddSerialByteToMsgBuffer(*pu8Data); pu8Data++; u8DataLength--; } AddSerialMsgTrailer(); } } /*** End SendSimpleShortAddrRfDataPacketMsg ***/ /** * Sends message type 0x22 (Send Advanced Short Address RF Data Packet) to the module via UART communication. * This will spark an ACK message from the module to the Arduino of type 0xA2. Subscribing to 0xA2 in * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback * for more information. * * Example: * * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; * uint8_t u8PacketID; * * SendAdvancedShortAddrRfDataPacketMsg(&u8Data, sizeof(u8Data, 1111, 213, 0, packetID++); * */ void LsrModule::SendAdvancedShortAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. , uint8_t u8DataLength ///< Length of data being sent. , uint16_t u16DestPanId ///< 2 byte Personal Area Network (PAN) ID. , uint16_t u16DestAddress ///< 2 byte destination address. , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. , uint8_t u8PacketId ///< ID assigned to packet. ) { if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_ADVANCED_SHORT_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_ADVANCED_SHORT_RF_DATA_LENGTH)))) { AddSerialMsgHeader(LSR_MODULE_SEND_ADVANCED_SHORT_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 11)); AddSerialByteToMsgBuffer(u8TxOptions); AddSerialByteToMsgBuffer(u16DestPanId % 256); AddSerialByteToMsgBuffer(u16DestPanId >> 8); AddSerialByteToMsgBuffer(u16DestAddress % 256); AddSerialByteToMsgBuffer(u16DestAddress >> 8); AddSerialByteToMsgBuffer(u8PacketId); while (u8DataLength != 0) { AddSerialByteToMsgBuffer(*pu8Data); pu8Data++; u8DataLength--; } AddSerialMsgTrailer(); } } /*** End SendAdvancedShortAddrRfDataPacketMsg ***/ /** * Sends message type 0x24 (Send Simple Long Address RF Data Packet) to the module via UART communication. * This will spark an ACK message from the module to the Arduino of type 0xA4. Subscribing to 0xA4 in * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback * for more information. * * Example: * * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; * uint8_t u8DestAddress[8] = {2, 3, 6, 5, 2, 3, 6, 5}; * uint8_t u8PacketID; * * SendSimpleLongAddrRfDataPacketMsg(&u8Data, sizeof(u8Data), &u8DestAddress, 0, packetID++); * */ void LsrModule::SendSimpleLongAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. , uint8_t u8DataLength ///< Length of data being sent. , uint8_t* pu8DestAddress ///< Pointer to 8 byte destination address. , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. , uint8_t u8PacketId ///< ID assigned to packet. ) { if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_SIMPLE_LONG_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_SIMPLE_LONG_RF_DATA_LENGTH)))) { AddSerialMsgHeader(LSR_MODULE_SEND_SIMPLE_LONG_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 15)); AddSerialByteToMsgBuffer(u8TxOptions); for (u8ForLoopCounter = 0; u8ForLoopCounter < 8; u8ForLoopCounter++) { AddSerialByteToMsgBuffer(*pu8DestAddress); pu8DestAddress++; } AddSerialByteToMsgBuffer(u8PacketId); while (u8DataLength != 0) { AddSerialByteToMsgBuffer(*pu8Data); pu8Data++; u8DataLength--; } AddSerialMsgTrailer(); } } /*** End SendSimpleLongAddrRfDataPacketMsg ***/ /** * Sends message type 0x26 (Send Advanced Long Address RF Data Packet) to the module via UART communication. * This will spark an ACK message from the module to the Arduino of type 0xA6. Subscribing to 0xA6 in * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback * for more information. * * Example: * * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; * uint8_t u8DestAddress[8] = {2, 3, 6, 5, 2, 3, 6, 5}; * uint8_t u8PacketID; * * SendAdvancedLongAddrRfDataPacketMsg(&u8Data, sizeof(u8Data), 1111, &u8DestAddress, 0, packetID++); * */ void LsrModule::SendAdvancedLongAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. , uint8_t u8DataLength ///< Length of data being sent. , uint16_t u16DestPanId ///< 2 byte Personal Area Network (PAN) ID. , uint8_t* pu8DestAddress ///< Pointer to 8 byte destination address. , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. , uint8_t u8PacketId ///< ID assigned to packet. ) { if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_ADVANCED_LONG_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_ADVANCED_LONG_RF_DATA_LENGTH)))) { AddSerialMsgHeader(LSR_MODULE_SEND_ADVANCED_LONG_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 17)); AddSerialByteToMsgBuffer(u8TxOptions); AddSerialByteToMsgBuffer(u16DestPanId % 256); AddSerialByteToMsgBuffer(u16DestPanId >> 8); for (u8ForLoopCounter = 0; u8ForLoopCounter < 8; u8ForLoopCounter++) { AddSerialByteToMsgBuffer(*pu8DestAddress); pu8DestAddress++; } AddSerialByteToMsgBuffer(u8PacketId); while (u8DataLength != 0) { AddSerialByteToMsgBuffer(*pu8Data); pu8Data++; u8DataLength--; } AddSerialMsgTrailer(); } } /*** End SendAdvancedLongAddrRfDataPacketMsg ***/ /** * Sends message type 0x44 (Channel Energy Scan) to the module via UART communication. This will spark a response message from the module * to the Arduino of type 0xC5. Subscribing to 0xC5 in your main application will allow you to parse the response * data. See the description for SubscribeRxMsgCallback for more information. * * Example (Channel 5 for SiFLEX02, Channel 15 for ProFLEX01): * * ChannelEnergyScanMsg(11110111, 7); * */ void LsrModule::ChannelEnergyScanMsg(uint16_t u16ChannelMask ///< Two byte bitmask (LSB to MSB) of the RF channels to perfom an enrgy scan on. , uint8_t u8ScanDuration ///< Duration to scan for: ///< 0 = 61.4 mSec ///< 1 = 92.2 mSec ///< 2 = 154 mSec ///< 3 = 276 mSec ///< 4 = 522 mSec ///< 5 = 1.01 Sec ///< 6 = 2.00 Sec ///< 7 = 3.96 Sec ///< 8 = 7.90 Sec ///< 9 = 15.8 Sec ///< 10 = 31.5 Sec ///< 11 = 62.9 Sec ///< 12 = 126 Sec ///< 13 = 252 Sec ///< 14 = 503 Sec ) { Wordu_t wuChannelMask; wuChannelMask.u16 = u16ChannelMask; if (u8ScanDuration <= LSR_MODULE_SCAN_DURATION_MAX) { AddSerialMsgHeader(LSR_MODULE_CHANNEL_ENERGY_SCAN_MSG_TYPE, 8); AddSerialByteToMsgBuffer(wuChannelMask.ws.lb); AddSerialByteToMsgBuffer(wuChannelMask.ws.hb); AddSerialByteToMsgBuffer(u8ScanDuration); AddSerialMsgTrailer(); } } /*** End ChannelEnergyScanMsg ***/ /** * Verifies msg type and length. * @return True: Valid msg length and type. False: Invalid msg length or type. * */ bool LsrModule::ValidMsgLengthAndType(uint8_t u8MsgType ///< Received UART message type. , uint8_t u8MsgLength ///< Received UART message length. ) { if ((u8MsgLength >= cau8RxMsgLengthAndTypeTable[u8MsgType - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE][0]) && (u8MsgLength <= cau8RxMsgLengthAndTypeTable[u8MsgType - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE][1])) { return true; } return false; } /*** End ValidMsgLengthAndType ***/ /** * Verifies message checksum. * @return True: Valid checksum. False: Invalid checksum. * */ bool LsrModule::ValidRxChecksum(uint8_t* pu8MsgBuffer ///< Pointer to received UART buffer. , uint8_t u8MsgLength ///< Received UART message length. ) { uint8_t u8Checksum = 0; for (u8ForLoopCounter = 0; u8ForLoopCounter < (u8MsgLength - 2); u8ForLoopCounter++) { u8Checksum += au8UartRxBuffer[u8ForLoopCounter]; } if (au8UartRxBuffer[u8MsgLength-2] == u8Checksum) { return true; } return false; } /*** End ValidRxChecksum ***/ /** * Calls appropriate callback function for received message. * */ void LsrModule::HostProcessCallbackMsgStart(uint8_t* pu8MsgBuffer ///< Pointer to received message. , uint8_t u8Length ///< Length of received message. ) { if ((ptrRxMsgCallbackTable[(*(pu8MsgBuffer + LSR_MODULE_MSG_TYPE_BYTE_INDEX)) - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE]) != NULL) { ptrRxMsgCallbackTable[(*(pu8MsgBuffer + LSR_MODULE_MSG_TYPE_BYTE_INDEX)) - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE](); } } /*** End HostProcessCallbackMsgStart ***/ /** * Determines if appropriate serial port is available. * @return True: Serial is available. False: Serial is unavailable. * */ bool LsrModule::SerialAvailable(void) { if (readable()) { return true; } return false; } /*** End SerialAvailable ***/ /** * Reads appropriate serial port. * @return Byte read. * */ uint8_t LsrModule::SerialRead(void) { return getc(); } /*** End SerialRead ***/ /** * Refreshes and restarts Rx state machine. * */ void LsrModule::SerialRxCleanupRestart(void) { SerialFlush(); u8UartRxBufferIndex = LSR_MODULE_MSG_START_BYTE_INDEX; ptrHostState = &LsrModule::HostRxWaitForMsgStartByteState; } /*** End SerialRxCleanupRestart ***/ /** * Waits for data packet start byte. * */ void LsrModule::HostRxWaitForMsgStartByteState(void) { if (SerialAvailable() && (SerialRead() == LSR_MODULE_SERIAL_MSG_START_BYTE)) { au8UartRxBuffer[u8UartRxBufferIndex++] = LSR_MODULE_SERIAL_MSG_START_BYTE; ptrHostState = &LsrModule::HostRxGetMsgLengthState; } } /*** End HostRxWaitForMsgStartByteState ***/ /** * Gets data packet length byte. * */ void LsrModule::HostRxGetMsgLengthState(void) { if (SerialAvailable()) { u8RxReadByte = SerialRead(); if ((u8RxReadByte >= LSR_MODULE_MIN_SERIAL_RX_MSG_LENGTH) && (u8RxReadByte <= LSR_MODULE_MAX_SERIAL_RX_MSG_LENGTH)) { au8UartRxBuffer[u8UartRxBufferIndex++] = u8RxReadByte; ptrHostState = &LsrModule::HostRxGetMsgTypeState; } else { ptrHostState = &LsrModule::SerialRxCleanupRestart; } } } /*** End HostRxGetMsgLengthState ***/ /** * Gets data packet type byte. * */ void LsrModule::HostRxGetMsgTypeState(void) { if (SerialAvailable()) { u8RxReadByte = SerialRead(); if (ValidMsgLengthAndType(u8RxReadByte, au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX])) { au8UartRxBuffer[u8UartRxBufferIndex++] = u8RxReadByte; ptrHostState = &LsrModule::HostRxWaitToGetRestOfMsgState; } else { ptrHostState = &LsrModule::SerialRxCleanupRestart; } } } /*** End HostRxGetMsgTypeState ***/ /** * Grabs rest of data packet bytes. * */ void LsrModule::HostRxWaitToGetRestOfMsgState(void) { if (SerialAvailable()) { u8RxReadByte = SerialRead(); au8UartRxBuffer[u8UartRxBufferIndex++] = u8RxReadByte; if (u8UartRxBufferIndex > LSR_MODULE_MAX_SERIAL_RX_MSG_LENGTH) { ptrHostState = &LsrModule::SerialRxCleanupRestart; } else if ((u8RxReadByte == LSR_MODULE_SERIAL_MSG_END_BYTE) && (u8UartRxBufferIndex == au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX])) { ptrHostState = &LsrModule::HostRxValidateMsgState; } } } /*** End HostRxWaitToGetRestOfMsgState ***/ /** * Validates received message. * */ void LsrModule::HostRxValidateMsgState(void) { if (ValidRxChecksum(au8UartRxBuffer, au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX])) // Is checksum good? { ptrHostState = &LsrModule::HostRxGoodMsgState; // Good checksum - next state } else { ptrHostState = &LsrModule::SerialRxCleanupRestart; // Bad checksum - restart } } /*** End HostRxValidateMsgState ***/ /** * Calls appropriate received UART message callback and starts state machine over. * */ void LsrModule::HostRxGoodMsgState(void) { pu8RxBuffer = au8UartRxBuffer; u8RxMsgLength = au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX]; HostProcessCallbackMsgStart(au8UartRxBuffer, u8RxMsgLength); ptrHostState = &LsrModule::SerialRxCleanupRestart; // Start new RX sequence } /*** End HostRxGoodMsgState ***/