Library for using the LSR SiFlex/ProFlex RF modules with mbed.

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