Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
XBee.cpp
00001 /** 00002 * Copyright (c) 2015 Digi International Inc., 00003 * All rights not expressly granted are reserved. 00004 * 00005 * This Source Code Form is subject to the terms of the Mozilla Public 00006 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 00007 * You can obtain one at http://mozilla.org/MPL/2.0/. 00008 * 00009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 00010 * ======================================================================= 00011 */ 00012 00013 #include "XBeeLib.h" 00014 #include "FrameHandlers/FH_ModemStatus.h" 00015 00016 /* States for the state machine that processes incoming data on the serial port */ 00017 #define WAITING_FOR_START_FRAME (0) 00018 #define WAITING_FOR_LENGTH_MSB (1) 00019 #define WAITING_FOR_LENGTH_LSB (2) 00020 #define WAITING_FOR_PAYLOAD (3) 00021 #define WAITING_FOR_CHECKSUM (4) 00022 00023 #define IS_API2() (_mode == ModeAPI2) 00024 #define IS_API_MODE() (_mode == ModeAPI1 || _mode == ModeAPI2) 00025 00026 using namespace XBeeLib; 00027 00028 #if defined(FRAME_BUFFER_SIZE_SYNCR) 00029 #if FRAME_BUFFER_SIZE_SYNCR < 2 00030 #error "FRAME_BUFFER_SIZE_SYNCR must be at least 2" 00031 #endif 00032 #else 00033 #define FRAME_BUFFER_SIZE_SYNCR 1 00034 #endif 00035 00036 #define MAX_FRAME_PAYLOAD_LEN_SYNCR (1 /* type */ + 1 /* id */ + 2 /* at cmd*/ + 1 /* status */ + 2 /* MY sender */ + \ 00037 8 /* 64b sender */ + 20 /* max id */ + 1 /* null ter */ + 2 /* MY parent */ + 1 /* dev type */ + \ 00038 1 /* source event */ + 2 /* prof. id */ + 2 /* man. id */) 00039 00040 FrameBuffer XBee::_framebuf_app(FRAME_BUFFER_SIZE, MAX_FRAME_PAYLOAD_LEN); 00041 FrameBuffer XBee::_framebuf_syncr(FRAME_BUFFER_SIZE_SYNCR, MAX_FRAME_PAYLOAD_LEN_SYNCR); 00042 00043 #if defined(DEVICE_SERIAL_FC) 00044 bool XBee::check_radio_flow_control() 00045 { 00046 AtCmdFrame::AtCmdResp cmdresp; 00047 uint32_t value; 00048 00049 if (_serial_flow_type == SerialBase::RTSCTS || _serial_flow_type == SerialBase::CTS) { 00050 cmdresp = get_param("D7", &value); 00051 if (cmdresp != AtCmdFrame::AtCmdRespOk) { 00052 digi_log(LogLevelError, "Could not read CTS configuration. Error %d\r\n", cmdresp); 00053 return false; 00054 } else if (value != 1) { 00055 digi_log(LogLevelError, "Bad CTS configuration. Radio 'D7' param is %d and should be 1\r\n", value); 00056 return false; 00057 } 00058 } 00059 00060 if (_serial_flow_type == SerialBase::RTSCTS || _serial_flow_type == SerialBase::RTS) { 00061 cmdresp = get_param("D6", &value); 00062 if (cmdresp != AtCmdFrame::AtCmdRespOk) { 00063 digi_log(LogLevelError, "Could not read RTS configuration. Error %d\r\n", cmdresp); 00064 return false; 00065 } else if (value != 1) { 00066 digi_log(LogLevelError, "Bad RTS configuration. Radio 'D6' param is %d and should be 1\r\n", value); 00067 return false; 00068 } 00069 } 00070 00071 return true; 00072 } 00073 #endif 00074 00075 /* Class constructor */ 00076 XBee::XBee(PinName tx, PinName rx, PinName reset, PinName rts, PinName cts, int baud) : 00077 _mode(ModeUnknown), _hw_version(0), _fw_version(0), _timeout_ms(SYNC_OPS_TIMEOUT_MS), _dev_addr64(ADDR64_UNASSIGNED), 00078 _reset(NULL), _tx_options(0), _hw_reset_cnt(0), _wd_reset_cnt(0), _modem_status_handler(NULL), _modem_status(AtCmdFrame::HwReset), _initializing(true), _node_by_ni_frame_id(0) 00079 { 00080 00081 if (reset != NC) { 00082 _reset = new DigitalOut(reset, 1); 00083 } 00084 00085 _uart = new UnbufferedSerial(tx, rx); 00086 _uart->baud(baud); 00087 00088 _serial_flow_type = SerialBase::Disabled; 00089 #if defined(DEVICE_SERIAL_FC) 00090 if (rts != NC && cts != NC) { 00091 _serial_flow_type = SerialBase::RTSCTS; 00092 _uart->set_flow_control(_serial_flow_type, rts, cts); 00093 } else if (rts != NC && cts == NC) { 00094 _serial_flow_type = SerialBase::RTS; 00095 _uart->set_flow_control(_serial_flow_type, rts); 00096 } else if (rts == NC && cts != NC) { 00097 _serial_flow_type = SerialBase::CTS; 00098 _uart->set_flow_control(_serial_flow_type, cts); 00099 } 00100 #endif 00101 /* Enable the reception of bytes on the serial interface by providing a cb */ 00102 //_uart->attach(this, &XBee::uart_read_cb, Serial::RxIrq); 00103 _uart->attach(callback(this,&XBee::uart_read_cb), SerialBase::RxIrq); 00104 00105 for (int i = 0; i < MAX_FRAME_HANDLERS; i++) { 00106 _fhandlers[i] = NULL; 00107 } 00108 } 00109 00110 /* Class destructor */ 00111 XBee::~XBee() 00112 { 00113 unregister_modem_status_cb(); 00114 00115 if (_uart != NULL) { 00116 delete _uart; 00117 } 00118 if (_reset != NULL) { 00119 delete _reset; 00120 } 00121 } 00122 00123 #include <inttypes.h> 00124 00125 RadioStatus XBee::init(void) 00126 { 00127 AtCmdFrame::AtCmdResp cmd_resp; 00128 uint32_t var32; 00129 00130 _initializing = true; 00131 00132 const unsigned int max_reset_retries = 3; 00133 RadioStatus reset_status; 00134 for (unsigned int i = 0; i < max_reset_retries; i++) { 00135 reset_status = device_reset(); 00136 if (reset_status == Success) { 00137 break; 00138 } 00139 } 00140 if (reset_status != Success) { 00141 return reset_status; 00142 } 00143 00144 /* Check if radio is in API1 or API2 _mode */ 00145 cmd_resp = get_param("AP", &var32); 00146 if (cmd_resp != AtCmdFrame::AtCmdRespOk) { 00147 return Failure; 00148 } 00149 _mode = (RadioMode)var32; 00150 00151 /* Read the device unique 64b address */ 00152 uint32_t serialn_high, serialn_low; 00153 cmd_resp = get_param("SH", &serialn_high); 00154 if (cmd_resp != AtCmdFrame::AtCmdRespOk) { 00155 return Failure; 00156 } 00157 00158 cmd_resp = get_param("SL", &serialn_low); 00159 if (cmd_resp != AtCmdFrame::AtCmdRespOk) { 00160 return Failure; 00161 } 00162 00163 _dev_addr64 = ((uint64_t)serialn_high << 32) | serialn_low; 00164 00165 /* Read some important parameters */ 00166 cmd_resp = get_param("HV", &var32); 00167 if (cmd_resp != AtCmdFrame::AtCmdRespOk) { 00168 return Failure; 00169 } 00170 _hw_version = var32; 00171 00172 cmd_resp = get_param("VR", &var32); 00173 if (cmd_resp != AtCmdFrame::AtCmdRespOk) { 00174 return Failure; 00175 } 00176 _fw_version = var32; 00177 00178 digi_log(LogLevelInfo, "mode: %02x\r\n", (uint8_t)_mode); 00179 digi_log(LogLevelInfo, "HV: %04x\r\n", _hw_version); 00180 digi_log(LogLevelInfo, "VR: %04x\r\n", _fw_version); 00181 digi_log(LogLevelInfo, "ADDR64: %08x:%08x\r\n", UINT64_HI32(_dev_addr64), UINT64_LO32(_dev_addr64)); 00182 00183 #if defined(DEVICE_SERIAL_FC) 00184 bool valid_radio_fc = check_radio_flow_control(); 00185 assert(valid_radio_fc == true); 00186 #endif 00187 00188 _initializing = false; 00189 if (_modem_status_handler != NULL) { 00190 const ApiFrame frame = ApiFrame(ApiFrame::AtModemStatus, (uint8_t *)&_modem_status, sizeof(_modem_status)); 00191 _modem_status_handler->process_frame_data(&frame); 00192 } 00193 00194 return Success; 00195 } 00196 00197 uint64_t XBee::get_addr64() const 00198 { 00199 return _dev_addr64; 00200 } 00201 00202 RadioStatus XBee::hardware_reset() 00203 { 00204 if (_reset != NULL) { 00205 volatile uint16_t * const rst_cnt_p = &_hw_reset_cnt; 00206 const uint16_t init_rst_cnt = *rst_cnt_p; 00207 *_reset = 0; 00208 //wait_ms(10); 00209 ThisThread::sleep_for(chrono::milliseconds(10)); 00210 *_reset = 1; 00211 return wait_for_module_to_reset(rst_cnt_p, init_rst_cnt); 00212 } 00213 00214 return Failure; 00215 } 00216 00217 RadioStatus XBee::device_reset() 00218 { 00219 if (hardware_reset() == Success) { 00220 return Success; 00221 } 00222 00223 return software_reset(); 00224 } 00225 00226 RadioStatus XBee::wait_for_module_to_reset(volatile uint16_t *rst_cnt_p, uint16_t init_rst_cnt) 00227 { 00228 Timer timer = Timer(); 00229 timer.start(); 00230 00231 //while (*rst_cnt_p == init_rst_cnt && timer.read_ms() < RESET_TIMEOUT_MS) { 00232 //wait_ms(100); 00233 while (*rst_cnt_p == init_rst_cnt && timer.elapsed_time().count() < RESET_TIMEOUT_MS) { 00234 00235 ThisThread::sleep_for(chrono::milliseconds(100)); 00236 } 00237 00238 if (*rst_cnt_p == init_rst_cnt) { 00239 digi_log(LogLevelWarning, "Reset Timeout\r\n"); 00240 return Failure; 00241 } 00242 return Success; 00243 } 00244 00245 /** Callback function called when data is received on the serial port */ 00246 void XBee::uart_read_cb(void) 00247 { 00248 static uint8_t rxstate = WAITING_FOR_START_FRAME; 00249 static uint16_t framelen = 0; 00250 static uint16_t bytes_read; 00251 static uint8_t chksum; 00252 static ApiFrame *frame = NULL; 00253 static bool last_byte_escaped = false; 00254 static FrameBuffer * framebuf = NULL; 00255 00256 while (_uart->readable()) { 00257 //uint8_t data = _uart->getc(); 00258 uint8_t data; 00259 _uart->read(&data, 1); 00260 00261 if (IS_API2() && rxstate != WAITING_FOR_START_FRAME) { 00262 if (last_byte_escaped) { 00263 data = data ^ DR_ESCAPE_XOR_BYTE; 00264 last_byte_escaped = false; 00265 } else if (data == DR_ESCAPE_BYTE) { 00266 last_byte_escaped = true; 00267 continue; 00268 } 00269 } 00270 00271 switch (rxstate) { 00272 case WAITING_FOR_START_FRAME: 00273 if (data == DR_START_OF_FRAME) { 00274 rxstate = WAITING_FOR_LENGTH_MSB; 00275 } 00276 break; 00277 00278 case WAITING_FOR_LENGTH_MSB: 00279 framelen = data << 8; 00280 rxstate = WAITING_FOR_LENGTH_LSB; 00281 break; 00282 00283 case WAITING_FOR_LENGTH_LSB: 00284 framelen |= data; 00285 rxstate = WAITING_FOR_PAYLOAD; 00286 bytes_read = 0; 00287 chksum = 0; 00288 /* Sanity check that the frame is smaller than... */ 00289 if (framelen > MAX_FRAME_PAYLOAD_LEN) { 00290 digi_log(LogLevelDebug, "framelen=%d too long\r\n", framelen); 00291 digi_log(LogLevelWarning, "Frame dropped, frame too long. Increase MAX_FRAME_PAYLOAD_LEN define\r\n"); 00292 rxstate = WAITING_FOR_START_FRAME; 00293 } 00294 break; 00295 00296 case WAITING_FOR_PAYLOAD: 00297 #define CACHED_SIZE 3 00298 static uint8_t frame_cached[CACHED_SIZE]; 00299 00300 if (framelen <= CACHED_SIZE) { 00301 if (!bytes_read) { 00302 const ApiFrame::ApiFrameType frame_type = (ApiFrame::ApiFrameType)data; 00303 switch (frame_type) 00304 { 00305 case ApiFrame::AtCmdResp: 00306 case ApiFrame::RemoteCmdResp: 00307 case ApiFrame::TxStatusZBDM: 00308 case ApiFrame::TxStatus: 00309 framebuf = &_framebuf_syncr; 00310 break; 00311 00312 case ApiFrame::RxPacket64Bit: 00313 case ApiFrame::RxPacket16Bit: 00314 case ApiFrame::Io64Bit: 00315 case ApiFrame::Io16Bit: 00316 case ApiFrame::AtModemStatus: 00317 case ApiFrame::RxPacketAO0: 00318 case ApiFrame::IoSampleRxZBDM: 00319 framebuf = &_framebuf_app; 00320 break; 00321 00322 case ApiFrame::RxPacketAO1: 00323 case ApiFrame::SensorRxIndAO0: 00324 case ApiFrame::NodeIdentIndAO0: 00325 case ApiFrame::OtaFwUpStatus: 00326 case ApiFrame::RouteRecInd: 00327 case ApiFrame::Many2OneRRInd: 00328 case ApiFrame::TxReq64Bit: 00329 case ApiFrame::TxReq16Bit: 00330 case ApiFrame::AtCmd: 00331 case ApiFrame::AtCmdQueuePV: 00332 case ApiFrame::TxReqZBDM: 00333 case ApiFrame::ExpAddrCmd: 00334 case ApiFrame::RemoteCmdReq: 00335 case ApiFrame::CreateSrcRoute: 00336 case ApiFrame::Invalid: 00337 case ApiFrame::RouteInfo: 00338 case ApiFrame::AggregateAddr: 00339 framebuf = NULL; 00340 break; 00341 } 00342 00343 if (framebuf == NULL) { 00344 digi_log(LogLevelWarning, "Discarding not supported frame type %02x\r\n", frame_type); 00345 rxstate = WAITING_FOR_START_FRAME; 00346 } else { 00347 frame = framebuf->get_next_free_frame(); 00348 if (frame == NULL) { 00349 /* It's not possible to achive this condition as we discard older frames and only one frame can be used by syncr. commands */ 00350 assert(frame != NULL); 00351 rxstate = WAITING_FOR_START_FRAME; 00352 } else { 00353 frame->set_data_len(framelen - 1); 00354 } 00355 00356 frame->set_frame_type(frame_type); 00357 } 00358 } else { 00359 frame->set_data(data, bytes_read - 1); 00360 } 00361 chksum += data; 00362 bytes_read++; 00363 if (bytes_read == framelen) { 00364 rxstate = WAITING_FOR_CHECKSUM; 00365 } 00366 break; 00367 } 00368 00369 00370 if (bytes_read < CACHED_SIZE) { 00371 frame_cached[bytes_read] = data; 00372 } 00373 else if (bytes_read == CACHED_SIZE) { 00374 const ApiFrame::ApiFrameType frame_type = (ApiFrame::ApiFrameType)frame_cached[0]; 00375 switch (frame_type) 00376 { 00377 case ApiFrame::RemoteCmdResp: 00378 case ApiFrame::TxStatusZBDM: 00379 case ApiFrame::TxStatus: 00380 framebuf = &_framebuf_syncr; 00381 break; 00382 00383 case ApiFrame::AtCmdResp: 00384 if ((frame_cached[1] != _node_by_ni_frame_id ) && (frame_cached[2] == 'N') && (data == 'D')) 00385 { 00386 framebuf = &_framebuf_app; 00387 } else { 00388 framebuf = &_framebuf_syncr; 00389 } 00390 break; 00391 00392 case ApiFrame::RxPacket64Bit: 00393 case ApiFrame::RxPacket16Bit: 00394 case ApiFrame::Io64Bit: 00395 case ApiFrame::Io16Bit: 00396 case ApiFrame::AtModemStatus: 00397 case ApiFrame::RxPacketAO0: 00398 case ApiFrame::IoSampleRxZBDM: 00399 framebuf = &_framebuf_app; 00400 break; 00401 00402 case ApiFrame::RxPacketAO1: 00403 case ApiFrame::SensorRxIndAO0: 00404 case ApiFrame::NodeIdentIndAO0: 00405 case ApiFrame::OtaFwUpStatus: 00406 case ApiFrame::RouteRecInd: 00407 case ApiFrame::Many2OneRRInd: 00408 case ApiFrame::TxReq64Bit: 00409 case ApiFrame::TxReq16Bit: 00410 case ApiFrame::AtCmd: 00411 case ApiFrame::AtCmdQueuePV: 00412 case ApiFrame::TxReqZBDM: 00413 case ApiFrame::ExpAddrCmd: 00414 case ApiFrame::RemoteCmdReq: 00415 case ApiFrame::CreateSrcRoute: 00416 case ApiFrame::Invalid: 00417 case ApiFrame::RouteInfo: 00418 case ApiFrame::AggregateAddr: 00419 framebuf = NULL; 00420 break; 00421 } 00422 00423 if (framebuf == NULL) { 00424 digi_log(LogLevelWarning, "Discarding not supported frame type %02x\r\n", frame_type); 00425 rxstate = WAITING_FOR_START_FRAME; 00426 } else { 00427 frame = framebuf->get_next_free_frame(); 00428 if (frame == NULL) { 00429 /* It's not possible to achive this condition as we discard older frames and only one frame can be used by syncr. commands */ 00430 assert(frame != NULL); 00431 rxstate = WAITING_FOR_START_FRAME; 00432 } else { 00433 frame->set_data_len(framelen - 1); 00434 } 00435 00436 frame->set_frame_type(frame_type); 00437 frame->set_data(frame_cached[1], 0); 00438 frame->set_data(frame_cached[2], 1); 00439 frame->set_data(data, 2); 00440 } 00441 } else { 00442 frame->set_data(data, bytes_read - 1); 00443 } 00444 chksum += data; 00445 bytes_read++; 00446 if (bytes_read == framelen) { 00447 rxstate = WAITING_FOR_CHECKSUM; 00448 } 00449 break; 00450 00451 case WAITING_FOR_CHECKSUM: 00452 chksum += data; 00453 if (chksum == 0xFF) { 00454 /* We got a valid frame!! */ 00455 frame->dump(); 00456 00457 /* If its a _modem status frame, process it to update the status info of the library. 00458 * The frame is also queued to allow processing it other handlers registered. 00459 * Note that radio_status_update() has to be fast to minimize the impact of processing 00460 * the funcion here */ 00461 if (frame->get_frame_type() == ApiFrame::AtModemStatus) { 00462 radio_status_update((AtCmdFrame::ModemStatus)frame->get_data_at(0)); 00463 if (_initializing) { 00464 framebuf->free_frame(frame); 00465 } else { 00466 framebuf->complete_frame(frame); 00467 } 00468 } else { 00469 framebuf->complete_frame(frame); 00470 /* Note, the frame will be released elsewhere, once it has been processed */ 00471 } 00472 } else { 00473 framebuf->free_frame(frame); 00474 digi_log(LogLevelWarning, "Checksum error, got %02x, %02x\r\n", data, chksum); 00475 } 00476 /* Intentional fall-through */ 00477 default: 00478 rxstate = WAITING_FOR_START_FRAME; 00479 break; 00480 } 00481 } 00482 /* TODO, signal the thread processing incoming frames */ 00483 } 00484 00485 /* This is a pure virtual function, but exists here because its called from this class to 00486 * to update the status of the object, and can be called before the construction of the 00487 * object has been completed and the virtual functions filled */ 00488 void XBee::radio_status_update(AtCmdFrame::ModemStatus modem_status) 00489 { 00490 UNUSED_PARAMETER(modem_status); 00491 } 00492 00493 void XBee::set_timeout(uint16_t timeout_ms) 00494 { 00495 this->_timeout_ms = timeout_ms; 00496 } 00497 00498 uint16_t XBee::get_timeout(void) const 00499 { 00500 return _timeout_ms; 00501 } 00502 00503 ApiFrame * XBee::get_this_api_frame(uint8_t id, ApiFrame::ApiFrameType type, 00504 ApiFrame::ApiFrameType type2) 00505 { 00506 Timer timer = Timer(); 00507 timer.start(); 00508 00509 //while (timer.read_ms() < _timeout_ms) { 00510 while (timer.elapsed_time().count() < _timeout_ms) { 00511 00512 ApiFrame * frame = _framebuf_syncr.get_next_complete_frame(); 00513 if (frame == NULL) { 00514 //wait_ms(10); 00515 ThisThread::sleep_for(chrono::milliseconds(10)); 00516 continue; 00517 } 00518 00519 if ((frame->get_frame_type() != type) && 00520 (frame->get_frame_type() != type2)) { 00521 _framebuf_syncr.complete_frame(frame); 00522 //wait_ms(1); 00523 ThisThread::sleep_for(chrono::milliseconds(1)); 00524 continue; 00525 } 00526 00527 if (frame->get_data_at(ATCMD_RESP_FRAME_ID_OFFSET) != id) { 00528 _framebuf_syncr.complete_frame(frame); 00529 //wait_ms(1); 00530 ThisThread::sleep_for(chrono::milliseconds(1)); 00531 continue; 00532 } 00533 00534 /* frame found */ 00535 return frame; 00536 } 00537 00538 digi_log(LogLevelWarning, "Frame type: %02x, id: %02x, timeout\r\n", (uint8_t)type, id); 00539 00540 return NULL; 00541 } 00542 00543 void XBee::send_byte_escaping_if(uint8_t data) 00544 { 00545 if (IS_API2()) { 00546 switch (data) { 00547 case DR_START_OF_FRAME: 00548 case DR_ESCAPE_BYTE: 00549 case DR_XON_BYTE: 00550 case DR_XOFF_BYTE: 00551 //_uart->putc(DR_ESCAPE_BYTE); 00552 //_uart->putc(data ^ DR_ESCAPE_XOR_BYTE); 00553 _uart->write((uint8_t *)DR_ESCAPE_BYTE, 1); 00554 _uart->write((uint8_t *)(data ^ DR_ESCAPE_XOR_BYTE),1); 00555 break; 00556 default: 00557 //_uart->putc(data); 00558 _uart->write(&data,1); 00559 } 00560 } else { 00561 //_uart->putc(data); 00562 _uart->write(&data,1); 00563 } 00564 } 00565 00566 void XBee::send_api_frame(ApiFrame *frame) 00567 { 00568 uint8_t chksum; 00569 const uint8_t *data; 00570 uint16_t bytes_sent = 0, frame_len; 00571 00572 frame->dump(); 00573 00574 frame_len = 1 + frame->get_data_len(); /* frame type + frame payload */ 00575 data = frame->get_data(); 00576 00577 /* Send the start of frame delimiter */ 00578 //_uart->putc(DR_START_OF_FRAME); 00579 _uart->write((uint8_t *)DR_START_OF_FRAME,1); 00580 00581 /* Now the length */ 00582 send_byte_escaping_if((uint8_t)(frame_len >> 8)); 00583 send_byte_escaping_if((uint8_t)frame_len); 00584 00585 /* Send the Frame type and then the payload */ 00586 chksum = (uint8_t)frame->get_frame_type(); 00587 send_byte_escaping_if(chksum); 00588 bytes_sent++; 00589 00590 /* And now, send the packet payload */ 00591 while (bytes_sent++ < frame_len) { 00592 chksum += *data; 00593 send_byte_escaping_if(*data++); 00594 } 00595 00596 /* And finally send the checksum */ 00597 send_byte_escaping_if(~chksum); 00598 } 00599 00600 RadioStatus XBee::register_frame_handler(FrameHandler *const handler) 00601 { 00602 if (handler != NULL) { 00603 for (int i = 0; i < MAX_FRAME_HANDLERS; i++) { 00604 if (_fhandlers[i] != NULL) { 00605 continue; 00606 } 00607 _fhandlers[i] = handler; 00608 return Success; 00609 } 00610 } 00611 00612 digi_log(LogLevelError, "No more Frame Handlers available. Increase MAX_FRAME_HANDLERS define\r\n"); 00613 00614 return Failure; 00615 } 00616 00617 RadioStatus XBee::unregister_frame_handler(FrameHandler *const handler) 00618 { 00619 int i; 00620 00621 if (handler != NULL) { 00622 for (i = 0; i < MAX_FRAME_HANDLERS; i++) { 00623 if (_fhandlers[i] == handler) { 00624 break; 00625 } 00626 } 00627 00628 if (i == MAX_FRAME_HANDLERS) { 00629 return Failure; 00630 } 00631 00632 do { 00633 if (i == MAX_FRAME_HANDLERS - 1) { 00634 _fhandlers[i] = NULL; 00635 } else { 00636 _fhandlers[i] = _fhandlers[i + 1]; 00637 } 00638 } while (++i < MAX_FRAME_HANDLERS); 00639 } 00640 00641 return Success; 00642 } 00643 00644 XBee::RadioProtocol XBee::get_radio_protocol(void) const 00645 { 00646 enum HardwareVersion { 00647 #ifdef EXTRA_XBEE_PROTOCOLS 00648 X09_009 = 0x01, 00649 X09_019 = 0x02, 00650 XH9_009 = 0x03, 00651 XH9_019 = 0x04, 00652 X24_009 = 0x05, 00653 X24_019 = 0x06, 00654 X09_001 = 0x07, 00655 XH9_001 = 0x08, 00656 X08_004 = 0x09, 00657 XC09_009 = 0x0A, 00658 XC09_038 = 0x0B, 00659 X24_038 = 0x0C, 00660 X09_009_TX = 0x0D, 00661 X09_019_TX = 0x0E, 00662 XH9_009_TX = 0x0F, 00663 XH9_019_TX = 0x10, 00664 X09_001_TX = 0x11, 00665 XH9_001_TX = 0x12, 00666 XT09B_XXX = 0x13, 00667 XT09_XXX = 0x14, 00668 XC08_009 = 0x15, 00669 XC08_038 = 0x16, 00670 #endif 00671 XB24_AXX_XX = 0x17, 00672 XBP24_AXX_XX = 0x18, 00673 XB24_BXIX_XXX = 0x19, 00674 XBP24_BXIX_XXX = 0x1A, 00675 #ifdef EXTRA_XBEE_PROTOCOLS 00676 XBP09_DXIX_XXX = 0x1B, 00677 XBP09_XCXX_XXX = 0x1C, 00678 XBP08_DXXX_XXX = 0x1D, 00679 #endif 00680 XBP24B = 0x1E, 00681 #ifdef EXTRA_XBEE_PROTOCOLS 00682 XB24_WF = 0x1F, 00683 AMBER_MBUS = 0x20, 00684 #endif 00685 XBP24C = 0x21, 00686 XB24C = 0x22, 00687 #ifdef EXTRA_XBEE_PROTOCOLS 00688 XSC_GEN3 = 0x23, 00689 SRD_868_GEN3 = 0x24, 00690 ABANDONATED = 0x25, 00691 SMT_900LP = 0x26, 00692 WIFI_ATHEROS = 0x27, 00693 SMT_WIFI_ATHEROS = 0x28, 00694 SMT_475LP = 0x29, 00695 XBEE_CELL_TH = 0x2A, 00696 XLR_MODULE = 0x2B, 00697 XB900HP_NZ = 0x2C, 00698 XBP24C_TH_DIP = 0x2D, 00699 XB24C_TH_DIP = 0x2E, 00700 XLR_BASEBOARD = 0x2F, 00701 XBP24C_S2C_SMT = 0x30 00702 #endif 00703 }; 00704 const bool fw_4_bytes_len = _fw_version > 0x0FFF && _fw_version < 0xFFFF; 00705 const uint8_t fw_nibble_3 = (_fw_version >> (4 * 3)) & 0x000F; 00706 const uint8_t fw_nibble_1 = (_fw_version >> (4 * 1)) & 0x000F; 00707 const uint8_t fw_nibble_0 = (_fw_version >> (4 * 0)) & 0x000F; 00708 const uint8_t hw_version_msb = _hw_version >> 8; 00709 00710 if (hw_version_msb == XB24_AXX_XX || hw_version_msb == XBP24_AXX_XX) { 00711 #ifdef EXTRA_XBEE_PROTOCOLS 00712 if (fw_4_bytes_len && fw_nibble_3 == 8) { 00713 return DigiMesh; 00714 } 00715 return Raw_802_15_4; 00716 #else 00717 if (!(fw_4_bytes_len && fw_nibble_3 == 8)) { 00718 return Raw_802_15_4; 00719 } 00720 #endif 00721 } else if (hw_version_msb == XB24_BXIX_XXX || hw_version_msb == XBP24_BXIX_XXX) { 00722 if (fw_4_bytes_len && ((fw_nibble_3 == 1 && fw_nibble_1 == 2 && fw_nibble_0 == 0) || fw_nibble_3 == 2)) { 00723 return ZigBee; 00724 } 00725 #ifdef EXTRA_XBEE_PROTOCOLS 00726 if (fw_4_bytes_len && fw_nibble_3 == 3) { 00727 return SmartEnergy; 00728 } 00729 return ZNet; 00730 } else if (hw_version_msb == XBP09_DXIX_XXX) { 00731 if (fw_4_bytes_len && (fw_nibble_3 == 8 || fw_nibble_1 == 8)) { 00732 return DigiMesh; 00733 } 00734 return DigiPoint; 00735 } else if (hw_version_msb == XBP08_DXXX_XXX) { 00736 return DigiPoint; 00737 #endif 00738 } else if (hw_version_msb == XBP24B) { 00739 #ifdef EXTRA_XBEE_PROTOCOLS 00740 if (fw_4_bytes_len && fw_nibble_3 == 3) { 00741 return SmartEnergy; 00742 } 00743 return ZigBee; 00744 #else 00745 if (!(fw_4_bytes_len && fw_nibble_3 == 3)) { 00746 return ZigBee; 00747 } 00748 #endif 00749 #ifdef EXTRA_XBEE_PROTOCOLS 00750 } else if (hw_version_msb == XB24_WF || hw_version_msb == WIFI_ATHEROS || hw_version_msb == SMT_WIFI_ATHEROS) { 00751 return XBeeWiFi; 00752 #endif 00753 } else if (hw_version_msb == XBP24C || hw_version_msb == XB24C) { 00754 if (fw_4_bytes_len && fw_nibble_3 == 2) { 00755 return Raw_802_15_4; 00756 } 00757 #ifdef EXTRA_XBEE_PROTOCOLS 00758 if (fw_4_bytes_len && fw_nibble_3 == 5) { 00759 return SmartEnergy; 00760 } 00761 return ZigBee; 00762 #else 00763 if (!(fw_4_bytes_len && fw_nibble_3 == 5)) { 00764 return ZigBee; 00765 } 00766 #endif 00767 #ifdef EXTRA_XBEE_PROTOCOLS 00768 } else if (hw_version_msb == XSC_GEN3 || hw_version_msb == SRD_868_GEN3) { 00769 if (fw_4_bytes_len && fw_nibble_3 == 8) { 00770 return DigiMesh; 00771 } else if (fw_4_bytes_len && fw_nibble_3 == 1) { 00772 return DigiPoint; 00773 } 00774 return None; 00775 } else if (hw_version_msb == XBEE_CELL_TH) { 00776 return None; 00777 } else if (hw_version_msb == XLR_MODULE) { 00778 return None; 00779 } else if (hw_version_msb == XLR_BASEBOARD) { 00780 return None; 00781 } else if (hw_version_msb == XB900HP_NZ) { 00782 return DigiPoint; 00783 } else if (hw_version_msb == XBP24C_TH_DIP || hw_version_msb == XB24C_TH_DIP || hw_version_msb == XBP24C_S2C_SMT) { 00784 if (fw_4_bytes_len && fw_nibble_3 == 9) { 00785 return DigiMesh; 00786 } 00787 if (fw_4_bytes_len && fw_nibble_3 == 5) { 00788 return SmartEnergy; 00789 } 00790 if (fw_4_bytes_len && fw_nibble_3 == 2) { 00791 return Raw_802_15_4; 00792 } 00793 return ZigBee; 00794 } 00795 #else 00796 } 00797 #endif 00798 00799 return None; 00800 } 00801 00802 #define TX_STATUS_OFFSET_ZB 4 00803 #define TX_STATUS_OFFSET_802 1 00804 00805 TxStatus XBee::send_data(ApiFrame *frame) 00806 { 00807 TxStatus resp = TxStatusTimeout; 00808 ApiFrame *resp_frame; 00809 00810 send_api_frame(frame); 00811 00812 /* Wait for the transmit status response packet */ 00813 resp_frame = get_this_api_frame(frame->get_frame_id(), 00814 ApiFrame::TxStatusZBDM, ApiFrame::TxStatus); 00815 if (resp_frame == NULL) { 00816 return resp; 00817 } 00818 00819 uint8_t index = resp_frame->get_frame_type() == ApiFrame::TxStatusZBDM ? 00820 TX_STATUS_OFFSET_ZB : TX_STATUS_OFFSET_802; 00821 00822 resp = (TxStatus)resp_frame->get_data_at(index); 00823 00824 /* Once processed, remove the frame from the buffer */ 00825 _framebuf_syncr.free_frame(resp_frame); 00826 00827 return resp; 00828 } 00829 00830 TxStatus XBee::send_data_broadcast(const uint8_t *const data, uint16_t len, bool syncr) 00831 { 00832 const RemoteXBee remoteDevice = RemoteXBee(ADDR64_BROADCAST); 00833 return send_data(remoteDevice, data, len, syncr); 00834 } 00835 00836 uint32_t XBee::process_rx_frames() 00837 { 00838 ApiFrame *frame = NULL; 00839 00840 while ((frame = _framebuf_app.get_next_complete_frame()) != NULL) { 00841 for (int i = 0; i < MAX_FRAME_HANDLERS; i++) { 00842 00843 if (_fhandlers[i] == NULL) { 00844 /* No more handlers, break here */ 00845 break; 00846 } 00847 00848 /* Check if frame and handler match, if not... go for the next one */ 00849 if (frame->get_frame_type() != _fhandlers[i]->get_type()) { 00850 continue; 00851 } 00852 00853 _fhandlers[i]->process_frame_data(frame); 00854 } 00855 00856 /* Once processed, remove the frame from the buffer */ 00857 _framebuf_app.free_frame(frame); 00858 } 00859 00860 const uint32_t dropped_frames = _framebuf_app.get_dropped_frames_count(); 00861 if (dropped_frames != 0) { 00862 digi_log(LogLevelWarning, "process_rx_frames: %d frames dropped!!!\r\n", dropped_frames); 00863 } 00864 00865 return dropped_frames; 00866 } 00867 00868 void XBee::register_modem_status_cb(modem_status_cb_t function) 00869 { 00870 if (_modem_status_handler == NULL) { 00871 _modem_status_handler = new FH_ModemStatus(); 00872 register_frame_handler(_modem_status_handler); 00873 } 00874 _modem_status_handler->register_modem_status_cb(function); 00875 } 00876 00877 void XBee::unregister_modem_status_cb() 00878 { 00879 if (_modem_status_handler != NULL) { 00880 _modem_status_handler->unregister_modem_status_cb(); 00881 unregister_frame_handler(_modem_status_handler); 00882 delete _modem_status_handler; 00883 _modem_status_handler = NULL; /* as delete does not set to NULL */ 00884 } 00885 } 00886 00887 int XBee::get_AI(void) 00888 { 00889 uint32_t atai; 00890 const AtCmdFrame::AtCmdResp status = get_param("AI", &atai); 00891 00892 if (status != AtCmdFrame::AtCmdRespOk) { 00893 digi_log(LogLevelError, "get_association_indication() failed with %d\r\n", status); 00894 return -1; 00895 } 00896 return atai; 00897 }
Generated on Thu Jul 14 2022 04:53:34 by
