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