Library for using the LSR SiFlex/ProFlex RF modules with mbed.
Embed:
(wiki syntax)
Show/hide line numbers
LsrModule.cpp
Go to the documentation of this file.
00001 /** 00002 * @file LsrModule.cpp 00003 * @author LS Research LLC 00004 * @version 1.0 00005 * 00006 * @section LICENSE 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License as 00010 * published by the Free Software Foundation; either version 2 of 00011 * the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, but 00014 * WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * General Public License for more details at 00017 * http://www.gnu.org/copyleft/gpl.html 00018 * 00019 * @section DESCRIPTION 00020 * 00021 * Implementation of contents in LsrModule.h. 00022 */ 00023 00024 /** 00025 * Modified by Mark Harris at SAIT.ca 00026 * Improved functionality for mbed 00027 */ 00028 00029 #include "LsrModule.h " 00030 #include "mbed.h" 00031 00032 /** 00033 * C function pointer typedef. 00034 * 00035 */ 00036 typedef void (*ptrRxMsgCallback)(void); 00037 00038 /** 00039 * Table used for subscribing callback functions for 00040 * received UART messages. 00041 */ 00042 ptrRxMsgCallback ptrRxMsgCallbackTable[69]; 00043 00044 00045 /** 00046 * This table contains the min and max length for each message type. The first array index 00047 * is the message type and the second index is the min value (0) or max value (1). 00048 */ 00049 const uint8_t cau8RxMsgLengthAndTypeTable[69][2] = { 00050 {12, 39}, // 0x81 - Query Firmware Version Response 00051 {0, 0}, // 0x82 - Invalid message type 00052 {0, 0}, // 0x83 - Invalid message type 00053 {0, 0}, // 0x84 - Invalid message type 00054 {0, 0}, // 0x85 - Invalid message type 00055 {0, 0}, // 0x86 - Invalid message type 00056 {0, 0}, // 0x87 - Invalid message type 00057 {0, 0}, // 0x88 - Invalid message type 00058 {0, 0}, // 0x89 - Invalid message type 00059 {0, 0}, // 0x8A - Invalid message type 00060 {0, 0}, // 0x8B - Invalid message type 00061 {5, 5}, // 0x8C - Set Security Transmit Frame Counter Ack 00062 {11, 11}, // 0x8D - Query Security Transmit Frame Counter Response 00063 {0, 0}, // 0x8E - Invalid message type 00064 {0, 0}, // 0x8F - Invalid message type 00065 {5, 5}, // 0x90 - Set Basic RF Settings Ack 00066 {39, 39}, // 0x91 - Query Basic RF Settings Response 00067 {5, 5}, // 0x92 - Save Settings to NV Memory Ack 00068 {5, 5}, // 0x93 - Reset Request Ack 00069 {9, 9}, // 0x94 - Query Supply Voltage Response 00070 {21, 21}, // 0x95 - Query Statistics Response 00071 {5, 5}, // 0x96 - Clear Statistics Ack 00072 {0, 0}, // 0x97 - Invalid message type 00073 {5, 5}, // 0x98 - Set Host Data Rate Ack 00074 {0, 0}, // 0x99 - Invalid message type 00075 {0, 0}, // 0x9A - Invalid message type 00076 {0, 0}, // 0x9B - Invalid message type 00077 {0, 0}, // 0x9C - Invalid message type 00078 {0, 0}, // 0x9D - Invalid message type 00079 {0, 0}, // 0x9E - Invalid message type 00080 {0, 0}, // 0x9F - Invalid message type 00081 {7, 7}, // 0xA0 - Send Simple Short Address RF Data Packet Ack 00082 {17, 115}, // 0xA1 - Received Simple Short Address RF Data Packet 00083 {7, 7}, // 0xA2 - Send Advanced Short Address RF Data Packet Ack 00084 {21, 119}, // 0xA3 - Received Advanced Short Address RF Data Packet 00085 {7, 7}, // 0xA4 - Send Simple Long Address RF Data Packet Ack 00086 {29, 127}, // 0xA5 - Received Simple Long Address RF Data Packet 00087 {7, 7}, // 0xA6 - Send Advanced Long Address RF Data Packet Ack 00088 {33, 131}, // 0xA7 - Received Advanced Long Address RF Data Packet 00089 {0, 0}, // 0xA8 - Invalid message type 00090 {0, 0}, // 0xA9 - Invalid message type 00091 {0, 0}, // 0xAA - Invalid message type 00092 {0, 0}, // 0xAB - Invalid message type 00093 {0, 0}, // 0xAC - Invalid message type 00094 {0, 0}, // 0xAD - Invalid message type 00095 {13, 131}, // 0xAE - Received Promiscuous Mode Packet 00096 {0, 0}, // 0xAF - Invalid message type 00097 {0, 0}, // 0xB0 - Invalid message type 00098 {0, 0}, // 0xB1 - Invalid message type 00099 {0, 0}, // 0xB2 - Invalid message type 00100 {0, 0}, // 0xB3 - Invalid message type 00101 {0, 0}, // 0xB4 - Invalid message type 00102 {0, 0}, // 0xB5 - Invalid message type 00103 {0, 0}, // 0xB6 - Invalid message type 00104 {0, 0}, // 0xB7 - Invalid message type 00105 {0, 0}, // 0xB8 - Invalid message type 00106 {0, 0}, // 0xB9 - Invalid message type 00107 {0, 0}, // 0xBA - Invalid message type 00108 {0, 0}, // 0xBB - Invalid message type 00109 {0, 0}, // 0xBC - Invalid message type 00110 {0, 0}, // 0xBD - Invalid message type 00111 {0, 0}, // 0xBE - Invalid message type 00112 {0, 0}, // 0xBF - Invalid message type 00113 {0, 0}, // 0xC0 - Invalid message type 00114 {0, 0}, // 0xC1 - Invalid message type 00115 {0, 0}, // 0xC2 - Invalid message type 00116 {0 ,0}, // 0xC3 - Invalid message type 00117 {5, 5}, // 0xC4 - Channel Energy Scan Ack 00118 {23, 23} // 0xC5 - Channel Energy Scan Results 00119 }; 00120 00121 /** 00122 * Construnctor. 00123 * 00124 * Example: 00125 * 00126 * LsrModule(false, 19200); 00127 * 00128 */ 00129 LsrModule::LsrModule(PinName tx, PinName rx, int baudRate) : Serial(tx, rx) 00130 { 00131 baud(baudRate); 00132 00133 ptrHostState = &LsrModule::HostRxWaitForMsgStartByteState; 00134 00135 //attach(this, &LsrModule::RunHostRxStateMachine); 00136 } /*** End LsrModule ***/ 00137 00138 00139 /** 00140 * Destructor. Called automatically, de-allocates resources. 00141 * 00142 */ 00143 LsrModule::~LsrModule(void) 00144 { 00145 pu8RxBuffer = NULL; 00146 ptrHostState = NULL; 00147 ptrHostProcessCallbackState = NULL; 00148 00149 for (u8ForLoopCounter = 0; u8ForLoopCounter < sizeof(ptrRxMsgCallbackTable); u8ForLoopCounter++) 00150 { 00151 ptrRxMsgCallbackTable[u8ForLoopCounter] = NULL; 00152 } 00153 } /*** End ~LsrModule ***/ 00154 00155 00156 /** 00157 * Creates a callback for specific received UART message. Call this function from your main application in 00158 * this manner: "SubscribeRxMsgCallback(0xA1, &simpleShortAddrCallback)", where simpleShortAddrCallback is 00159 * defined like this: void simpleShortAddrCallback(void) in your main application. 00160 * IMPORTANT: All user defined callback methods must return void and take no parameters (void). 00161 * 00162 * @return True: Subscribed callback. False: Did not subscribe callback. 00163 * 00164 */ 00165 bool LsrModule::SubscribeRxMsgCallback(uint8_t u8RxMsgType ///< The received message for which you want the callback to execute. 00166 , void (*callback)(void) ///< C function pointer to the specified callback function. 00167 ) 00168 { 00169 if ((u8RxMsgType > LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE) && (u8RxMsgType < LSR_MODULE_MAX_SERIAL_RX_MSG_TYPE)) 00170 { 00171 ptrRxMsgCallbackTable[u8RxMsgType- LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE] = callback; 00172 return true; 00173 } 00174 00175 return false; 00176 } /*** End SubscribeRxMsgCallback ***/ 00177 00178 00179 /** 00180 * Removes a callback for specific received UART message. See SubscribeRxMsgCallback's description for 00181 * more information. 00182 * 00183 * @return True: Unsubscribed callback. False: Did not unsubscribed callback. 00184 * 00185 */ 00186 bool LsrModule::UnsubscribeRxMsgCallback(uint8_t u8RxMsgType ///< The received message for which you want the callback to be removed. 00187 ) 00188 { 00189 if ((u8RxMsgType > LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE) && (u8RxMsgType < LSR_MODULE_MAX_SERIAL_RX_MSG_TYPE)) 00190 { 00191 ptrRxMsgCallbackTable[u8RxMsgType - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE] = NULL; 00192 return true; 00193 } 00194 00195 return false; 00196 } /*** End UnsubscribeRxMsgCallback ***/ 00197 00198 00199 /** 00200 * Executes host RX state machine. This function must be executed continually from the loop function in your main 00201 * application. 00202 * 00203 */ 00204 void LsrModule::RunHostRxStateMachine(void) 00205 { 00206 (this->*ptrHostState)(); 00207 } /*** End RunHostRxStateMachine ***/ 00208 00209 00210 /** 00211 * Flushes appropriate serial port. 00212 * 00213 */ 00214 void LsrModule::SerialFlush(void) 00215 { 00216 // Serial.flush(); 00217 // i think this is meant to clean out the rx buffer 00218 /*** End SerialFlush ***/ 00219 } 00220 00221 /** 00222 * Adds header to the UART transmit buffer. 00223 * 00224 */ 00225 void LsrModule::AddSerialMsgHeader(uint8_t u8MsgType, uint8_t u8MsgLength) 00226 { 00227 SerialFlush(); 00228 u8UartTxBufferIndex = LSR_MODULE_MSG_START_BYTE_INDEX; 00229 au8UartTxBuffer[u8UartTxBufferIndex++] = LSR_MODULE_SERIAL_MSG_START_BYTE; 00230 au8UartTxBuffer[u8UartTxBufferIndex++] = u8MsgLength; 00231 au8UartTxBuffer[u8UartTxBufferIndex++] = u8MsgType; 00232 u8TxMsgChecksum = (LSR_MODULE_SERIAL_MSG_START_BYTE + u8MsgLength + u8MsgType); 00233 } /*** End LsrModuleAddSerialMsgHeader ***/ 00234 00235 00236 /** 00237 * Adds data bytes to the UART transmit buffer. 00238 * 00239 */ 00240 void LsrModule::AddSerialByteToMsgBuffer(uint8_t u8Data ///< The data to add. 00241 ) 00242 { 00243 au8UartTxBuffer[u8UartTxBufferIndex++] = u8Data; 00244 u8TxMsgChecksum += u8Data; 00245 } /*** End LsrModuleAddSerialByteToMsgBuffer ***/ 00246 00247 00248 /** 00249 * Adds message trailer to the UART transmit buffer. 00250 * 00251 */ 00252 void LsrModule::AddSerialMsgTrailer(void) 00253 { 00254 au8UartTxBuffer[u8UartTxBufferIndex++] = u8TxMsgChecksum; 00255 au8UartTxBuffer[u8UartTxBufferIndex] = LSR_MODULE_SERIAL_MSG_END_BYTE; 00256 WriteSerialMsg(); 00257 } /*** End AddSerialMsgTrailer ***/ 00258 00259 00260 /** 00261 * Writes the UART transmit buffer using the appropriate serial port. 00262 * 00263 */ 00264 void LsrModule::WriteSerialMsg(void) 00265 { 00266 //write (const uint8_t *buffer, int length, const event_callback_t &callback, int event=SERIAL_EVENT_TX_COMPLETE) 00267 write(au8UartTxBuffer, au8UartTxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX]); 00268 00269 } /*** End WriteSerialMsg ***/ 00270 00271 00272 /** 00273 * Sends message type 0x01 (Query Version) to the module via UART communication. This will spark 00274 * a response message from the module to the Arduino of type 0x81. Subscribing to 0x81 in 00275 * your main application will allow you to parse the response data. See the description for 00276 * SubscribeRxMsgCallback for more information. 00277 * 00278 */ 00279 void LsrModule::QueryVersionMsg(void) 00280 { 00281 AddSerialMsgHeader(LSR_MODULE_QUERY_VERSION_MSG_TYPE, 5); 00282 AddSerialMsgTrailer(); 00283 } /*** End QueryVersionMsg ***/ 00284 00285 00286 /** 00287 * Sends message type 0x0C (Sets Security Transmit Frame Counter) to the module via UART communication. 00288 * This frame counter is used with RF messages transmitted with security to ensure sequential freshness. 00289 * This sets the starting frame count and is automatically incremented on every secured packet sent. 00290 * This will spark an ACK message from the module to the Arduino of type 0x8C. Subscribing to 0x8C in 00291 * your main application will allow you to parse the response data. See the description for 00292 * SubscribeRxMsgCallback for more information. 00293 * 00294 * Example: 00295 * 00296 * uint32_t u32FrameCounter = 0xAEDFEDFA; 00297 * SetSecurityTransmitFrameCounterMsg(&u32FrameCounter); 00298 * 00299 */ 00300 void LsrModule::SetSecurityTransmitFrameCounterMsg(uint32_t* pu32FrameCounter ///< Pointer to 4 byte frame counter (LSB to MSB). 00301 ) 00302 { 00303 DWordu_t dwuFrameCounter; 00304 00305 dwuFrameCounter.u32 = *pu32FrameCounter; 00306 00307 AddSerialMsgHeader(LSR_MODULE_SET_SECURITY_TX_FRAME_COUNTER_MSG_TYPE, 11); 00308 AddSerialByteToMsgBuffer(dwuFrameCounter.dws.lb); 00309 AddSerialByteToMsgBuffer(dwuFrameCounter.dws.mlb); 00310 AddSerialByteToMsgBuffer(dwuFrameCounter.dws.mhb); 00311 AddSerialByteToMsgBuffer(dwuFrameCounter.dws.hb); 00312 AddSerialByteToMsgBuffer(0x00); // Add filler byte. 00313 AddSerialByteToMsgBuffer(0x00); // Add filler byte. 00314 AddSerialMsgTrailer(); 00315 } /*** End SetSecurityTransmitFrameCounterMsg ***/ 00316 00317 00318 /** 00319 * Sends message type 0x0D (Query Security Transmit Frame Counter) to the module via UART communication. This 00320 * will spark a response message from the module to the Arduino of type 0x8D. Subscribing to 0x8D in your main 00321 * application will allow you to parse the response data. See the description for SubscribeRxMsgCallback 00322 * for more information. 00323 * 00324 */ 00325 void LsrModule::QuerySecurityTransmitFrameCounterMsg(void) 00326 { 00327 AddSerialMsgHeader(LSR_MODULE_QUERY_SECURITY_TX_FRAME_COUNTER_MSG_TYPE, 5); 00328 AddSerialMsgTrailer(); 00329 } /*** End QuerySecurityTransmitFrameCounterMsg ***/ 00330 00331 00332 /** 00333 * Sends message type 0x10 (Set Basic RF Settings) to the module via UART communication. 00334 * This will spark an ACK message from the module to the Arduino of type 0x90. Subscribing to 0x90 in 00335 * your main application will allow you to parse the response data. See the description for 00336 * SubscribeRxMsgCallback for more information. 00337 * 00338 */ 00339 void LsrModule::SetBasicRfSettingsMsg(uint16_t u16PanId ///< Personal Area Network (PAN) ID assigned to module. 00340 , uint16_t u16AddrShort ///< 2 byte short address assigned to module. 00341 , uint8_t* pu8AddrLong ///< Pointer to 8 byte long address assigned to module. Do not assign a zero, even if using short addressing. 00342 , uint8_t u8RfChannel ///< RF channel assigned to module. 00343 , uint8_t u8TxPowerLevel ///< Transmit power assigned to module. 00344 , uint8_t u8ReceiverConfig ///< 1 byte bitmask of receiver options. 00345 , uint8_t* pu8SecurityKey ///< Pointer to 32 byte security key assigned to module. 00346 ) 00347 { 00348 Wordu_t wuPanId; 00349 Wordu_t wuShortAddr; 00350 00351 wuPanId.u16 = u16PanId; 00352 wuShortAddr.u16 = u16AddrShort; 00353 00354 if ((u8RfChannel >= LSR_MODULE_RF_CHANNEL_MIN) && (u8RfChannel <= LSR_MODULE_RF_CHANNEL_MAX) && 00355 (u8TxPowerLevel <= LSR_MODULE_TX_POWER_LEVEL_MAX) && 00356 (u8ReceiverConfig <= LSR_MODULE_RX_CONFIG_MAX)) 00357 { 00358 AddSerialMsgHeader(LSR_MODULE_SET_BASIC_RF_SETTINGS_MSG_TYPE, 39); 00359 AddSerialByteToMsgBuffer(wuPanId.ws.lb); 00360 AddSerialByteToMsgBuffer(wuPanId.ws.hb); 00361 AddSerialByteToMsgBuffer(wuShortAddr.ws.lb); 00362 AddSerialByteToMsgBuffer(wuShortAddr.ws.hb); 00363 00364 for (u8ForLoopCounter = 0; u8ForLoopCounter < 8; u8ForLoopCounter++) 00365 { 00366 AddSerialByteToMsgBuffer(*pu8AddrLong); 00367 pu8AddrLong++; 00368 } 00369 00370 AddSerialByteToMsgBuffer(u8RfChannel); 00371 AddSerialByteToMsgBuffer(u8TxPowerLevel); 00372 AddSerialByteToMsgBuffer(u8ReceiverConfig); 00373 00374 AddSerialByteToMsgBuffer(0x00); // Add filler byte. 00375 AddSerialByteToMsgBuffer(0x00); // Add filler byte. 00376 AddSerialByteToMsgBuffer(0x00); // Add filler byte. 00377 00378 for (u8ForLoopCounter = 0; u8ForLoopCounter < 16; u8ForLoopCounter++) 00379 { 00380 AddSerialByteToMsgBuffer(*pu8SecurityKey); 00381 pu8SecurityKey++; 00382 } 00383 00384 AddSerialMsgTrailer(); 00385 } 00386 } /*** End SetBasicRfSettingsMsg ***/ 00387 00388 00389 /** 00390 * Sends message type 0x11 (Query Basic RF Settings) to the module via UART communication. This will spark 00391 * a response message from the module to the Arduino of type 0x91. Subscribing to 0x91 in your main 00392 * application will allow you to parse the response data. See the description for SubscribeRxMsgCallback 00393 * for more information. 00394 * 00395 */ 00396 void LsrModule::QueryBasicRfSettingsMsg(void) 00397 { 00398 AddSerialMsgHeader(LSR_MODULE_QUERY_BASIC_RF_SETTINGS_MSG_TYPE, 5); 00399 AddSerialMsgTrailer(); 00400 } /*** End QueryBasicRfSettingsMsg ***/ 00401 00402 00403 /** 00404 * Sends message type 0x12 (Save Settings to non-volatile Memory) to the module via UART communication. Calling 00405 * this command will make your module retain all basic configuration settings on boot up. This will spark an ACK 00406 * message from the module to the Arduino of type 0x92. Subscribing to 0x92 in your main application will allow 00407 * you to parse the response data. See the description for SubscribeRxMsgCallback for more information. 00408 * 00409 */ 00410 void LsrModule::SaveSettingsToNVMemoryMsg(void) 00411 { 00412 AddSerialMsgHeader(LSR_MODULE_SAVE_SETTINGS_TO_NV_MEMORY_MSG_TYPE, 5); 00413 AddSerialMsgTrailer(); 00414 } /*** End SaveSettingsToNVMemoryMsg ***/ 00415 00416 00417 /** 00418 * Sends message type 0x13 (Reset Request) to the module via UART communication. This will make your module perform 00419 * a restart. This will spark an ACK message from the module to the Arduino of type 0x93. Subscribing to 0x93 in 00420 * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback 00421 * for more information. 00422 * 00423 */ 00424 void LsrModule::ResetRequestMsg(void) 00425 { 00426 AddSerialMsgHeader(LSR_MODULE_RESET_REQUEST_MSG_TYPE, 5); 00427 AddSerialMsgTrailer(); 00428 } /*** End ResetRequestMsg ***/ 00429 00430 00431 /** 00432 * Sends message type 0x14 (Query Supply Voltage) to the module via UART communication. This will spark a 00433 * response message from the module to the Arduino of type 0x94. Subscribing to 0x94 in your main application 00434 * will allow you to parse the response data. See the description for SubscribeRxMsgCallback for more information. 00435 * 00436 */ 00437 void LsrModule::QuerySupplyVoltageMsg(void) 00438 { 00439 AddSerialMsgHeader(LSR_MODULE_QUERY_SUPPLY_VOLTAGE_MSG_TYPE, 5); 00440 AddSerialMsgTrailer(); 00441 } /*** End QuerySupplyVoltageMsg ***/ 00442 00443 00444 /** 00445 * Sends message type 0x15 (Query Statistics) to the module via UART communication. Statistics include packets sent, 00446 * acks received, packets received and broadcast packets received. This will spark a response message from the module 00447 * to the Arduino of type 0x95. Subscribing to 0x94 in your main application will allow you to parse the response 00448 * data. See the description for SubscribeRxMsgCallback for more information. 00449 * 00450 */ 00451 void LsrModule::QueryStatisticsMsg(void) 00452 { 00453 AddSerialMsgHeader(LSR_MODULE_QUERY_STATISTICS_MSG_TYPE, 5); 00454 AddSerialMsgTrailer(); 00455 } /*** End QueryStatisticsMsg ***/ 00456 00457 00458 /** 00459 * Sends message type 0x16 (Clear Statistics) to the module via UART communication. This will spark an ACK message 00460 * from the module to the Arduino of type 0x96. Subscribing to 0x96 in your main application will allow you to 00461 * Parse the response data. See the description for SubscribeRxMsgCallback for more information. 00462 * 00463 */ 00464 void LsrModule::ClearStatisticsMsg(void) 00465 { 00466 AddSerialMsgHeader(LSR_MODULE_CLEAR_STATISTICS_MSG_TYPE, 5); 00467 AddSerialMsgTrailer(); 00468 } /*** End ClearStatisticsMsg ***/ 00469 00470 00471 /** 00472 * Sends message type 0x18 (Set Host Data Rate) to the module via UART communication. This will spark an ACK message 00473 * from the module to the Arduino of type 0x98. Subscribing to 0x98 in your main application will allow you to parse 00474 * the response data. See the description for SubscribeRxMsgCallback for more information. 00475 * 00476 */ 00477 void LsrModule::SetHostDataRateMsg(uint8_t u8HostDataRate ///< Data rate for module to use when communicating via UART: 00478 ///< 0 = 1,200 bits/s 00479 ///< 1 = 2,400 bits/s 00480 ///< 2 = 4,800 bits/s 00481 ///< 3 = 9,600 bits/s 00482 ///< 4 = 19,200 bits/s 00483 ///< 5 = 38,400 bits/s 00484 ///< 6 = 57,600 bits/s 00485 ///< 7 = 115,200 bits/s 00486 ) 00487 { 00488 if (u8HostDataRate <= LSR_MODULE_HOST_DATA_RATE_MAX) 00489 { 00490 AddSerialMsgHeader(LSR_MODULE_SET_HOST_DATA_RATE_MSG_TYPE, 6); 00491 AddSerialByteToMsgBuffer(u8HostDataRate); 00492 AddSerialMsgTrailer(); 00493 00494 // 2.4 ms for the data rate change packet to be transmitted. 00495 wait_ms(3); 00496 00497 switch (u8HostDataRate) 00498 { 00499 case LSR_MODULE_HOST_DATA_RATE_1200: 00500 baud(1200); 00501 break; 00502 case LSR_MODULE_HOST_DATA_RATE_2400: 00503 baud(2400); 00504 break; 00505 case LSR_MODULE_HOST_DATA_RATE_4800: 00506 baud(4800); 00507 break; 00508 case LSR_MODULE_HOST_DATA_RATE_9600: 00509 baud(9600); 00510 break; 00511 case LSR_MODULE_HOST_DATA_RATE_19200: 00512 baud(19200); 00513 break; 00514 case LSR_MODULE_HOST_DATA_RATE_38400: 00515 baud(38400); 00516 break; 00517 case LSR_MODULE_HOST_DATA_RATE_57600: 00518 baud(57600); 00519 break; 00520 case LSR_MODULE_HOST_DATA_RATE_115200: 00521 baud(115200); 00522 break; 00523 case LSR_MODULE_HOST_DATA_RATE_230400: 00524 baud(230400); 00525 break; 00526 case LSR_MODULE_HOST_DATA_RATE_460800: 00527 baud(460800); 00528 break; 00529 case LSR_MODULE_HOST_DATA_RATE_921600: 00530 baud(921600); 00531 break; 00532 } 00533 } 00534 } /*** End SetHostDataRateMsg ***/ 00535 00536 00537 /** 00538 * Sends message type 0x19 (Set RF Data Rate) to the module via UART communication. This will spark an ACK message 00539 * from the module to the Arduino of type 0x98. Subscribing to 0x98 in your main application will allow you to parse 00540 * the response data. See the description for SubscribeRxMsgCallback for more information. 00541 * 00542 */ 00543 void LsrModule::SetRfDataRateMsg(uint8_t u8RfDataRate ///< Data rate for module to use when communicating via radio: 00544 ///< 0 = 1,200 bits/s 00545 ///< 1 = 2,400 bits/s 00546 ///< 2 = 4,800 bits/s 00547 ///< 3 = 9,600 bits/s 00548 ///< 4 = 19,200 bits/s 00549 ///< 5 = 38,400 bits/s 00550 ///< 6 = 57,600 bits/s 00551 ///< 7 = 115,200 bits/s 00552 ) 00553 { 00554 if (u8RfDataRate <= LSR_MODULE_RF_DATA_RATE_MAX) 00555 { 00556 AddSerialMsgHeader(LSR_MODULE_SET_RF_DATA_RATE_MSG_TYPE, 6); 00557 AddSerialByteToMsgBuffer(u8RfDataRate); 00558 AddSerialMsgTrailer(); 00559 } 00560 } /*** End SetRfDataRateMsg ***/ 00561 00562 /** 00563 * Sends message type 0x20 (Send Simple Short Address RF Data Packet) to the module via UART communication. 00564 * This will spark an ACK message from the module to the Arduino of type 0xA0. Subscribing to 0xA0 in 00565 * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback 00566 * for more information. 00567 * 00568 * Example: 00569 * 00570 * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; 00571 * uint8_t u8PacketID; 00572 * 00573 * SendSimpleShortAddrRfDataPacketMsg(&u8Data, sizeof(u8Data, 213, 0, packetID++); 00574 * 00575 */ 00576 void LsrModule::SendSimpleShortAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. 00577 , uint8_t u8DataLength ///< Length of data being sent. 00578 , uint16_t u16DestAddress ///< 2 byte destination address. 00579 , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. 00580 , uint8_t u8PacketId ///< ID assigned to packet. 00581 ) 00582 { 00583 if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && 00584 ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_SIMPLE_SHORT_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || 00585 (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_SIMPLE_SHORT_RF_DATA_LENGTH)))) 00586 { 00587 AddSerialMsgHeader(LSR_MODULE_SEND_SIMPLE_SHORT_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 9)); 00588 00589 AddSerialByteToMsgBuffer(u8TxOptions); 00590 AddSerialByteToMsgBuffer(u16DestAddress % 256); 00591 AddSerialByteToMsgBuffer(u16DestAddress >> 8); 00592 AddSerialByteToMsgBuffer(u8PacketId); 00593 00594 while (u8DataLength != 0) 00595 { 00596 AddSerialByteToMsgBuffer(*pu8Data); 00597 pu8Data++; 00598 u8DataLength--; 00599 } 00600 00601 AddSerialMsgTrailer(); 00602 } 00603 } /*** End SendSimpleShortAddrRfDataPacketMsg ***/ 00604 00605 00606 /** 00607 * Sends message type 0x22 (Send Advanced Short Address RF Data Packet) to the module via UART communication. 00608 * This will spark an ACK message from the module to the Arduino of type 0xA2. Subscribing to 0xA2 in 00609 * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback 00610 * for more information. 00611 * 00612 * Example: 00613 * 00614 * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; 00615 * uint8_t u8PacketID; 00616 * 00617 * SendAdvancedShortAddrRfDataPacketMsg(&u8Data, sizeof(u8Data, 1111, 213, 0, packetID++); 00618 * 00619 */ 00620 void LsrModule::SendAdvancedShortAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. 00621 , uint8_t u8DataLength ///< Length of data being sent. 00622 , uint16_t u16DestPanId ///< 2 byte Personal Area Network (PAN) ID. 00623 , uint16_t u16DestAddress ///< 2 byte destination address. 00624 , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. 00625 , uint8_t u8PacketId ///< ID assigned to packet. 00626 ) 00627 { 00628 if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && 00629 ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_ADVANCED_SHORT_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || 00630 (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_ADVANCED_SHORT_RF_DATA_LENGTH)))) 00631 { 00632 AddSerialMsgHeader(LSR_MODULE_SEND_ADVANCED_SHORT_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 11)); 00633 00634 AddSerialByteToMsgBuffer(u8TxOptions); 00635 AddSerialByteToMsgBuffer(u16DestPanId % 256); 00636 AddSerialByteToMsgBuffer(u16DestPanId >> 8); 00637 AddSerialByteToMsgBuffer(u16DestAddress % 256); 00638 AddSerialByteToMsgBuffer(u16DestAddress >> 8); 00639 AddSerialByteToMsgBuffer(u8PacketId); 00640 00641 while (u8DataLength != 0) 00642 { 00643 AddSerialByteToMsgBuffer(*pu8Data); 00644 pu8Data++; 00645 u8DataLength--; 00646 } 00647 00648 AddSerialMsgTrailer(); 00649 } 00650 } /*** End SendAdvancedShortAddrRfDataPacketMsg ***/ 00651 00652 00653 /** 00654 * Sends message type 0x24 (Send Simple Long Address RF Data Packet) to the module via UART communication. 00655 * This will spark an ACK message from the module to the Arduino of type 0xA4. Subscribing to 0xA4 in 00656 * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback 00657 * for more information. 00658 * 00659 * Example: 00660 * 00661 * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; 00662 * uint8_t u8DestAddress[8] = {2, 3, 6, 5, 2, 3, 6, 5}; 00663 * uint8_t u8PacketID; 00664 * 00665 * SendSimpleLongAddrRfDataPacketMsg(&u8Data, sizeof(u8Data), &u8DestAddress, 0, packetID++); 00666 * 00667 */ 00668 void LsrModule::SendSimpleLongAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. 00669 , uint8_t u8DataLength ///< Length of data being sent. 00670 , uint8_t* pu8DestAddress ///< Pointer to 8 byte destination address. 00671 , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. 00672 , uint8_t u8PacketId ///< ID assigned to packet. 00673 ) 00674 { 00675 if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && 00676 ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_SIMPLE_LONG_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || 00677 (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_SIMPLE_LONG_RF_DATA_LENGTH)))) 00678 { 00679 AddSerialMsgHeader(LSR_MODULE_SEND_SIMPLE_LONG_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 15)); 00680 00681 AddSerialByteToMsgBuffer(u8TxOptions); 00682 00683 for (u8ForLoopCounter = 0; u8ForLoopCounter < 8; u8ForLoopCounter++) 00684 { 00685 AddSerialByteToMsgBuffer(*pu8DestAddress); 00686 pu8DestAddress++; 00687 } 00688 00689 AddSerialByteToMsgBuffer(u8PacketId); 00690 00691 while (u8DataLength != 0) 00692 { 00693 AddSerialByteToMsgBuffer(*pu8Data); 00694 pu8Data++; 00695 u8DataLength--; 00696 } 00697 00698 AddSerialMsgTrailer(); 00699 } 00700 } /*** End SendSimpleLongAddrRfDataPacketMsg ***/ 00701 00702 00703 /** 00704 * Sends message type 0x26 (Send Advanced Long Address RF Data Packet) to the module via UART communication. 00705 * This will spark an ACK message from the module to the Arduino of type 0xA6. Subscribing to 0xA6 in 00706 * your main application will allow you to parse the response data. See the description for SubscribeRxMsgCallback 00707 * for more information. 00708 * 00709 * Example: 00710 * 00711 * uint8_t u8Data[5] = {4, 7, 3, 5, 8}; 00712 * uint8_t u8DestAddress[8] = {2, 3, 6, 5, 2, 3, 6, 5}; 00713 * uint8_t u8PacketID; 00714 * 00715 * SendAdvancedLongAddrRfDataPacketMsg(&u8Data, sizeof(u8Data), 1111, &u8DestAddress, 0, packetID++); 00716 * 00717 */ 00718 void LsrModule::SendAdvancedLongAddrRfDataPacketMsg(uint8_t* pu8Data ///< Pointer to data being sent. 00719 , uint8_t u8DataLength ///< Length of data being sent. 00720 , uint16_t u16DestPanId ///< 2 byte Personal Area Network (PAN) ID. 00721 , uint8_t* pu8DestAddress ///< Pointer to 8 byte destination address. 00722 , uint8_t u8TxOptions ///< 1 byte bit mask of transmit options. 00723 , uint8_t u8PacketId ///< ID assigned to packet. 00724 ) 00725 { 00726 if ((u8TxOptions <= LSR_MODULE_TX_OPTIONS_MAX) && 00727 ((((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) != 0) && (u8DataLength <= (LSR_MODULE_ADVANCED_LONG_RF_DATA_LENGTH - LSR_MODULE_SECURITY_OVERHEAD))) || 00728 (((u8TxOptions & LSR_MODULE_TX_OPTIONS_USE_SECURITY_BITMASK) == 0) && (u8DataLength <= LSR_MODULE_ADVANCED_LONG_RF_DATA_LENGTH)))) 00729 { 00730 AddSerialMsgHeader(LSR_MODULE_SEND_ADVANCED_LONG_RF_DATA_PACKET_MSG_TYPE, (u8DataLength + 17)); 00731 00732 AddSerialByteToMsgBuffer(u8TxOptions); 00733 AddSerialByteToMsgBuffer(u16DestPanId % 256); 00734 AddSerialByteToMsgBuffer(u16DestPanId >> 8); 00735 00736 for (u8ForLoopCounter = 0; u8ForLoopCounter < 8; u8ForLoopCounter++) 00737 { 00738 AddSerialByteToMsgBuffer(*pu8DestAddress); 00739 pu8DestAddress++; 00740 } 00741 00742 AddSerialByteToMsgBuffer(u8PacketId); 00743 00744 while (u8DataLength != 0) 00745 { 00746 AddSerialByteToMsgBuffer(*pu8Data); 00747 pu8Data++; 00748 u8DataLength--; 00749 } 00750 00751 AddSerialMsgTrailer(); 00752 } 00753 } /*** End SendAdvancedLongAddrRfDataPacketMsg ***/ 00754 00755 00756 /** 00757 * Sends message type 0x44 (Channel Energy Scan) to the module via UART communication. This will spark a response message from the module 00758 * to the host of type 0xC5. Subscribing to 0xC5 in your main application will allow you to parse the response 00759 * data. See the description for SubscribeRxMsgCallback for more information. 00760 * 00761 * Example (Channel 5 for SiFLEX02, Channel 15 for ProFLEX01): 00762 * 00763 * ChannelEnergyScanMsg(11110111, 7); 00764 * 00765 */ 00766 void LsrModule::ChannelEnergyScanMsg(uint16_t u16ChannelMask ///< Two byte bitmask (LSB to MSB) of the RF channels to perfom an enrgy scan on. 00767 , uint8_t u8ScanDuration ///< Duration to scan for: 00768 ///< 0 = 61.4 mSec 00769 ///< 1 = 92.2 mSec 00770 ///< 2 = 154 mSec 00771 ///< 3 = 276 mSec 00772 ///< 4 = 522 mSec 00773 ///< 5 = 1.01 Sec 00774 ///< 6 = 2.00 Sec 00775 ///< 7 = 3.96 Sec 00776 ///< 8 = 7.90 Sec 00777 ///< 9 = 15.8 Sec 00778 ///< 10 = 31.5 Sec 00779 ///< 11 = 62.9 Sec 00780 ///< 12 = 126 Sec 00781 ///< 13 = 252 Sec 00782 ///< 14 = 503 Sec 00783 00784 ) 00785 { 00786 Wordu_t wuChannelMask; 00787 00788 wuChannelMask.u16 = u16ChannelMask; 00789 00790 if (u8ScanDuration <= LSR_MODULE_SCAN_DURATION_MAX) 00791 { 00792 AddSerialMsgHeader(LSR_MODULE_CHANNEL_ENERGY_SCAN_MSG_TYPE, 8); 00793 AddSerialByteToMsgBuffer(wuChannelMask.ws.lb); 00794 AddSerialByteToMsgBuffer(wuChannelMask.ws.hb); 00795 AddSerialByteToMsgBuffer(u8ScanDuration); 00796 AddSerialMsgTrailer(); 00797 } 00798 } /*** End ChannelEnergyScanMsg ***/ 00799 00800 /** 00801 * Sends message type 0x51 (Query Host Interface Configuration) to the module via UART communication. This will spark a 00802 * response message from the module to the host of type 0xD1. Subscribing to 0xD1 in your main application 00803 * will allow you to parse the response data. See the description for SubscribeRxMsgCallback for more information. 00804 * 00805 */ 00806 void LsrModule::QueryHostInterfaceConfiguration(void) 00807 { 00808 AddSerialMsgHeader(LSR_MODULE_QUERY_HOST_INTERFACE_CONFIGURATION, 5); 00809 AddSerialMsgTrailer(); 00810 } /*** End QuerySupplyVoltageMsg ***/ 00811 00812 00813 00814 /** 00815 * Verifies msg type and length. 00816 * @return True: Valid msg length and type. False: Invalid msg length or type. 00817 * 00818 */ 00819 bool LsrModule::ValidMsgLengthAndType(uint8_t u8MsgType ///< Received UART message type. 00820 , uint8_t u8MsgLength ///< Received UART message length. 00821 ) 00822 { 00823 if ((u8MsgLength >= cau8RxMsgLengthAndTypeTable[u8MsgType - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE][0]) && 00824 (u8MsgLength <= cau8RxMsgLengthAndTypeTable[u8MsgType - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE][1])) 00825 { 00826 return true; 00827 } 00828 return false; 00829 } /*** End ValidMsgLengthAndType ***/ 00830 00831 00832 /** 00833 * Verifies message checksum. 00834 * @return True: Valid checksum. False: Invalid checksum. 00835 * 00836 */ 00837 bool LsrModule::ValidRxChecksum(uint8_t* pu8MsgBuffer ///< Pointer to received UART buffer. 00838 , uint8_t u8MsgLength ///< Received UART message length. 00839 ) 00840 { 00841 uint8_t u8Checksum = 0; 00842 00843 for (u8ForLoopCounter = 0; u8ForLoopCounter < (u8MsgLength - 2); u8ForLoopCounter++) 00844 { 00845 u8Checksum += au8UartRxBuffer[u8ForLoopCounter]; 00846 } 00847 00848 if (au8UartRxBuffer[u8MsgLength-2] == u8Checksum) 00849 { 00850 return true; 00851 } 00852 00853 return false; 00854 } /*** End ValidRxChecksum ***/ 00855 00856 00857 /** 00858 * Calls appropriate callback function for received message. 00859 * 00860 */ 00861 void LsrModule::HostProcessCallbackMsgStart(uint8_t* pu8MsgBuffer ///< Pointer to received message. 00862 , uint8_t u8Length ///< Length of received message. 00863 ) 00864 { 00865 if ((ptrRxMsgCallbackTable[(*(pu8MsgBuffer + LSR_MODULE_MSG_TYPE_BYTE_INDEX)) - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE]) != NULL) 00866 { 00867 ptrRxMsgCallbackTable[(*(pu8MsgBuffer + LSR_MODULE_MSG_TYPE_BYTE_INDEX)) - LSR_MODULE_MIN_SERIAL_RX_MSG_TYPE](); 00868 } 00869 } /*** End HostProcessCallbackMsgStart ***/ 00870 00871 00872 /** 00873 * Determines if appropriate serial port is available. 00874 * @return True: Serial is available. False: Serial is unavailable. 00875 * 00876 */ 00877 bool LsrModule::SerialAvailable(void) 00878 { 00879 if (readable()) 00880 { 00881 return true; 00882 } 00883 00884 return false; 00885 } /*** End SerialAvailable ***/ 00886 00887 00888 /** 00889 * Reads appropriate serial port. 00890 * @return Byte read. 00891 * 00892 */ 00893 uint8_t LsrModule::SerialRead(void) 00894 { 00895 return getc(); 00896 00897 } /*** End SerialRead ***/ 00898 00899 00900 /** 00901 * Refreshes and restarts Rx state machine. 00902 * 00903 */ 00904 void LsrModule::SerialRxCleanupRestart(void) 00905 { 00906 SerialFlush(); 00907 u8UartRxBufferIndex = LSR_MODULE_MSG_START_BYTE_INDEX; 00908 ptrHostState = &LsrModule::HostRxWaitForMsgStartByteState; 00909 } /*** End SerialRxCleanupRestart ***/ 00910 00911 00912 /** 00913 * Waits for data packet start byte. 00914 * 00915 */ 00916 void LsrModule::HostRxWaitForMsgStartByteState(void) 00917 { 00918 while (readable() && (SerialRead() == LSR_MODULE_SERIAL_MSG_START_BYTE)) 00919 { 00920 au8UartRxBuffer[u8UartRxBufferIndex++] = LSR_MODULE_SERIAL_MSG_START_BYTE; 00921 ptrHostState = &LsrModule::HostRxGetMsgLengthState; 00922 } 00923 } /*** End HostRxWaitForMsgStartByteState ***/ 00924 00925 00926 /** 00927 * Gets data packet length byte. 00928 * 00929 */ 00930 void LsrModule::HostRxGetMsgLengthState(void) 00931 { 00932 while (readable()) 00933 { 00934 u8RxReadByte = SerialRead(); 00935 00936 if ((u8RxReadByte >= LSR_MODULE_MIN_SERIAL_RX_MSG_LENGTH) && 00937 (u8RxReadByte <= LSR_MODULE_MAX_SERIAL_RX_MSG_LENGTH)) 00938 { 00939 au8UartRxBuffer[u8UartRxBufferIndex++] = u8RxReadByte; 00940 ptrHostState = &LsrModule::HostRxGetMsgTypeState; 00941 } 00942 else 00943 { 00944 ptrHostState = &LsrModule::SerialRxCleanupRestart; 00945 } 00946 } 00947 } /*** End HostRxGetMsgLengthState ***/ 00948 00949 00950 /** 00951 * Gets data packet type byte. 00952 * 00953 */ 00954 void LsrModule::HostRxGetMsgTypeState(void) 00955 { 00956 while (readable()) 00957 { 00958 00959 u8RxReadByte = SerialRead(); 00960 00961 if (ValidMsgLengthAndType(u8RxReadByte, au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX])) 00962 { 00963 au8UartRxBuffer[u8UartRxBufferIndex++] = u8RxReadByte; 00964 ptrHostState = &LsrModule::HostRxWaitToGetRestOfMsgState; 00965 } 00966 else 00967 { 00968 ptrHostState = &LsrModule::SerialRxCleanupRestart; 00969 } 00970 } 00971 } /*** End HostRxGetMsgTypeState ***/ 00972 00973 00974 /** 00975 * Grabs rest of data packet bytes. 00976 * 00977 */ 00978 void LsrModule::HostRxWaitToGetRestOfMsgState(void) 00979 { 00980 while (readable()) 00981 { 00982 u8RxReadByte = SerialRead(); 00983 au8UartRxBuffer[u8UartRxBufferIndex++] = u8RxReadByte; 00984 00985 if (u8UartRxBufferIndex > LSR_MODULE_MAX_SERIAL_RX_MSG_LENGTH) 00986 { 00987 ptrHostState = &LsrModule::SerialRxCleanupRestart; 00988 } 00989 else if ((u8RxReadByte == LSR_MODULE_SERIAL_MSG_END_BYTE) && (u8UartRxBufferIndex == au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX])) 00990 { 00991 ptrHostState = &LsrModule::HostRxValidateMsgState; 00992 } 00993 } 00994 } /*** End HostRxWaitToGetRestOfMsgState ***/ 00995 00996 00997 /** 00998 * Validates received message. 00999 * 01000 */ 01001 void LsrModule::HostRxValidateMsgState(void) 01002 { 01003 01004 if (ValidRxChecksum(au8UartRxBuffer, au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX])) // Is checksum good? 01005 { 01006 ptrHostState = &LsrModule::HostRxGoodMsgState; // Good checksum - next state 01007 } 01008 else 01009 { 01010 ptrHostState = &LsrModule::SerialRxCleanupRestart; // Bad checksum - restart 01011 } 01012 } /*** End HostRxValidateMsgState ***/ 01013 01014 01015 /** 01016 * Calls appropriate received UART message callback and starts state machine over. 01017 * 01018 */ 01019 void LsrModule::HostRxGoodMsgState(void) 01020 { 01021 pu8RxBuffer = au8UartRxBuffer; 01022 u8RxMsgLength = au8UartRxBuffer[LSR_MODULE_MSG_LENGTH_BYTE_INDEX]; 01023 HostProcessCallbackMsgStart(au8UartRxBuffer, u8RxMsgLength); 01024 ptrHostState = &LsrModule::SerialRxCleanupRestart; // Start new RX sequence 01025 } /*** End HostRxGoodMsgState ***/
Generated on Tue Jul 12 2022 21:29:55 by
1.7.2
Mark Harris