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:
Sun Jul 06 20:17:19 2014 +0000
Revision:
43:975a28e01dac
Parent:
42:81c789ba4c08
Child:
48:48397bedf95d
Update logic of return for setupDispatchTask() to be in line with other methods

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 33:eccf4725930c 82 }
johnb 33:eccf4725930c 83
johnb 33:eccf4725930c 84 XBeeDevice::XBeeDevice( PinName p_tx, PinName p_rx, PinName p_rts, PinName p_cts ): m_serialNeedsDelete( true )
johnb 33:eccf4725930c 85 {
johnb 33:eccf4725930c 86 init();
johnb 42:81c789ba4c08 87
johnb 41:07cb97b44e81 88 m_if = new RawSerial( p_tx, p_rx );
johnb 33:eccf4725930c 89
johnb 5:b40a6fd3a334 90 /* Can only do flow control on devices which support it */
johnb 5:b40a6fd3a334 91 #if defined ( DEVICE_SERIAL_FC )
johnb 5:b40a6fd3a334 92 /* TODO: need rts and cts both set? */
johnb 33:eccf4725930c 93 m_if->set_flow_control( mbed::SerialBase::Flow.RTSCTS, p_rts, p_cts );
johnb 5:b40a6fd3a334 94 #endif
johnb 5:b40a6fd3a334 95
johnb 5:b40a6fd3a334 96 /* Attach RX call-back to the serial interface */
johnb 33:eccf4725930c 97 m_if->attach( this, &XBeeDevice::if_rx, Serial::RxIrq);
johnb 33:eccf4725930c 98 }
johnb 33:eccf4725930c 99
johnb 41:07cb97b44e81 100 XBeeDevice::XBeeDevice( RawSerial* p_serialIf ): m_if( p_serialIf ),
johnb 33:eccf4725930c 101 m_serialNeedsDelete( true )
johnb 33:eccf4725930c 102 {
johnb 33:eccf4725930c 103 init();
johnb 5:b40a6fd3a334 104 }
johnb 5:b40a6fd3a334 105
johnb 5:b40a6fd3a334 106 XBeeDevice::~XBeeDevice( void )
johnb 5:b40a6fd3a334 107 {
johnb 5:b40a6fd3a334 108 /* Iterate all of the decoders and un-register them */
johnb 5:b40a6fd3a334 109 for( FixedLengthList<XBeeApiFrameDecoder*, XBEEAPI_CONFIG_DECODER_LIST_SIZE>::iterator it = m_decoders.begin() ;
johnb 5:b40a6fd3a334 110 it != m_decoders.end();
johnb 5:b40a6fd3a334 111 ++it ) {
johnb 5:b40a6fd3a334 112 (*it)->unregisterCallback();
johnb 5:b40a6fd3a334 113 }
johnb 33:eccf4725930c 114 if( m_serialNeedsDelete )
johnb 33:eccf4725930c 115 {
johnb 33:eccf4725930c 116 delete( m_if );
johnb 33:eccf4725930c 117 }
johnb 42:81c789ba4c08 118 #if defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 119 s_XBeeDevices.remove( this );
johnb 42:81c789ba4c08 120 #endif // defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 121
johnb 5:b40a6fd3a334 122 }
johnb 5:b40a6fd3a334 123
johnb 29:c6d037cceb02 124 XBeeDevice::XBeeDeviceModel_t XBeeDevice::getXBeeModel() const
johnb 29:c6d037cceb02 125 {
johnb 29:c6d037cceb02 126 return m_model;
johnb 29:c6d037cceb02 127 }
johnb 29:c6d037cceb02 128
johnb 29:c6d037cceb02 129 void XBeeDevice::setXBeeModel( const XBeeDevice::XBeeDeviceModel_t p_model )
johnb 29:c6d037cceb02 130 {
johnb 29:c6d037cceb02 131 m_model = p_model;
johnb 29:c6d037cceb02 132 }
johnb 29:c6d037cceb02 133
johnb 5:b40a6fd3a334 134 void XBeeDevice::if_rx( void )
johnb 5:b40a6fd3a334 135 {
johnb 5:b40a6fd3a334 136 /* Keep going while there are bytes to be read */
johnb 33:eccf4725930c 137 while(m_if->readable()) {
johnb 5:b40a6fd3a334 138
johnb 33:eccf4725930c 139 uint8_t c = m_if->getc();
johnb 5:b40a6fd3a334 140
johnb 5:b40a6fd3a334 141 /* Sanity check that if we're starting from an empty buffer the byte that we're
johnb 5:b40a6fd3a334 142 receiving is a frame delimiter */
johnb 5:b40a6fd3a334 143 if(( m_inAtCmdMode ) ||
johnb 5:b40a6fd3a334 144 (( c == XBEE_SB_FRAME_DELIMITER ) ||
johnb 5:b40a6fd3a334 145 ( m_rxBuff.getSize() )))
johnb 5:b40a6fd3a334 146 {
johnb 5:b40a6fd3a334 147 /* If it's an escape character we want to de-code the escape, so flag
johnb 5:b40a6fd3a334 148 that we have a pending escape but don't modify the rx buffer */
johnb 5:b40a6fd3a334 149 if( m_escape &&
johnb 5:b40a6fd3a334 150 ( c == XBEE_SB_ESCAPE ))
johnb 5:b40a6fd3a334 151 {
johnb 5:b40a6fd3a334 152 m_rxMsgLastWasEsc = true;
johnb 5:b40a6fd3a334 153 }
johnb 5:b40a6fd3a334 154 else
johnb 5:b40a6fd3a334 155 {
johnb 5:b40a6fd3a334 156 if( m_rxMsgLastWasEsc ) {
johnb 5:b40a6fd3a334 157 c = c ^ 0x20;
johnb 5:b40a6fd3a334 158 m_rxMsgLastWasEsc = false;
johnb 5:b40a6fd3a334 159 }
johnb 5:b40a6fd3a334 160 m_rxBuff.write( &c, 1 );
johnb 5:b40a6fd3a334 161 }
johnb 5:b40a6fd3a334 162 } else {
johnb 5:b40a6fd3a334 163 /* TODO */
johnb 5:b40a6fd3a334 164 }
johnb 5:b40a6fd3a334 165 }
johnb 5:b40a6fd3a334 166
johnb 5:b40a6fd3a334 167 if( m_inAtCmdMode )
johnb 5:b40a6fd3a334 168 {
johnb 7:2f1e157cdd1c 169 /* Safeguard - if we're in cmd mode, clear out status associated with API mode */
johnb 5:b40a6fd3a334 170 m_rxMsgLastWasEsc = false;
johnb 5:b40a6fd3a334 171 }
johnb 7:2f1e157cdd1c 172 else
johnb 7:2f1e157cdd1c 173 {
johnb 42:81c789ba4c08 174 #if defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 175 /* Not going to check for API data here in the interrupt handler - set a signal
johnb 42:81c789ba4c08 176 to the handling thread */
johnb 42:81c789ba4c08 177 osSignalSet(XBeeRxDispatchTID, 0x1);
johnb 42:81c789ba4c08 178 #else
johnb 7:2f1e157cdd1c 179 /* Check to see if there's API data to decode */
johnb 7:2f1e157cdd1c 180 checkRxDecode();
johnb 42:81c789ba4c08 181 #endif
johnb 7:2f1e157cdd1c 182 }
johnb 5:b40a6fd3a334 183 }
johnb 42:81c789ba4c08 184
johnb 5:b40a6fd3a334 185 void XBeeDevice::checkRxDecode( void )
johnb 5:b40a6fd3a334 186 {
johnb 5:b40a6fd3a334 187 uint8_t buff[INITIAL_PEEK_LEN];
johnb 7:2f1e157cdd1c 188 bool cont = false;
johnb 5:b40a6fd3a334 189
johnb 7:2f1e157cdd1c 190 /* Ensure that we're delimiter aligned - this should allow recovery in the case that
johnb 7:2f1e157cdd1c 191 we've missed bytes and somehow become unaligned */
johnb 7:2f1e157cdd1c 192 while( m_rxBuff.getSize() &&
johnb 7:2f1e157cdd1c 193 ( m_rxBuff[0] != XBEE_SB_FRAME_DELIMITER ))
johnb 5:b40a6fd3a334 194 {
johnb 7:2f1e157cdd1c 195 m_rxBuff.chomp( 1 );
johnb 7:2f1e157cdd1c 196 }
johnb 7:2f1e157cdd1c 197
johnb 7:2f1e157cdd1c 198 do {
johnb 7:2f1e157cdd1c 199 /* Get an initial portion of data from the read buffer so that the message length can be determined */
johnb 7:2f1e157cdd1c 200 uint16_t len = m_rxBuff.peek( buff, INITIAL_PEEK_LEN );
johnb 7:2f1e157cdd1c 201 cont = false;
johnb 42:81c789ba4c08 202
johnb 7:2f1e157cdd1c 203 /* Ensure that sufficient data was received - already know that we should be delimiter aligned based on the above */
johnb 7:2f1e157cdd1c 204 if( len >= INITIAL_PEEK_LEN )
johnb 5:b40a6fd3a334 205 {
johnb 7:2f1e157cdd1c 206 /* Try and get enough data to cover the whole message */
johnb 7:2f1e157cdd1c 207 const uint16_t cmdLen = MSG_LEN_IN_BUFFER( buff ) + XBEE_API_FRAME_OVERHEAD;
johnb 7:2f1e157cdd1c 208 uint8_t cmdBuff[cmdLen];
johnb 7:2f1e157cdd1c 209 uint16_t len = m_rxBuff.peek( cmdBuff, cmdLen );
johnb 7:2f1e157cdd1c 210
johnb 7:2f1e157cdd1c 211 /* Check that we've received the entire frame */
johnb 7:2f1e157cdd1c 212 if( len >= cmdLen )
johnb 7:2f1e157cdd1c 213 {
johnb 7:2f1e157cdd1c 214 /* TODO: Verify checksum */
johnb 7:2f1e157cdd1c 215
johnb 7:2f1e157cdd1c 216 /* Iterate all of the decoders */
johnb 7:2f1e157cdd1c 217 for( FixedLengthList<XBeeApiFrameDecoder*, XBEEAPI_CONFIG_DECODER_LIST_SIZE>::iterator it = m_decoders.begin() ;
johnb 7:2f1e157cdd1c 218 it != m_decoders.end();
johnb 7:2f1e157cdd1c 219 ++it ) {
johnb 7:2f1e157cdd1c 220
johnb 7:2f1e157cdd1c 221 bool processed = (*it)->decodeCallback( cmdBuff, cmdLen );
johnb 42:81c789ba4c08 222
johnb 7:2f1e157cdd1c 223 if( processed )
johnb 7:2f1e157cdd1c 224 {
johnb 7:2f1e157cdd1c 225 break;
johnb 7:2f1e157cdd1c 226 }
johnb 7:2f1e157cdd1c 227 }
johnb 7:2f1e157cdd1c 228 /* Remove the data from the receive buffer - either it was decoded (all well and good)
johnb 7:2f1e157cdd1c 229 or it wasn't, in which case we need to get rid of it to prevent it from jamming
johnb 7:2f1e157cdd1c 230 up the message queue */
johnb 7:2f1e157cdd1c 231 m_rxBuff.chomp( cmdLen );
johnb 5:b40a6fd3a334 232
johnb 7:2f1e157cdd1c 233 /* Successfully decoded 1 message ... there may be more waiting in the buffer! */
johnb 7:2f1e157cdd1c 234 cont = true;
johnb 7:2f1e157cdd1c 235 }
johnb 5:b40a6fd3a334 236 }
johnb 7:2f1e157cdd1c 237 } while( cont );
johnb 5:b40a6fd3a334 238 }
johnb 5:b40a6fd3a334 239
johnb 5:b40a6fd3a334 240 bool XBeeDevice::registerDecoder( XBeeApiFrameDecoder* const p_decoder )
johnb 5:b40a6fd3a334 241 {
johnb 5:b40a6fd3a334 242 bool ret_val = false;
johnb 5:b40a6fd3a334 243 if( p_decoder != NULL )
johnb 5:b40a6fd3a334 244 {
johnb 7:2f1e157cdd1c 245 /* Check if decoder already registered */
johnb 7:2f1e157cdd1c 246 if( !m_decoders.inList( p_decoder ) )
johnb 7:2f1e157cdd1c 247 {
johnb 5:b40a6fd3a334 248 m_decoders.push( p_decoder );
johnb 5:b40a6fd3a334 249 p_decoder->registerCallback( this );
johnb 5:b40a6fd3a334 250 ret_val = true;
johnb 5:b40a6fd3a334 251 }
johnb 5:b40a6fd3a334 252 }
johnb 5:b40a6fd3a334 253 return ret_val;
johnb 5:b40a6fd3a334 254 }
johnb 5:b40a6fd3a334 255
johnb 5:b40a6fd3a334 256 bool XBeeDevice::unregisterDecoder( XBeeApiFrameDecoder* const p_decoder )
johnb 5:b40a6fd3a334 257 {
johnb 5:b40a6fd3a334 258 bool ret_val = false;
johnb 5:b40a6fd3a334 259 if( p_decoder != NULL )
johnb 5:b40a6fd3a334 260 {
johnb 7:2f1e157cdd1c 261 if( m_decoders.remove( p_decoder ) )
johnb 7:2f1e157cdd1c 262 {
johnb 7:2f1e157cdd1c 263 p_decoder->unregisterCallback();
johnb 7:2f1e157cdd1c 264 ret_val = true;
johnb 5:b40a6fd3a334 265 }
johnb 5:b40a6fd3a334 266 }
johnb 5:b40a6fd3a334 267 return ret_val;
johnb 5:b40a6fd3a334 268 }
johnb 5:b40a6fd3a334 269
johnb 16:8095c43a2a6e 270 void XBeeDevice::SendFrame( XBeeApiFrame* const p_cmd )
johnb 5:b40a6fd3a334 271 {
johnb 5:b40a6fd3a334 272 uint8_t sum = 0U;
johnb 5:b40a6fd3a334 273 uint16_t len;
johnb 5:b40a6fd3a334 274 uint16_t i;
johnb 5:b40a6fd3a334 275 const uint8_t* cmdData;
johnb 10:0d084d0253a7 276 uint16_t written = 0;
johnb 5:b40a6fd3a334 277
johnb 5:b40a6fd3a334 278 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 279 // m_ifMutex.lock();
johnb 5:b40a6fd3a334 280 #endif
johnb 5:b40a6fd3a334 281
johnb 5:b40a6fd3a334 282 xbeeWrite( XBEE_SB_FRAME_DELIMITER, false );
johnb 5:b40a6fd3a334 283
johnb 5:b40a6fd3a334 284 len = p_cmd->getCmdLen();
johnb 5:b40a6fd3a334 285 xbeeWrite((uint8_t)(len >> 8U));
johnb 5:b40a6fd3a334 286 xbeeWrite((uint8_t)(len & 0xFF));
johnb 5:b40a6fd3a334 287
johnb 5:b40a6fd3a334 288 sum += xbeeWrite((uint8_t)p_cmd->getApiId());
johnb 10:0d084d0253a7 289 len--;
johnb 5:b40a6fd3a334 290
johnb 10:0d084d0253a7 291 /* While data still to go out */
johnb 10:0d084d0253a7 292 while( written < len )
johnb 5:b40a6fd3a334 293 {
johnb 10:0d084d0253a7 294 uint16_t buffer_len;
johnb 10:0d084d0253a7 295
johnb 10:0d084d0253a7 296 /* Get the next chunk of data from the frame object */
johnb 10:0d084d0253a7 297 p_cmd->getDataPtr( written, &cmdData, &buffer_len );
johnb 10:0d084d0253a7 298
johnb 10:0d084d0253a7 299 /* Write the buffer to the XBee */
johnb 10:0d084d0253a7 300 for( i = 0;
johnb 10:0d084d0253a7 301 i < buffer_len;
johnb 10:0d084d0253a7 302 ++i,++written )
johnb 10:0d084d0253a7 303 {
johnb 10:0d084d0253a7 304 sum += xbeeWrite(cmdData[i]);
johnb 10:0d084d0253a7 305 }
johnb 5:b40a6fd3a334 306 }
johnb 6:3cb62daace78 307
johnb 5:b40a6fd3a334 308 /* Checksum is 0xFF - summation of bytes (excluding delimiter and length) */
johnb 5:b40a6fd3a334 309 xbeeWrite( (uint8_t)0xFFU - sum );
johnb 5:b40a6fd3a334 310
johnb 16:8095c43a2a6e 311 #if defined XBEE_DEBUG_DEVICE_DUMP_MESSAGE_DECODE
johnb 16:8095c43a2a6e 312 m_if.printf("\r\n");
johnb 16:8095c43a2a6e 313 #endif
johnb 5:b40a6fd3a334 314
johnb 5:b40a6fd3a334 315 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 316 // m_ifMutex.unlock();
johnb 5:b40a6fd3a334 317 #endif
johnb 5:b40a6fd3a334 318 }
johnb 5:b40a6fd3a334 319
johnb 5:b40a6fd3a334 320 uint8_t XBeeDevice::xbeeWrite( uint8_t p_byte, bool p_doEscape )
johnb 5:b40a6fd3a334 321 {
johnb 5:b40a6fd3a334 322 uint8_t c_sum = 0;
johnb 5:b40a6fd3a334 323
johnb 5:b40a6fd3a334 324 if (p_doEscape && m_escape &&
johnb 5:b40a6fd3a334 325 ((p_byte == XBEE_SB_FRAME_DELIMITER ) ||
johnb 5:b40a6fd3a334 326 (p_byte == XBEE_SB_ESCAPE ) ||
johnb 5:b40a6fd3a334 327 (p_byte == XBEE_SB_XON ) ||
johnb 5:b40a6fd3a334 328 (p_byte == XBEE_SB_XOFF)))
johnb 5:b40a6fd3a334 329 {
johnb 16:8095c43a2a6e 330 #if defined XBEE_DEBUG_DEVICE_DUMP_MESSAGE_DECODE
johnb 33:eccf4725930c 331 m_if->printf("%02x ",XBEE_SB_ESCAPE);
johnb 33:eccf4725930c 332 m_if->printf("%02x ",p_byte ^ 0x20);
johnb 16:8095c43a2a6e 333 #else
johnb 33:eccf4725930c 334 m_if->putc(XBEE_SB_ESCAPE);
johnb 33:eccf4725930c 335 m_if->putc(p_byte ^ 0x20);
johnb 16:8095c43a2a6e 336 #endif
johnb 5:b40a6fd3a334 337 c_sum += XBEE_SB_ESCAPE;
johnb 5:b40a6fd3a334 338 c_sum += p_byte ^ 0x20;
johnb 5:b40a6fd3a334 339 } else {
johnb 16:8095c43a2a6e 340 #if defined XBEE_DEBUG_DEVICE_DUMP_MESSAGE_DECODE
johnb 33:eccf4725930c 341 m_if->printf("%02x ",p_byte);
johnb 16:8095c43a2a6e 342 #else
johnb 33:eccf4725930c 343 m_if->putc(p_byte);
johnb 16:8095c43a2a6e 344 #endif
johnb 5:b40a6fd3a334 345 c_sum += p_byte;
johnb 5:b40a6fd3a334 346 }
johnb 5:b40a6fd3a334 347 return c_sum;
johnb 5:b40a6fd3a334 348 }
johnb 5:b40a6fd3a334 349
johnb 5:b40a6fd3a334 350 #define IS_OK( _b ) (( _b[ 0 ] == 'O' ) && ( _b[ 1 ] == 'K' ) && ( _b[ 2 ] == '\r' ))
johnb 5:b40a6fd3a334 351 #define OK_LEN (3U)
johnb 5:b40a6fd3a334 352
johnb 5:b40a6fd3a334 353 XBeeDevice::XBeeDeviceReturn_t XBeeDevice::SendFrame( const char* const p_dat, size_t p_len, int p_wait_ms )
johnb 5:b40a6fd3a334 354 {
johnb 5:b40a6fd3a334 355 XBeeDeviceReturn_t ret_val;
johnb 5:b40a6fd3a334 356
johnb 5:b40a6fd3a334 357 if( m_inAtCmdMode )
johnb 5:b40a6fd3a334 358 {
johnb 5:b40a6fd3a334 359 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 360 // m_ifMutex.lock();
johnb 5:b40a6fd3a334 361 #endif
johnb 5:b40a6fd3a334 362 for( size_t i = 0;
johnb 5:b40a6fd3a334 363 i < p_len;
johnb 5:b40a6fd3a334 364 i++ ) {
johnb 33:eccf4725930c 365 m_if->putc(p_dat[i]);
johnb 5:b40a6fd3a334 366 }
johnb 5:b40a6fd3a334 367
johnb 5:b40a6fd3a334 368 wait_ms( p_wait_ms );
johnb 5:b40a6fd3a334 369
johnb 5:b40a6fd3a334 370 /* Check the response for the OK indicator */
johnb 5:b40a6fd3a334 371 if( m_rxBuff.getSize() == OK_LEN )
johnb 5:b40a6fd3a334 372 {
johnb 5:b40a6fd3a334 373 uint8_t ok_buff[OK_LEN];
johnb 5:b40a6fd3a334 374 m_rxBuff.read( ok_buff, OK_LEN );
johnb 5:b40a6fd3a334 375
johnb 5:b40a6fd3a334 376 if( IS_OK( ok_buff ))
johnb 5:b40a6fd3a334 377 {
johnb 5:b40a6fd3a334 378 ret_val = XBEEDEVICE_OK;
johnb 5:b40a6fd3a334 379 }
johnb 5:b40a6fd3a334 380 else
johnb 5:b40a6fd3a334 381 {
johnb 5:b40a6fd3a334 382 ret_val = XBEEDEVICE_UNEXPECTED_DATA;
johnb 5:b40a6fd3a334 383 }
johnb 5:b40a6fd3a334 384 }
johnb 5:b40a6fd3a334 385 else
johnb 5:b40a6fd3a334 386 {
johnb 5:b40a6fd3a334 387 ret_val = XBEEDEVICE_UNEXPECTED_LENGTH;
johnb 5:b40a6fd3a334 388 }
johnb 5:b40a6fd3a334 389 #if defined XBEEAPI_CONFIG_USING_RTOS
johnb 42:81c789ba4c08 390 // m_ifMutex.unlock();
johnb 5:b40a6fd3a334 391 #endif
johnb 5:b40a6fd3a334 392 }
johnb 5:b40a6fd3a334 393 else
johnb 5:b40a6fd3a334 394 {
johnb 5:b40a6fd3a334 395 ret_val = XBEEDEVICE_WRONG_MODE;
johnb 5:b40a6fd3a334 396 }
johnb 5:b40a6fd3a334 397 return ret_val;
johnb 5:b40a6fd3a334 398 }
johnb 5:b40a6fd3a334 399
johnb 5:b40a6fd3a334 400 XBeeDevice::XBeeDeviceReturn_t XBeeDevice::setUpApi( void )
johnb 5:b40a6fd3a334 401 {
johnb 5:b40a6fd3a334 402 XBeeDeviceReturn_t ret_val;
johnb 5:b40a6fd3a334 403
johnb 5:b40a6fd3a334 404 /* Wait for the guard period before transmitting command sequence */
johnb 5:b40a6fd3a334 405 wait_ms( XBEEAPI_CONFIG_GUARDPERIOD_MS );
johnb 5:b40a6fd3a334 406
johnb 5:b40a6fd3a334 407 m_inAtCmdMode = true;
johnb 5:b40a6fd3a334 408
johnb 5:b40a6fd3a334 409 /* Request to enter command mode */
johnb 5:b40a6fd3a334 410 /* TODO: Magic number */
johnb 5:b40a6fd3a334 411 ret_val = SendFrame("+++", 3, 3000);
johnb 5:b40a6fd3a334 412
johnb 5:b40a6fd3a334 413 /* Everything OK with last request? */
johnb 5:b40a6fd3a334 414 if( ret_val == XBEEDEVICE_OK )
johnb 5:b40a6fd3a334 415 {
johnb 5:b40a6fd3a334 416 wait_ms( XBEEAPI_CONFIG_GUARDPERIOD_MS );
johnb 5:b40a6fd3a334 417
johnb 5:b40a6fd3a334 418 /* API mode 2 please! */
johnb 5:b40a6fd3a334 419 ret_val = SendFrame(api_mode2_cmd,sizeof(api_mode2_cmd));
johnb 5:b40a6fd3a334 420 }
johnb 5:b40a6fd3a334 421
johnb 5:b40a6fd3a334 422 /* Everything OK with last request? */
johnb 5:b40a6fd3a334 423 if( ret_val == XBEEDEVICE_OK )
johnb 5:b40a6fd3a334 424 {
johnb 5:b40a6fd3a334 425 /* Exit command mode, back to API mode */
johnb 5:b40a6fd3a334 426 ret_val = SendFrame(exit_cmd_mode_cmd,sizeof(exit_cmd_mode_cmd));
johnb 5:b40a6fd3a334 427 }
johnb 5:b40a6fd3a334 428
johnb 5:b40a6fd3a334 429 m_inAtCmdMode = false;
johnb 5:b40a6fd3a334 430
johnb 5:b40a6fd3a334 431 return ret_val;
johnb 5:b40a6fd3a334 432 }
johnb 5:b40a6fd3a334 433
johnb 42:81c789ba4c08 434 #if defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 435 bool XBeeDevice::setupDispatchTask( void )
johnb 42:81c789ba4c08 436 {
johnb 42:81c789ba4c08 437 bool ret_val = false;
johnb 42:81c789ba4c08 438
johnb 42:81c789ba4c08 439 /* Ensure the dispatch thread exists */
johnb 42:81c789ba4c08 440 if( XBeeRxDispatchTID == NULL )
johnb 42:81c789ba4c08 441 {
johnb 42:81c789ba4c08 442 XBeeRxDispatchTID = osThreadCreate(osThread(XBeeRxDispatch), NULL);
johnb 42:81c789ba4c08 443 }
johnb 42:81c789ba4c08 444
johnb 42:81c789ba4c08 445 /* Register this device in the list that need dispatch */
johnb 43:975a28e01dac 446 if( s_XBeeDevices.push( this ) )
johnb 42:81c789ba4c08 447 {
johnb 42:81c789ba4c08 448 ret_val = true;
johnb 42:81c789ba4c08 449 }
johnb 42:81c789ba4c08 450
johnb 42:81c789ba4c08 451 return ret_val;
johnb 42:81c789ba4c08 452 }
johnb 42:81c789ba4c08 453 #endif // defined XBEEAPI_CONFIG_USING_RTOS && defined XBEEAPI_CONFIG_RTOS_USE_DISPATCHER
johnb 42:81c789ba4c08 454
johnb 5:b40a6fd3a334 455 #if defined XBEEAPI_CONFIG_ENABLE_DEVELOPER
johnb 5:b40a6fd3a334 456
johnb 5:b40a6fd3a334 457 #define PRINTABLE_ASCII_FIRST 32U
johnb 5:b40a6fd3a334 458 #define PRINTABLE_ASCII_LAST 126U
johnb 5:b40a6fd3a334 459
johnb 5:b40a6fd3a334 460 void XBeeDevice::dumpRxBuffer( Stream* p_buf, const bool p_hexView )
johnb 5:b40a6fd3a334 461 {
johnb 5:b40a6fd3a334 462 uint8_t c;
johnb 5:b40a6fd3a334 463 while( m_rxBuff.getSize() ) {
johnb 5:b40a6fd3a334 464 if( m_rxBuff.read( &c, 1 ) ) {
johnb 5:b40a6fd3a334 465 if( p_hexView ) {
johnb 5:b40a6fd3a334 466 uint8_t a = '-';
johnb 5:b40a6fd3a334 467 if(( c>=PRINTABLE_ASCII_FIRST ) && (c<=PRINTABLE_ASCII_LAST)) {
johnb 5:b40a6fd3a334 468 a = c;
johnb 5:b40a6fd3a334 469 }
johnb 5:b40a6fd3a334 470 p_buf->printf("0x%02x (%c) ",c,a);
johnb 5:b40a6fd3a334 471 } else {
johnb 5:b40a6fd3a334 472 p_buf->printf("%c",c);
johnb 5:b40a6fd3a334 473 if( c == '\r' ) {
johnb 5:b40a6fd3a334 474 p_buf->printf("\n");
johnb 5:b40a6fd3a334 475 }
johnb 5:b40a6fd3a334 476 }
johnb 5:b40a6fd3a334 477 }
johnb 5:b40a6fd3a334 478 }
johnb 5:b40a6fd3a334 479 }
johnb 5:b40a6fd3a334 480
johnb 5:b40a6fd3a334 481 #endif