API for communicating with XBee devices.

Dependencies:   CircularBuffer FixedLengthList

Dependents:   XBeeApiTest XBeeApiSimpleATCmdsExample XBeeApiBroadcastExample XBeeApiBroadcastExampleRTOS ... more

Overview

XBeeApi is intended to be a library for providing a high-level API interface to the XBee - for example getChannel() and setChannel(2) methods rather than needing to send( "ATCH" ) and send( "ATCH 2" ) - and then de-code the responses.

See the notebook page here for a description of how the API works & some details on the various classes.

Features:

  • Support for transmission & reception of data packets
  • Support for reading & changing settings
  • Support for "Remote AT" interface to access settings & I/O channels on remote XBees
  • XBeeApi should work if you're using mbed-rtos, though it is not currently threadsafe. Take a look at the XBeeApiBroadcastExampleRTOS example if you're including mbed-rtos.

Example Programs

There are also example programs available:

Transmit

Import programXBeeApiSimpleBroadcastExample

Simple example of how to use XBeeApi - set up the XBee, configure P2P networking then transmit a frame.

Import programXBeeApiBroadcastExample

Example for XBeeAPI; a little more involved than XBeeApiSimpleBroadcastExample with report on failure to set up the XBee and on the transmit status of the message.

Import programXBeeApiBroadcastExampleRTOS

Example of using the XBeeApi library to broadcast a message, based on XBeeApiBroadcastExample. This example shows how to use the library when using mbed-rtos. Before compiling you must open "XbeeApi\Config\XBeeApiCfg.hpp" and change the '#if 0' to '#if 1' on the line above the comment reading "Use RTOS features to make XBeeApi threadsafe"

Settings/Status

Import programXBeeApiSimpleATCmdsExample

Simple example of using XBeeApi to send AT-style commands to the XBee

Import programXBeeApiRemoteATCmdsExample

Example of using the XBeeApi library to send AT commands to remote XBee devices in order to read/write settings

Receive

Import programXBeeApiSimpleReceiveExample

Simple example of using XBeeApi to receive data packets via wireless

Import programXBeeApiReceiveCallbackExample

Example of using the XBeeApi library to receive a message via a callback method

Import programXBeeApiReceiveCallbackExampleRTOS

Example of using the XBeeApi library to receive a message via a callback method. This example shows how to use the library when using mbed-rtos. See the comment at the top of main.cpp

Remote I/O

Import programXBeeApiRemoteIOExample

Example of using the XBeeApi library to read inputs on a remote XBee

If you have 2 mbed connected XBees available then you can use XBeeApiSimpleReceiveExample and XBeeApiSimpleBroadcastExample as a pair.

Note that this is still a work in progress! XBeeApiTodoList tracks some of the functionality still to be added.

Committer:
johnb
Date:
Mon Jul 07 19:03:09 2014 +0000
Revision:
48:48397bedf95d
Parent:
43:975a28e01dac
Child:
49:37bba77ee73f
Add checksum verification on the received frames and the ability to turn it on/off.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
johnb 5:b40a6fd3a334 1 /**
johnb 5:b40a6fd3a334 2
johnb 5:b40a6fd3a334 3 Copyright 2014 John Bailey
johnb 5:b40a6fd3a334 4
johnb 5:b40a6fd3a334 5 Licensed under the Apache License, Version 2.0 (the "License");
johnb 5:b40a6fd3a334 6 you may not use this file except in compliance with the License.
johnb 5:b40a6fd3a334 7 You may obtain a copy of the License at
johnb 5:b40a6fd3a334 8
johnb 5:b40a6fd3a334 9 http://www.apache.org/licenses/LICENSE-2.0
johnb 5:b40a6fd3a334 10
johnb 5:b40a6fd3a334 11 Unless required by applicable law or agreed to in writing, software
johnb 5:b40a6fd3a334 12 distributed under the License is distributed on an "AS IS" BASIS,
johnb 5:b40a6fd3a334 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
johnb 5:b40a6fd3a334 14 See the License for the specific language governing permissions and
johnb 5:b40a6fd3a334 15 limitations under the License.
johnb 5:b40a6fd3a334 16
johnb 5:b40a6fd3a334 17 */
johnb 5:b40a6fd3a334 18
johnb 5:b40a6fd3a334 19 #include "XBeeDevice.hpp"
johnb 16:8095c43a2a6e 20 #include "XBeeApiCfg.hpp"
johnb 5:b40a6fd3a334 21
johnb 5:b40a6fd3a334 22 /** Number of bytes we need to 'peek' into the receive buffer in order to retrieve the
johnb 5:b40a6fd3a334 23 payload length */
johnb 5:b40a6fd3a334 24 #define INITIAL_PEEK_LEN (3U)
johnb 5:b40a6fd3a334 25
johnb 5:b40a6fd3a334 26 /** Enum of bytes with a special meaning when communicating with the XBee in API
johnb 5:b40a6fd3a334 27 mode. In escaped mode, these are the bytes that need to be escaped */
johnb 5:b40a6fd3a334 28 typedef enum
johnb 5:b40a6fd3a334 29 {
johnb 5:b40a6fd3a334 30 XBEE_SB_XON = 0x11,
johnb 5:b40a6fd3a334 31 XBEE_SB_XOFF = 0x13,
johnb 5:b40a6fd3a334 32 XBEE_SB_FRAME_DELIMITER = 0x7E,
johnb 5:b40a6fd3a334 33 XBEE_SB_ESCAPE = 0x7D
johnb 5:b40a6fd3a334 34 } XBeeSerialSpecialBytes_e;
johnb 5:b40a6fd3a334 35
johnb 5:b40a6fd3a334 36 /** ASCII command to the XBee to request API mode 2 */
johnb 5:b40a6fd3a334 37 const char api_mode2_cmd[] = { 'A', 'T', 'A', 'P', ' ', '2', '\r' };
johnb 5:b40a6fd3a334 38
johnb 5:b40a6fd3a334 39 /** ASCII command to the XBee to request that it exit command mode */
johnb 5:b40a6fd3a334 40 const char exit_cmd_mode_cmd[] = { 'A', 'T', 'C', 'N', '\r' };
johnb 5:b40a6fd3a334 41
johnb 42:81c789ba4c08 42 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 43 #if defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 44
johnb 42:81c789ba4c08 45 #if XBEEAPI_CONFIG_RTOS_DISPATCHER_LIST_SIZE < 1
johnb 42:81c789ba4c08 46 #error Can't deal with XBEEAPI_CONFIG_RTOS_DISPATCHER_LIST_SIZE being less than 1
johnb 42:81c789ba4c08 47 #endif
johnb 42:81c789ba4c08 48
johnb 42:81c789ba4c08 49 /** List of XBeeDevices that will receive RX dispatches from the XBeeRxDispatch thread */
johnb 42:81c789ba4c08 50 static FixedLengthList<XBeeDevice*, XBEEAPI_CONFIG_RTOS_DISPATCHER_LIST_SIZE> s_XBeeDevices;
johnb 42:81c789ba4c08 51
johnb 42:81c789ba4c08 52 /** Serial data is received in the interrupt context which signals this thread to call
johnb 42:81c789ba4c08 53 the XBeeDevice classes in order to deal with the data */
johnb 42:81c789ba4c08 54 void XBeeRxDispatch(void const *args) {
johnb 42:81c789ba4c08 55 while (true) {
johnb 42:81c789ba4c08 56 // Wait for a signal to that there's data ready to be examined.
johnb 42:81c789ba4c08 57 osSignalWait(0x1, osWaitForever);
johnb 42:81c789ba4c08 58
johnb 42:81c789ba4c08 59 /* Loop all devices - TODO: could make this more efficient and skip devices with no data?
johnb 42:81c789ba4c08 60 TODO: mutex the list to prevent modification while iterating */
johnb 42:81c789ba4c08 61 for( FixedLengthList<XBeeDevice*, XBEEAPI_CONFIG_RTOS_DISPATCHER_LIST_SIZE>::iterator it = s_XBeeDevices.begin();
johnb 42:81c789ba4c08 62 it!= s_XBeeDevices.end();
johnb 42:81c789ba4c08 63 it++ )
johnb 42:81c789ba4c08 64 {
johnb 42:81c789ba4c08 65 (*it)->checkRxDecode();
johnb 42:81c789ba4c08 66 }
johnb 42:81c789ba4c08 67 }
johnb 42:81c789ba4c08 68 }
johnb 42:81c789ba4c08 69
johnb 42:81c789ba4c08 70 osThreadDef(XBeeRxDispatch, osPriorityNormal, XBEEAPI_CONFIG_RTOS_DISPATCHER_TASK_STACK_SIZE);
johnb 42:81c789ba4c08 71 static osThreadId XBeeRxDispatchTID = NULL;
johnb 42:81c789ba4c08 72
johnb 42:81c789ba4c08 73 #endif // defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 74 #endif // defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 75
johnb 33:eccf4725930c 76 void XBeeDevice::init()
johnb 5:b40a6fd3a334 77 {
johnb 33:eccf4725930c 78 m_model = XBeeDevice::XBEEDEVICE_S1;
johnb 5:b40a6fd3a334 79 m_inAtCmdMode = false;
johnb 5:b40a6fd3a334 80 m_rxMsgLastWasEsc = false;
johnb 33:eccf4725930c 81 m_escape = true;
johnb 48:48397bedf95d 82 m_ignoreBadCsum = false;
johnb 48:48397bedf95d 83 m_badCsumCount = 0U;
johnb 48:48397bedf95d 84 m_serialBytesDiscarded = 0U;
johnb 33:eccf4725930c 85 }
johnb 33:eccf4725930c 86
johnb 33:eccf4725930c 87 XBeeDevice::XBeeDevice( PinName p_tx, PinName p_rx, PinName p_rts, PinName p_cts ): m_serialNeedsDelete( true )
johnb 33:eccf4725930c 88 {
johnb 33:eccf4725930c 89 init();
johnb 42:81c789ba4c08 90
johnb 41:07cb97b44e81 91 m_if = new RawSerial( p_tx, p_rx );
johnb 33:eccf4725930c 92
johnb 5:b40a6fd3a334 93 /* Can only do flow control on devices which support it */
johnb 5:b40a6fd3a334 94 #if defined ( DEVICE_SERIAL_FC )
johnb 5:b40a6fd3a334 95 /* TODO: need rts and cts both set? */
johnb 33:eccf4725930c 96 m_if->set_flow_control( mbed::SerialBase::Flow.RTSCTS, p_rts, p_cts );
johnb 5:b40a6fd3a334 97 #endif
johnb 5:b40a6fd3a334 98
johnb 5:b40a6fd3a334 99 /* Attach RX call-back to the serial interface */
johnb 33:eccf4725930c 100 m_if->attach( this, &XBeeDevice::if_rx, Serial::RxIrq);
johnb 33:eccf4725930c 101 }
johnb 33:eccf4725930c 102
johnb 41:07cb97b44e81 103 XBeeDevice::XBeeDevice( RawSerial* p_serialIf ): m_if( p_serialIf ),
johnb 33:eccf4725930c 104 m_serialNeedsDelete( true )
johnb 33:eccf4725930c 105 {
johnb 33:eccf4725930c 106 init();
johnb 5:b40a6fd3a334 107 }
johnb 5:b40a6fd3a334 108
johnb 5:b40a6fd3a334 109 XBeeDevice::~XBeeDevice( void )
johnb 5:b40a6fd3a334 110 {
johnb 5:b40a6fd3a334 111 /* Iterate all of the decoders and un-register them */
johnb 5:b40a6fd3a334 112 for( FixedLengthList<XBeeApiFrameDecoder*, XBEEAPI_CONFIG_DECODER_LIST_SIZE>::iterator it = m_decoders.begin() ;
johnb 5:b40a6fd3a334 113 it != m_decoders.end();
johnb 5:b40a6fd3a334 114 ++it ) {
johnb 5:b40a6fd3a334 115 (*it)->unregisterCallback();
johnb 5:b40a6fd3a334 116 }
johnb 33:eccf4725930c 117 if( m_serialNeedsDelete )
johnb 33:eccf4725930c 118 {
johnb 33:eccf4725930c 119 delete( m_if );
johnb 33:eccf4725930c 120 }
johnb 42:81c789ba4c08 121 #if defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 122 s_XBeeDevices.remove( this );
johnb 42:81c789ba4c08 123 #endif // defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 124
johnb 5:b40a6fd3a334 125 }
johnb 5:b40a6fd3a334 126
johnb 29:c6d037cceb02 127 XBeeDevice::XBeeDeviceModel_t XBeeDevice::getXBeeModel() const
johnb 29:c6d037cceb02 128 {
johnb 29:c6d037cceb02 129 return m_model;
johnb 29:c6d037cceb02 130 }
johnb 29:c6d037cceb02 131
johnb 29:c6d037cceb02 132 void XBeeDevice::setXBeeModel( const XBeeDevice::XBeeDeviceModel_t p_model )
johnb 29:c6d037cceb02 133 {
johnb 29:c6d037cceb02 134 m_model = p_model;
johnb 29:c6d037cceb02 135 }
johnb 29:c6d037cceb02 136
johnb 5:b40a6fd3a334 137 void XBeeDevice::if_rx( void )
johnb 5:b40a6fd3a334 138 {
johnb 5:b40a6fd3a334 139 /* Keep going while there are bytes to be read */
johnb 33:eccf4725930c 140 while(m_if->readable()) {
johnb 5:b40a6fd3a334 141
johnb 33:eccf4725930c 142 uint8_t c = m_if->getc();
johnb 5:b40a6fd3a334 143
johnb 5:b40a6fd3a334 144 /* Sanity check that if we're starting from an empty buffer the byte that we're
johnb 5:b40a6fd3a334 145 receiving is a frame delimiter */
johnb 5:b40a6fd3a334 146 if(( m_inAtCmdMode ) ||
johnb 5:b40a6fd3a334 147 (( c == XBEE_SB_FRAME_DELIMITER ) ||
johnb 5:b40a6fd3a334 148 ( m_rxBuff.getSize() )))
johnb 5:b40a6fd3a334 149 {
johnb 5:b40a6fd3a334 150 /* If it's an escape character we want to de-code the escape, so flag
johnb 5:b40a6fd3a334 151 that we have a pending escape but don't modify the rx buffer */
johnb 5:b40a6fd3a334 152 if( m_escape &&
johnb 5:b40a6fd3a334 153 ( c == XBEE_SB_ESCAPE ))
johnb 5:b40a6fd3a334 154 {
johnb 5:b40a6fd3a334 155 m_rxMsgLastWasEsc = true;
johnb 5:b40a6fd3a334 156 }
johnb 5:b40a6fd3a334 157 else
johnb 5:b40a6fd3a334 158 {
johnb 5:b40a6fd3a334 159 if( m_rxMsgLastWasEsc ) {
johnb 5:b40a6fd3a334 160 c = c ^ 0x20;
johnb 5:b40a6fd3a334 161 m_rxMsgLastWasEsc = false;
johnb 5:b40a6fd3a334 162 }
johnb 5:b40a6fd3a334 163 m_rxBuff.write( &c, 1 );
johnb 5:b40a6fd3a334 164 }
johnb 5:b40a6fd3a334 165 } else {
johnb 5:b40a6fd3a334 166 /* TODO */
johnb 5:b40a6fd3a334 167 }
johnb 5:b40a6fd3a334 168 }
johnb 5:b40a6fd3a334 169
johnb 5:b40a6fd3a334 170 if( m_inAtCmdMode )
johnb 5:b40a6fd3a334 171 {
johnb 7:2f1e157cdd1c 172 /* Safeguard - if we're in cmd mode, clear out status associated with API mode */
johnb 5:b40a6fd3a334 173 m_rxMsgLastWasEsc = false;
johnb 5:b40a6fd3a334 174 }
johnb 7:2f1e157cdd1c 175 else
johnb 7:2f1e157cdd1c 176 {
johnb 42:81c789ba4c08 177 #if defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 178 /* Not going to check for API data here in the interrupt handler - set a signal
johnb 42:81c789ba4c08 179 to the handling thread */
johnb 42:81c789ba4c08 180 osSignalSet(XBeeRxDispatchTID, 0x1);
johnb 42:81c789ba4c08 181 #else
johnb 7:2f1e157cdd1c 182 /* Check to see if there's API data to decode */
johnb 7:2f1e157cdd1c 183 checkRxDecode();
johnb 42:81c789ba4c08 184 #endif
johnb 7:2f1e157cdd1c 185 }
johnb 5:b40a6fd3a334 186 }
johnb 42:81c789ba4c08 187
johnb 5:b40a6fd3a334 188 void XBeeDevice::checkRxDecode( void )
johnb 5:b40a6fd3a334 189 {
johnb 5:b40a6fd3a334 190 uint8_t buff[INITIAL_PEEK_LEN];
johnb 7:2f1e157cdd1c 191 bool cont = false;
johnb 5:b40a6fd3a334 192
johnb 7:2f1e157cdd1c 193 /* Ensure that we're delimiter aligned - this should allow recovery in the case that
johnb 7:2f1e157cdd1c 194 we've missed bytes and somehow become unaligned */
johnb 7:2f1e157cdd1c 195 while( m_rxBuff.getSize() &&
johnb 7:2f1e157cdd1c 196 ( m_rxBuff[0] != XBEE_SB_FRAME_DELIMITER ))
johnb 5:b40a6fd3a334 197 {
johnb 7:2f1e157cdd1c 198 m_rxBuff.chomp( 1 );
johnb 48:48397bedf95d 199 m_serialBytesDiscarded++;
johnb 7:2f1e157cdd1c 200 }
johnb 7:2f1e157cdd1c 201
johnb 7:2f1e157cdd1c 202 do {
johnb 7:2f1e157cdd1c 203 /* Get an initial portion of data from the read buffer so that the message length can be determined */
johnb 7:2f1e157cdd1c 204 uint16_t len = m_rxBuff.peek( buff, INITIAL_PEEK_LEN );
johnb 7:2f1e157cdd1c 205 cont = false;
johnb 42:81c789ba4c08 206
johnb 7:2f1e157cdd1c 207 /* Ensure that sufficient data was received - already know that we should be delimiter aligned based on the above */
johnb 7:2f1e157cdd1c 208 if( len >= INITIAL_PEEK_LEN )
johnb 5:b40a6fd3a334 209 {
johnb 7:2f1e157cdd1c 210 /* Try and get enough data to cover the whole message */
johnb 7:2f1e157cdd1c 211 const uint16_t cmdLen = MSG_LEN_IN_BUFFER( buff ) + XBEE_API_FRAME_OVERHEAD;
johnb 7:2f1e157cdd1c 212 uint8_t cmdBuff[cmdLen];
johnb 7:2f1e157cdd1c 213 uint16_t len = m_rxBuff.peek( cmdBuff, cmdLen );
johnb 7:2f1e157cdd1c 214
johnb 7:2f1e157cdd1c 215 /* Check that we've received the entire frame */
johnb 7:2f1e157cdd1c 216 if( len >= cmdLen )
johnb 7:2f1e157cdd1c 217 {
johnb 48:48397bedf95d 218 bool doProcess = true;
johnb 48:48397bedf95d 219
johnb 48:48397bedf95d 220 /* Checksum verification, performed only if it's configured */
johnb 48:48397bedf95d 221 if( !m_ignoreBadCsum )
johnb 48:48397bedf95d 222 {
johnb 48:48397bedf95d 223 if( !verifyFrameChecksum( cmdBuff, cmdLen ))
johnb 48:48397bedf95d 224 {
johnb 48:48397bedf95d 225 doProcess = false;
johnb 48:48397bedf95d 226 m_badCsumCount++;
johnb 48:48397bedf95d 227 }
johnb 48:48397bedf95d 228 }
johnb 7:2f1e157cdd1c 229
johnb 48:48397bedf95d 230 if( doProcess )
johnb 48:48397bedf95d 231 {
johnb 48:48397bedf95d 232 /* Iterate all of the decoders */
johnb 48:48397bedf95d 233 for( FixedLengthList<XBeeApiFrameDecoder*, XBEEAPI_CONFIG_DECODER_LIST_SIZE>::iterator it = m_decoders.begin() ;
johnb 48:48397bedf95d 234 it != m_decoders.end();
johnb 48:48397bedf95d 235 ++it ) {
johnb 48:48397bedf95d 236
johnb 48:48397bedf95d 237 bool processed = (*it)->decodeCallback( cmdBuff, cmdLen );
johnb 7:2f1e157cdd1c 238
johnb 48:48397bedf95d 239 if( processed )
johnb 48:48397bedf95d 240 {
johnb 48:48397bedf95d 241 break;
johnb 48:48397bedf95d 242 }
johnb 7:2f1e157cdd1c 243 }
johnb 7:2f1e157cdd1c 244 }
johnb 7:2f1e157cdd1c 245 /* Remove the data from the receive buffer - either it was decoded (all well and good)
johnb 7:2f1e157cdd1c 246 or it wasn't, in which case we need to get rid of it to prevent it from jamming
johnb 7:2f1e157cdd1c 247 up the message queue */
johnb 7:2f1e157cdd1c 248 m_rxBuff.chomp( cmdLen );
johnb 5:b40a6fd3a334 249
johnb 7:2f1e157cdd1c 250 /* Successfully decoded 1 message ... there may be more waiting in the buffer! */
johnb 7:2f1e157cdd1c 251 cont = true;
johnb 7:2f1e157cdd1c 252 }
johnb 5:b40a6fd3a334 253 }
johnb 7:2f1e157cdd1c 254 } while( cont );
johnb 5:b40a6fd3a334 255 }
johnb 5:b40a6fd3a334 256
johnb 5:b40a6fd3a334 257 bool XBeeDevice::registerDecoder( XBeeApiFrameDecoder* const p_decoder )
johnb 5:b40a6fd3a334 258 {
johnb 5:b40a6fd3a334 259 bool ret_val = false;
johnb 5:b40a6fd3a334 260 if( p_decoder != NULL )
johnb 5:b40a6fd3a334 261 {
johnb 7:2f1e157cdd1c 262 /* Check if decoder already registered */
johnb 7:2f1e157cdd1c 263 if( !m_decoders.inList( p_decoder ) )
johnb 7:2f1e157cdd1c 264 {
johnb 5:b40a6fd3a334 265 m_decoders.push( p_decoder );
johnb 5:b40a6fd3a334 266 p_decoder->registerCallback( this );
johnb 5:b40a6fd3a334 267 ret_val = true;
johnb 5:b40a6fd3a334 268 }
johnb 5:b40a6fd3a334 269 }
johnb 5:b40a6fd3a334 270 return ret_val;
johnb 5:b40a6fd3a334 271 }
johnb 5:b40a6fd3a334 272
johnb 5:b40a6fd3a334 273 bool XBeeDevice::unregisterDecoder( XBeeApiFrameDecoder* const p_decoder )
johnb 5:b40a6fd3a334 274 {
johnb 5:b40a6fd3a334 275 bool ret_val = false;
johnb 5:b40a6fd3a334 276 if( p_decoder != NULL )
johnb 5:b40a6fd3a334 277 {
johnb 7:2f1e157cdd1c 278 if( m_decoders.remove( p_decoder ) )
johnb 7:2f1e157cdd1c 279 {
johnb 7:2f1e157cdd1c 280 p_decoder->unregisterCallback();
johnb 7:2f1e157cdd1c 281 ret_val = true;
johnb 5:b40a6fd3a334 282 }
johnb 5:b40a6fd3a334 283 }
johnb 5:b40a6fd3a334 284 return ret_val;
johnb 5:b40a6fd3a334 285 }
johnb 5:b40a6fd3a334 286
johnb 16:8095c43a2a6e 287 void XBeeDevice::SendFrame( XBeeApiFrame* const p_cmd )
johnb 5:b40a6fd3a334 288 {
johnb 5:b40a6fd3a334 289 uint8_t sum = 0U;
johnb 5:b40a6fd3a334 290 uint16_t len;
johnb 5:b40a6fd3a334 291 uint16_t i;
johnb 5:b40a6fd3a334 292 const uint8_t* cmdData;
johnb 10:0d084d0253a7 293 uint16_t written = 0;
johnb 5:b40a6fd3a334 294
johnb 5:b40a6fd3a334 295 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 296 // m_ifMutex.lock();
johnb 5:b40a6fd3a334 297 #endif
johnb 5:b40a6fd3a334 298
johnb 5:b40a6fd3a334 299 xbeeWrite( XBEE_SB_FRAME_DELIMITER, false );
johnb 5:b40a6fd3a334 300
johnb 5:b40a6fd3a334 301 len = p_cmd->getCmdLen();
johnb 5:b40a6fd3a334 302 xbeeWrite((uint8_t)(len >> 8U));
johnb 5:b40a6fd3a334 303 xbeeWrite((uint8_t)(len & 0xFF));
johnb 5:b40a6fd3a334 304
johnb 5:b40a6fd3a334 305 sum += xbeeWrite((uint8_t)p_cmd->getApiId());
johnb 10:0d084d0253a7 306 len--;
johnb 5:b40a6fd3a334 307
johnb 10:0d084d0253a7 308 /* While data still to go out */
johnb 10:0d084d0253a7 309 while( written < len )
johnb 5:b40a6fd3a334 310 {
johnb 10:0d084d0253a7 311 uint16_t buffer_len;
johnb 10:0d084d0253a7 312
johnb 10:0d084d0253a7 313 /* Get the next chunk of data from the frame object */
johnb 10:0d084d0253a7 314 p_cmd->getDataPtr( written, &cmdData, &buffer_len );
johnb 10:0d084d0253a7 315
johnb 10:0d084d0253a7 316 /* Write the buffer to the XBee */
johnb 10:0d084d0253a7 317 for( i = 0;
johnb 10:0d084d0253a7 318 i < buffer_len;
johnb 10:0d084d0253a7 319 ++i,++written )
johnb 10:0d084d0253a7 320 {
johnb 10:0d084d0253a7 321 sum += xbeeWrite(cmdData[i]);
johnb 10:0d084d0253a7 322 }
johnb 5:b40a6fd3a334 323 }
johnb 6:3cb62daace78 324
johnb 5:b40a6fd3a334 325 /* Checksum is 0xFF - summation of bytes (excluding delimiter and length) */
johnb 5:b40a6fd3a334 326 xbeeWrite( (uint8_t)0xFFU - sum );
johnb 5:b40a6fd3a334 327
johnb 16:8095c43a2a6e 328 #if defined XBEE_DEBUG_DEVICE_DUMP_MESSAGE_DECODE
johnb 16:8095c43a2a6e 329 m_if.printf("\r\n");
johnb 16:8095c43a2a6e 330 #endif
johnb 5:b40a6fd3a334 331
johnb 5:b40a6fd3a334 332 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 333 // m_ifMutex.unlock();
johnb 5:b40a6fd3a334 334 #endif
johnb 5:b40a6fd3a334 335 }
johnb 5:b40a6fd3a334 336
johnb 5:b40a6fd3a334 337 uint8_t XBeeDevice::xbeeWrite( uint8_t p_byte, bool p_doEscape )
johnb 5:b40a6fd3a334 338 {
johnb 5:b40a6fd3a334 339 uint8_t c_sum = 0;
johnb 5:b40a6fd3a334 340
johnb 5:b40a6fd3a334 341 if (p_doEscape && m_escape &&
johnb 5:b40a6fd3a334 342 ((p_byte == XBEE_SB_FRAME_DELIMITER ) ||
johnb 5:b40a6fd3a334 343 (p_byte == XBEE_SB_ESCAPE ) ||
johnb 5:b40a6fd3a334 344 (p_byte == XBEE_SB_XON ) ||
johnb 5:b40a6fd3a334 345 (p_byte == XBEE_SB_XOFF)))
johnb 5:b40a6fd3a334 346 {
johnb 16:8095c43a2a6e 347 #if defined XBEE_DEBUG_DEVICE_DUMP_MESSAGE_DECODE
johnb 33:eccf4725930c 348 m_if->printf("%02x ",XBEE_SB_ESCAPE);
johnb 33:eccf4725930c 349 m_if->printf("%02x ",p_byte ^ 0x20);
johnb 16:8095c43a2a6e 350 #else
johnb 33:eccf4725930c 351 m_if->putc(XBEE_SB_ESCAPE);
johnb 33:eccf4725930c 352 m_if->putc(p_byte ^ 0x20);
johnb 16:8095c43a2a6e 353 #endif
johnb 5:b40a6fd3a334 354 c_sum += XBEE_SB_ESCAPE;
johnb 5:b40a6fd3a334 355 c_sum += p_byte ^ 0x20;
johnb 5:b40a6fd3a334 356 } else {
johnb 16:8095c43a2a6e 357 #if defined XBEE_DEBUG_DEVICE_DUMP_MESSAGE_DECODE
johnb 33:eccf4725930c 358 m_if->printf("%02x ",p_byte);
johnb 16:8095c43a2a6e 359 #else
johnb 33:eccf4725930c 360 m_if->putc(p_byte);
johnb 16:8095c43a2a6e 361 #endif
johnb 5:b40a6fd3a334 362 c_sum += p_byte;
johnb 5:b40a6fd3a334 363 }
johnb 5:b40a6fd3a334 364 return c_sum;
johnb 5:b40a6fd3a334 365 }
johnb 5:b40a6fd3a334 366
johnb 5:b40a6fd3a334 367 #define IS_OK( _b ) (( _b[ 0 ] == 'O' ) && ( _b[ 1 ] == 'K' ) && ( _b[ 2 ] == '\r' ))
johnb 5:b40a6fd3a334 368 #define OK_LEN (3U)
johnb 5:b40a6fd3a334 369
johnb 5:b40a6fd3a334 370 XBeeDevice::XBeeDeviceReturn_t XBeeDevice::SendFrame( const char* const p_dat, size_t p_len, int p_wait_ms )
johnb 5:b40a6fd3a334 371 {
johnb 5:b40a6fd3a334 372 XBeeDeviceReturn_t ret_val;
johnb 5:b40a6fd3a334 373
johnb 5:b40a6fd3a334 374 if( m_inAtCmdMode )
johnb 5:b40a6fd3a334 375 {
johnb 5:b40a6fd3a334 376 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 377 // m_ifMutex.lock();
johnb 5:b40a6fd3a334 378 #endif
johnb 5:b40a6fd3a334 379 for( size_t i = 0;
johnb 5:b40a6fd3a334 380 i < p_len;
johnb 5:b40a6fd3a334 381 i++ ) {
johnb 33:eccf4725930c 382 m_if->putc(p_dat[i]);
johnb 5:b40a6fd3a334 383 }
johnb 5:b40a6fd3a334 384
johnb 5:b40a6fd3a334 385 wait_ms( p_wait_ms );
johnb 5:b40a6fd3a334 386
johnb 5:b40a6fd3a334 387 /* Check the response for the OK indicator */
johnb 5:b40a6fd3a334 388 if( m_rxBuff.getSize() == OK_LEN )
johnb 5:b40a6fd3a334 389 {
johnb 5:b40a6fd3a334 390 uint8_t ok_buff[OK_LEN];
johnb 5:b40a6fd3a334 391 m_rxBuff.read( ok_buff, OK_LEN );
johnb 5:b40a6fd3a334 392
johnb 5:b40a6fd3a334 393 if( IS_OK( ok_buff ))
johnb 5:b40a6fd3a334 394 {
johnb 5:b40a6fd3a334 395 ret_val = XBEEDEVICE_OK;
johnb 5:b40a6fd3a334 396 }
johnb 5:b40a6fd3a334 397 else
johnb 5:b40a6fd3a334 398 {
johnb 5:b40a6fd3a334 399 ret_val = XBEEDEVICE_UNEXPECTED_DATA;
johnb 5:b40a6fd3a334 400 }
johnb 5:b40a6fd3a334 401 }
johnb 5:b40a6fd3a334 402 else
johnb 5:b40a6fd3a334 403 {
johnb 5:b40a6fd3a334 404 ret_val = XBEEDEVICE_UNEXPECTED_LENGTH;
johnb 5:b40a6fd3a334 405 }
johnb 5:b40a6fd3a334 406 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 407 // m_ifMutex.unlock();
johnb 5:b40a6fd3a334 408 #endif
johnb 5:b40a6fd3a334 409 }
johnb 5:b40a6fd3a334 410 else
johnb 5:b40a6fd3a334 411 {
johnb 5:b40a6fd3a334 412 ret_val = XBEEDEVICE_WRONG_MODE;
johnb 5:b40a6fd3a334 413 }
johnb 5:b40a6fd3a334 414 return ret_val;
johnb 5:b40a6fd3a334 415 }
johnb 5:b40a6fd3a334 416
johnb 5:b40a6fd3a334 417 XBeeDevice::XBeeDeviceReturn_t XBeeDevice::setUpApi( void )
johnb 5:b40a6fd3a334 418 {
johnb 5:b40a6fd3a334 419 XBeeDeviceReturn_t ret_val;
johnb 5:b40a6fd3a334 420
johnb 5:b40a6fd3a334 421 /* Wait for the guard period before transmitting command sequence */
johnb 5:b40a6fd3a334 422 wait_ms( XBEEAPI_CONFIG_GUARDPERIOD_MS );
johnb 5:b40a6fd3a334 423
johnb 5:b40a6fd3a334 424 m_inAtCmdMode = true;
johnb 5:b40a6fd3a334 425
johnb 5:b40a6fd3a334 426 /* Request to enter command mode */
johnb 5:b40a6fd3a334 427 /* TODO: Magic number */
johnb 5:b40a6fd3a334 428 ret_val = SendFrame("+++", 3, 3000);
johnb 5:b40a6fd3a334 429
johnb 5:b40a6fd3a334 430 /* Everything OK with last request? */
johnb 5:b40a6fd3a334 431 if( ret_val == XBEEDEVICE_OK )
johnb 5:b40a6fd3a334 432 {
johnb 5:b40a6fd3a334 433 wait_ms( XBEEAPI_CONFIG_GUARDPERIOD_MS );
johnb 5:b40a6fd3a334 434
johnb 5:b40a6fd3a334 435 /* API mode 2 please! */
johnb 5:b40a6fd3a334 436 ret_val = SendFrame(api_mode2_cmd,sizeof(api_mode2_cmd));
johnb 5:b40a6fd3a334 437 }
johnb 5:b40a6fd3a334 438
johnb 5:b40a6fd3a334 439 /* Everything OK with last request? */
johnb 5:b40a6fd3a334 440 if( ret_val == XBEEDEVICE_OK )
johnb 5:b40a6fd3a334 441 {
johnb 5:b40a6fd3a334 442 /* Exit command mode, back to API mode */
johnb 5:b40a6fd3a334 443 ret_val = SendFrame(exit_cmd_mode_cmd,sizeof(exit_cmd_mode_cmd));
johnb 5:b40a6fd3a334 444 }
johnb 5:b40a6fd3a334 445
johnb 5:b40a6fd3a334 446 m_inAtCmdMode = false;
johnb 5:b40a6fd3a334 447
johnb 5:b40a6fd3a334 448 return ret_val;
johnb 5:b40a6fd3a334 449 }
johnb 5:b40a6fd3a334 450
johnb 48:48397bedf95d 451 void XBeeDevice::setIgnoreBadChecksum( const bool p_shouldIgnore )
johnb 48:48397bedf95d 452 {
johnb 48:48397bedf95d 453 m_ignoreBadCsum = p_shouldIgnore;
johnb 48:48397bedf95d 454 }
johnb 48:48397bedf95d 455
johnb 48:48397bedf95d 456 uint16_t XBeeDevice::getBadChecksumCount( void ) const
johnb 48:48397bedf95d 457 {
johnb 48:48397bedf95d 458 return m_badCsumCount;
johnb 48:48397bedf95d 459 }
johnb 48:48397bedf95d 460
johnb 48:48397bedf95d 461 uint16_t XBeeDevice::getSerialBytesDiscardedCount( void ) const
johnb 48:48397bedf95d 462 {
johnb 48:48397bedf95d 463 return m_serialBytesDiscarded;
johnb 48:48397bedf95d 464 }
johnb 48:48397bedf95d 465
johnb 48:48397bedf95d 466 bool XBeeDevice::verifyFrameChecksum( const uint8_t* const p_data, size_t p_len )
johnb 48:48397bedf95d 467 {
johnb 48:48397bedf95d 468 /* TODO: Could try and be "smarter" and build the checksum as the frame is RX'd */
johnb 48:48397bedf95d 469
johnb 48:48397bedf95d 470 /* Don't include bytes that aren't checksummed */
johnb 48:48397bedf95d 471 size_t ctr = p_len - XBEE_API_FRAME_OVERHEAD;
johnb 48:48397bedf95d 472 /* Skip over the start delimiter and length (not included in checksum) */
johnb 48:48397bedf95d 473 const uint8_t* dat = p_data + XBEE_API_FRAME_OVERHEAD_START;
johnb 48:48397bedf95d 474
johnb 48:48397bedf95d 475 uint8_t sum = 0;
johnb 48:48397bedf95d 476
johnb 48:48397bedf95d 477 do
johnb 48:48397bedf95d 478 {
johnb 48:48397bedf95d 479 sum += *dat;
johnb 48:48397bedf95d 480 dat++;
johnb 48:48397bedf95d 481 ctr--;
johnb 48:48397bedf95d 482 } while( ctr > 0 );
johnb 48:48397bedf95d 483
johnb 48:48397bedf95d 484 sum = 0xFFU - sum;
johnb 48:48397bedf95d 485
johnb 48:48397bedf95d 486 return( sum == (*dat));
johnb 48:48397bedf95d 487 }
johnb 48:48397bedf95d 488
johnb 48:48397bedf95d 489
johnb 42:81c789ba4c08 490 #if defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 491 bool XBeeDevice::setupDispatchTask( void )
johnb 42:81c789ba4c08 492 {
johnb 42:81c789ba4c08 493 bool ret_val = false;
johnb 42:81c789ba4c08 494
johnb 42:81c789ba4c08 495 /* Ensure the dispatch thread exists */
johnb 42:81c789ba4c08 496 if( XBeeRxDispatchTID == NULL )
johnb 42:81c789ba4c08 497 {
johnb 42:81c789ba4c08 498 XBeeRxDispatchTID = osThreadCreate(osThread(XBeeRxDispatch), NULL);
johnb 42:81c789ba4c08 499 }
johnb 42:81c789ba4c08 500
johnb 42:81c789ba4c08 501 /* Register this device in the list that need dispatch */
johnb 43:975a28e01dac 502 if( s_XBeeDevices.push( this ) )
johnb 42:81c789ba4c08 503 {
johnb 42:81c789ba4c08 504 ret_val = true;
johnb 42:81c789ba4c08 505 }
johnb 42:81c789ba4c08 506
johnb 42:81c789ba4c08 507 return ret_val;
johnb 42:81c789ba4c08 508 }
johnb 42:81c789ba4c08 509 #endif // defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 510
johnb 5:b40a6fd3a334 511 #if defined XBEEAPI_CONFIG_ENABLE_DEVELOPER
johnb 5:b40a6fd3a334 512
johnb 5:b40a6fd3a334 513 #define PRINTABLE_ASCII_FIRST 32U
johnb 5:b40a6fd3a334 514 #define PRINTABLE_ASCII_LAST 126U
johnb 5:b40a6fd3a334 515
johnb 5:b40a6fd3a334 516 void XBeeDevice::dumpRxBuffer( Stream* p_buf, const bool p_hexView )
johnb 5:b40a6fd3a334 517 {
johnb 5:b40a6fd3a334 518 uint8_t c;
johnb 5:b40a6fd3a334 519 while( m_rxBuff.getSize() ) {
johnb 5:b40a6fd3a334 520 if( m_rxBuff.read( &c, 1 ) ) {
johnb 5:b40a6fd3a334 521 if( p_hexView ) {
johnb 5:b40a6fd3a334 522 uint8_t a = '-';
johnb 5:b40a6fd3a334 523 if(( c>=PRINTABLE_ASCII_FIRST ) && (c<=PRINTABLE_ASCII_LAST)) {
johnb 5:b40a6fd3a334 524 a = c;
johnb 5:b40a6fd3a334 525 }
johnb 5:b40a6fd3a334 526 p_buf->printf("0x%02x (%c) ",c,a);
johnb 5:b40a6fd3a334 527 } else {
johnb 5:b40a6fd3a334 528 p_buf->printf("%c",c);
johnb 5:b40a6fd3a334 529 if( c == '\r' ) {
johnb 5:b40a6fd3a334 530 p_buf->printf("\n");
johnb 5:b40a6fd3a334 531 }
johnb 5:b40a6fd3a334 532 }
johnb 5:b40a6fd3a334 533 }
johnb 5:b40a6fd3a334 534 }
johnb 5:b40a6fd3a334 535 }
johnb 5:b40a6fd3a334 536
johnb 5:b40a6fd3a334 537 #endif