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

LsrModule.cpp

Committer:
Issus
Date:
2016-07-29
Revision:
9:98edda6ea79e
Parent:
8:10f8dbd8dfff

File content as of revision 9:98edda6ea79e:

/**
 * @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;
    
    //attach(this, &LsrModule::RunHostRxStateMachine);
}   /*** 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();
        
        // 2.4 ms for the data rate change packet to be transmitted.
        wait_ms(3);
        
        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 0x19 (Set RF 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::SetRfDataRateMsg(uint8_t u8RfDataRate ///< Data rate for module to use when communicating via radio:
                                 ///< 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 (u8RfDataRate <= LSR_MODULE_RF_DATA_RATE_MAX)
    {
        AddSerialMsgHeader(LSR_MODULE_SET_RF_DATA_RATE_MSG_TYPE, 6);
        AddSerialByteToMsgBuffer(u8RfDataRate);
        AddSerialMsgTrailer();
    }
}   /*** End SetRfDataRateMsg ***/

/**
* 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 host 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 ***/

/**
* Sends message type 0x51 (Query Host Interface Configuration) to the module via UART communication.  This will spark a 
* response message from the module to the host of type 0xD1.  Subscribing to 0xD1 in your main application
* will allow you to parse the response data.  See the description for SubscribeRxMsgCallback for more information.
*
*/
void LsrModule::QueryHostInterfaceConfiguration(void)
{
    AddSerialMsgHeader(LSR_MODULE_QUERY_HOST_INTERFACE_CONFIGURATION, 5);
    AddSerialMsgTrailer();
}   /*** End QuerySupplyVoltageMsg ***/



/**
* 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)
{
    while (readable() && (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)
{
    while (readable())
    {
        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)
{
    while (readable())
    {

        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)
{
    while (readable())
    {
        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 ***/