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:
Fri Aug 08 11:59:52 2014 +0000
Revision:
56:7fe74b03e6b1
Parent:
51:a7d0d2ef9261
Add support for setting up encrypted communications; Re-jig XBeeApiCmdAt virtual functions to make inheritance by XBeeDeviceRemoteAt cleaner.

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