Library for using the LSR SiFlex/ProFlex RF modules with mbed.
LsrModule.cpp
- Committer:
- Issus
- Date:
- 2016-07-25
- Revision:
- 3:8d794c196710
- Parent:
- 2:2c0b7246d769
- Child:
- 4:2ac0b9a7f43a
File content as of revision 3:8d794c196710:
/**
* @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();
// 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 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 ***/
Mark Harris