Lorenzo Maiorfi / XBeeLib_Fixed

Dependents:   XBeeZB_Receive_Data

Fork of XBeeLib by Digi International Inc.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers XBee.cpp Source File

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 }