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