Library for using the LSR SiFlex/ProFlex RF modules with mbed.
Diff: LsrModule.cpp
- Revision:
- 0:f9cf4a19bb84
- Child:
- 2:2c0b7246d769
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LsrModule.cpp Mon Jul 25 16:18:48 2016 +0000
@@ -0,0 +1,945 @@
+/**
+ * @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();
+ }
+} /*** 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 ***/
\ No newline at end of file
Mark Harris