SADSD
Dependencies: DigiLogger
Fork of XBeeLib_vs 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:10:43 by 1.7.2