Library to easily communicate with XBee modules.

Dependencies:   DigiLogger

Dependents:   WaterLogger XbeeGateway XBee_Cooker ProjetReceiver ... more

Use XBee radio modules to easily improve your project with wireless connectivity. You can enable entire networks of connected devices. XBees can exchange data with other modules in the network and configure remote modules as well as trigger actions or collect sensor data on XBee nodes without needing additional external microcontrollers. Using this documentation and configuration tools with XBee modules, it is easy to develop these types of applications and more.

/media/uploads/spastor/xbee-xbeepro-series1.jpg

The XBee mbed Library is a ready-to-import mbed extension that dramatically reduces development time for XBee projects on the mbed platforms. There are many modular examples, making it an easy and smooth process to add wireless networking to a whole range of useful applications.

Info

Currently 802.15.4 (Series 1 and 2), ZigBee (Series 2) and DigiMesh (Series 1 and 2) modules are supported. The libraries can be extended to support other protocols like DigiMesh point-to-point, WiFi, etc.

User manual

The user manual can be found at this project's Wiki pages:

  1. Configuring the library
  2. Debugging the library
  3. Initializing modules
  4. Resetting the local module
  5. Receiving Data from other module
  6. Sending data to another module
  7. Discovering nodes in the network
  8. Configuring local and remote modules
  9. Handling modem status changes
  10. Handling remote modules DIOs, ADCs and PWMs
  11. Handling IO Data Samples from other module
  12. Radio Power Management

Ready to use examples

There are a lot of ready to use examples to get started quickly.
Make sure you have a valid example setup before running the examples:

Examples for ZigBee modules

Import programXBeeZB_Receive_Data

ZigBee Receive Data example for mbed XBeeLib By Digi

Import programXBeeZB_Send_Data

ZigBee Send Data example for mbed XBeeLib By Digi

Import programXBeeZB_module_config

ZigBee network configuration example for mbed XBeeLib By Digi

Import programXBeeZB_AT_Commands

ZigBee AT Commands example for mbed XBeeLib By Digi

Import programXBeeZB_dio_adc

ZigBee DIOs and ADCs example for mbed XBeeLib By Digi

Import programXBeeZB_IO_Sample_Callback

ZigBee IO Sampling Callback example for mbed XBeeLib By Digi

Import programXBeeZB_modem_status

ZigBee Modem Status example for mbed XBeeLib By Digi

Import programXBeeZB_node_discovery

ZigBee Node Discovery example for mbed XBeeLib By Digi

Import programXBeeZB_power_mngmnt_cyclic_sleep

ZigBee Power Management using Cyclic Sleep example for mbed XBeeLib By Digi

Import programXBeeZB_power_mngmnt_pin_sleep

ZigBee Power Management using Pin Sleep example for mbed XBeeLib By Digi

Examples for 802.15.4 modules

Import programXBee802_Receive_Data

802.15.4 Receive Data example for mbed XBeeLib By Digi

Import programXBee802_Send_Data

802.15.4 Send Data example for mbed XBeeLib By Digi

Import programXBee802_module_config

802.15.4 network configuration example for mbed XBeeLib By Digi

Import programXBee802_AT_Commands

802.15.4 AT Commands example for mbed XBeeLib By Digi

Import programXBee802_dio_adc_pwm

802.15.4 DIOs, ADCs and PWM example for mbed XBeeLib By Digi

Import programXBee802_IO_Sample_Callback

802.15.4 IO Sampling Callback example for mbed XBeeLib By Digi

Import programXBee802_node_discovery

802.15.4 Node Discovery example for mbed XBeeLib By Digi

Import programXBee802_power_mngmnt_cyclic_sleep

802.15.4 Power Management using Cyclic Sleep example for mbed XBeeLib By Digi

Import programXBee802_power_mngmnt_pin_sleep

802.15.4 Power Management using Pin Sleep example for mbed XBeeLib By Digi

Examples for DigiMesh modules

Import programXBeeDM_Receive_Data

DigiMesh Receive Data example for mbed XBeeLib By Digi

Import programXBeeDM_Send_Data

DigiMesh Send Data example for mbed XBeeLib By Digi

Import programXBeeDM_module_config

DigiMesh network configuration example for mbed XBeeLib By Digi

Import programXBeeDM_AT_Commands

DigiMesh AT Commands example for mbed XBeeLib By Digi

Import programXBeeDM_dio_adc_pwm

DigiMEsh DIOs, ADCs and PWMs example for mbed XBeeLib By Digi

Import programXBeeDM_IO_Sample_Callback

DigiMesh IO Sampling Callback example for mbed XBeeLib By Digi

Import programXBeeDM_modem_status

DigiMesh Modem Status example for mbed XBeeLib By Digi

Import programXBeeDM_node_discovery

DigiMesh Node Discovery example for mbed XBeeLib By Digi

Import programXBeeDM_power_mngmnt_asyncr_cyclic_sleep

DigiMesh Power Management using Asynchronous Cyclic Sleep example for mbed XBeeLib By Digi

Import programXBeeDM_power_mngmnt_pin_sleep

DigiMesh Power Management using Pin Sleep example for mbed XBeeLib By Digi

Committer:
hbujanda
Date:
Fri Jul 29 13:10:07 2016 +0200
Revision:
9:780db84ce891
Parent:
6:06522f3a6642
Automatic upload

Who changed what in which revision?

UserRevisionLine numberNew contents of line
spastor 0:fcaad0dfa051 1 /**
spastor 0:fcaad0dfa051 2 * Copyright (c) 2015 Digi International Inc.,
spastor 0:fcaad0dfa051 3 * All rights not expressly granted are reserved.
spastor 0:fcaad0dfa051 4 *
spastor 0:fcaad0dfa051 5 * This Source Code Form is subject to the terms of the Mozilla Public
spastor 0:fcaad0dfa051 6 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
spastor 0:fcaad0dfa051 7 * You can obtain one at http://mozilla.org/MPL/2.0/.
spastor 0:fcaad0dfa051 8 *
spastor 0:fcaad0dfa051 9 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
spastor 0:fcaad0dfa051 10 * =======================================================================
spastor 0:fcaad0dfa051 11 */
spastor 0:fcaad0dfa051 12
spastor 0:fcaad0dfa051 13 #include "XBeeLib.h"
spastor 0:fcaad0dfa051 14 #include "FrameHandlers/FH_ModemStatus.h"
spastor 0:fcaad0dfa051 15
spastor 0:fcaad0dfa051 16 /* States for the state machine that processes incoming data on the serial port */
spastor 0:fcaad0dfa051 17 #define WAITING_FOR_START_FRAME (0)
spastor 0:fcaad0dfa051 18 #define WAITING_FOR_LENGTH_MSB (1)
spastor 0:fcaad0dfa051 19 #define WAITING_FOR_LENGTH_LSB (2)
spastor 0:fcaad0dfa051 20 #define WAITING_FOR_PAYLOAD (3)
spastor 0:fcaad0dfa051 21 #define WAITING_FOR_CHECKSUM (4)
spastor 0:fcaad0dfa051 22
spastor 0:fcaad0dfa051 23 #define IS_API2() (_mode == ModeAPI2)
spastor 0:fcaad0dfa051 24 #define IS_API_MODE() (_mode == ModeAPI1 || _mode == ModeAPI2)
spastor 0:fcaad0dfa051 25
spastor 0:fcaad0dfa051 26 using namespace XBeeLib;
spastor 0:fcaad0dfa051 27
spastor 4:629712865107 28 #if defined(FRAME_BUFFER_SIZE_SYNCR)
spastor 4:629712865107 29 #if FRAME_BUFFER_SIZE_SYNCR < 2
spastor 4:629712865107 30 #error "FRAME_BUFFER_SIZE_SYNCR must be at least 2"
spastor 4:629712865107 31 #endif
spastor 4:629712865107 32 #else
spastor 4:629712865107 33 #define FRAME_BUFFER_SIZE_SYNCR 1
spastor 4:629712865107 34 #endif
spastor 4:629712865107 35
spastor 4:629712865107 36 #define MAX_FRAME_PAYLOAD_LEN_SYNCR (1 /* type */ + 1 /* id */ + 2 /* at cmd*/ + 1 /* status */ + 2 /* MY sender */ + \
spastor 4:629712865107 37 8 /* 64b sender */ + 20 /* max id */ + 1 /* null ter */ + 2 /* MY parent */ + 1 /* dev type */ + \
spastor 4:629712865107 38 1 /* source event */ + 2 /* prof. id */ + 2 /* man. id */)
spastor 4:629712865107 39
spastor 4:629712865107 40 FrameBuffer XBee::_framebuf_app(FRAME_BUFFER_SIZE, MAX_FRAME_PAYLOAD_LEN);
spastor 4:629712865107 41 FrameBuffer XBee::_framebuf_syncr(FRAME_BUFFER_SIZE_SYNCR, MAX_FRAME_PAYLOAD_LEN_SYNCR);
spastor 0:fcaad0dfa051 42
hbujanda 2:2ee1b6d51df2 43 #if defined(DEVICE_SERIAL_FC)
hbujanda 2:2ee1b6d51df2 44 bool XBee::check_radio_flow_control()
hbujanda 2:2ee1b6d51df2 45 {
hbujanda 2:2ee1b6d51df2 46 AtCmdFrame::AtCmdResp cmdresp;
hbujanda 2:2ee1b6d51df2 47 uint32_t value;
hbujanda 2:2ee1b6d51df2 48
hbujanda 2:2ee1b6d51df2 49 if (_serial_flow_type == SerialBase::RTSCTS || _serial_flow_type == SerialBase::CTS) {
hbujanda 2:2ee1b6d51df2 50 cmdresp = get_param("D7", &value);
hbujanda 2:2ee1b6d51df2 51 if (cmdresp != AtCmdFrame::AtCmdRespOk) {
hbujanda 2:2ee1b6d51df2 52 digi_log(LogLevelError, "Could not read CTS configuration. Error %d\r\n", cmdresp);
hbujanda 2:2ee1b6d51df2 53 return false;
spastor 4:629712865107 54 } else if (value != 1) {
hbujanda 2:2ee1b6d51df2 55 digi_log(LogLevelError, "Bad CTS configuration. Radio 'D7' param is %d and should be 1\r\n", value);
hbujanda 2:2ee1b6d51df2 56 return false;
hbujanda 2:2ee1b6d51df2 57 }
hbujanda 2:2ee1b6d51df2 58 }
hbujanda 2:2ee1b6d51df2 59
hbujanda 2:2ee1b6d51df2 60 if (_serial_flow_type == SerialBase::RTSCTS || _serial_flow_type == SerialBase::RTS) {
hbujanda 2:2ee1b6d51df2 61 cmdresp = get_param("D6", &value);
hbujanda 2:2ee1b6d51df2 62 if (cmdresp != AtCmdFrame::AtCmdRespOk) {
hbujanda 2:2ee1b6d51df2 63 digi_log(LogLevelError, "Could not read RTS configuration. Error %d\r\n", cmdresp);
hbujanda 2:2ee1b6d51df2 64 return false;
spastor 4:629712865107 65 } else if (value != 1) {
hbujanda 2:2ee1b6d51df2 66 digi_log(LogLevelError, "Bad RTS configuration. Radio 'D6' param is %d and should be 1\r\n", value);
hbujanda 2:2ee1b6d51df2 67 return false;
hbujanda 2:2ee1b6d51df2 68 }
hbujanda 2:2ee1b6d51df2 69 }
hbujanda 2:2ee1b6d51df2 70
hbujanda 2:2ee1b6d51df2 71 return true;
hbujanda 2:2ee1b6d51df2 72 }
hbujanda 2:2ee1b6d51df2 73 #endif
hbujanda 2:2ee1b6d51df2 74
spastor 0:fcaad0dfa051 75 /* Class constructor */
spastor 0:fcaad0dfa051 76 XBee::XBee(PinName tx, PinName rx, PinName reset, PinName rts, PinName cts, int baud) :
spastor 4:629712865107 77 _mode(ModeUnknown), _hw_version(0), _fw_version(0), _timeout_ms(SYNC_OPS_TIMEOUT_MS), _dev_addr64(ADDR64_UNASSIGNED),
spastor 4:629712865107 78 _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)
spastor 0:fcaad0dfa051 79 {
spastor 0:fcaad0dfa051 80
spastor 0:fcaad0dfa051 81 if (reset != NC) {
hbujanda 1:794d1d3e4a08 82 _reset = new DigitalOut(reset, 1);
spastor 0:fcaad0dfa051 83 }
spastor 0:fcaad0dfa051 84
spastor 0:fcaad0dfa051 85 _uart = new RawSerial(tx, rx);
spastor 0:fcaad0dfa051 86 _uart->baud(baud);
hbujanda 1:794d1d3e4a08 87
hbujanda 1:794d1d3e4a08 88 _serial_flow_type = SerialBase::Disabled;
spastor 0:fcaad0dfa051 89 #if defined(DEVICE_SERIAL_FC)
spastor 0:fcaad0dfa051 90 if (rts != NC && cts != NC) {
hbujanda 1:794d1d3e4a08 91 _serial_flow_type = SerialBase::RTSCTS;
spastor 4:629712865107 92 _uart->set_flow_control(_serial_flow_type, rts, cts);
spastor 4:629712865107 93 } else if (rts != NC && cts == NC) {
hbujanda 1:794d1d3e4a08 94 _serial_flow_type = SerialBase::RTS;
hbujanda 1:794d1d3e4a08 95 _uart->set_flow_control(_serial_flow_type, rts);
spastor 4:629712865107 96 } else if (rts == NC && cts != NC) {
hbujanda 1:794d1d3e4a08 97 _serial_flow_type = SerialBase::CTS;
hbujanda 1:794d1d3e4a08 98 _uart->set_flow_control(_serial_flow_type, cts);
spastor 0:fcaad0dfa051 99 }
spastor 0:fcaad0dfa051 100 #endif
spastor 0:fcaad0dfa051 101 /* Enable the reception of bytes on the serial interface by providing a cb */
spastor 0:fcaad0dfa051 102 _uart->attach(this, &XBee::uart_read_cb, Serial::RxIrq);
spastor 0:fcaad0dfa051 103
spastor 0:fcaad0dfa051 104 for (int i = 0; i < MAX_FRAME_HANDLERS; i++) {
spastor 0:fcaad0dfa051 105 _fhandlers[i] = NULL;
spastor 0:fcaad0dfa051 106 }
spastor 0:fcaad0dfa051 107 }
spastor 0:fcaad0dfa051 108
spastor 0:fcaad0dfa051 109 /* Class destructor */
spastor 0:fcaad0dfa051 110 XBee::~XBee()
spastor 0:fcaad0dfa051 111 {
spastor 0:fcaad0dfa051 112 unregister_modem_status_cb();
spastor 0:fcaad0dfa051 113
spastor 0:fcaad0dfa051 114 if (_uart != NULL) {
spastor 0:fcaad0dfa051 115 delete _uart;
spastor 0:fcaad0dfa051 116 }
spastor 0:fcaad0dfa051 117 if (_reset != NULL) {
spastor 0:fcaad0dfa051 118 delete _reset;
spastor 0:fcaad0dfa051 119 }
spastor 0:fcaad0dfa051 120 }
spastor 0:fcaad0dfa051 121
spastor 0:fcaad0dfa051 122 #include <inttypes.h>
spastor 0:fcaad0dfa051 123
spastor 0:fcaad0dfa051 124 RadioStatus XBee::init(void)
spastor 0:fcaad0dfa051 125 {
spastor 0:fcaad0dfa051 126 AtCmdFrame::AtCmdResp cmd_resp;
spastor 0:fcaad0dfa051 127 uint32_t var32;
spastor 0:fcaad0dfa051 128
spastor 0:fcaad0dfa051 129 _initializing = true;
spastor 0:fcaad0dfa051 130
spastor 4:629712865107 131 const unsigned int max_reset_retries = 3;
spastor 4:629712865107 132 RadioStatus reset_status;
spastor 4:629712865107 133 for (unsigned int i = 0; i < max_reset_retries; i++) {
spastor 4:629712865107 134 reset_status = device_reset();
spastor 4:629712865107 135 if (reset_status == Success) {
spastor 4:629712865107 136 break;
spastor 4:629712865107 137 }
spastor 4:629712865107 138 }
spastor 4:629712865107 139 if (reset_status != Success) {
spastor 4:629712865107 140 return reset_status;
spastor 4:629712865107 141 }
spastor 0:fcaad0dfa051 142
spastor 0:fcaad0dfa051 143 /* Check if radio is in API1 or API2 _mode */
spastor 0:fcaad0dfa051 144 cmd_resp = get_param("AP", &var32);
spastor 4:629712865107 145 if (cmd_resp != AtCmdFrame::AtCmdRespOk) {
spastor 0:fcaad0dfa051 146 return Failure;
spastor 4:629712865107 147 }
spastor 0:fcaad0dfa051 148 _mode = (RadioMode)var32;
spastor 0:fcaad0dfa051 149
spastor 0:fcaad0dfa051 150 /* Read the device unique 64b address */
spastor 0:fcaad0dfa051 151 uint32_t serialn_high, serialn_low;
spastor 0:fcaad0dfa051 152 cmd_resp = get_param("SH", &serialn_high);
spastor 4:629712865107 153 if (cmd_resp != AtCmdFrame::AtCmdRespOk) {
spastor 0:fcaad0dfa051 154 return Failure;
spastor 4:629712865107 155 }
spastor 4:629712865107 156
spastor 0:fcaad0dfa051 157 cmd_resp = get_param("SL", &serialn_low);
spastor 4:629712865107 158 if (cmd_resp != AtCmdFrame::AtCmdRespOk) {
spastor 0:fcaad0dfa051 159 return Failure;
spastor 4:629712865107 160 }
spastor 0:fcaad0dfa051 161
spastor 0:fcaad0dfa051 162 _dev_addr64 = ((uint64_t)serialn_high << 32) | serialn_low;
spastor 0:fcaad0dfa051 163
spastor 0:fcaad0dfa051 164 /* Read some important parameters */
spastor 0:fcaad0dfa051 165 cmd_resp = get_param("HV", &var32);
spastor 4:629712865107 166 if (cmd_resp != AtCmdFrame::AtCmdRespOk) {
spastor 0:fcaad0dfa051 167 return Failure;
spastor 4:629712865107 168 }
spastor 0:fcaad0dfa051 169 _hw_version = var32;
spastor 0:fcaad0dfa051 170
spastor 0:fcaad0dfa051 171 cmd_resp = get_param("VR", &var32);
spastor 4:629712865107 172 if (cmd_resp != AtCmdFrame::AtCmdRespOk) {
spastor 0:fcaad0dfa051 173 return Failure;
spastor 4:629712865107 174 }
spastor 0:fcaad0dfa051 175 _fw_version = var32;
spastor 0:fcaad0dfa051 176
spastor 0:fcaad0dfa051 177 digi_log(LogLevelInfo, "mode: %02x\r\n", (uint8_t)_mode);
spastor 0:fcaad0dfa051 178 digi_log(LogLevelInfo, "HV: %04x\r\n", _hw_version);
spastor 0:fcaad0dfa051 179 digi_log(LogLevelInfo, "VR: %04x\r\n", _fw_version);
spastor 0:fcaad0dfa051 180 digi_log(LogLevelInfo, "ADDR64: %08x:%08x\r\n", UINT64_HI32(_dev_addr64), UINT64_LO32(_dev_addr64));
spastor 0:fcaad0dfa051 181
hbujanda 2:2ee1b6d51df2 182 #if defined(DEVICE_SERIAL_FC)
hbujanda 2:2ee1b6d51df2 183 bool valid_radio_fc = check_radio_flow_control();
hbujanda 2:2ee1b6d51df2 184 assert(valid_radio_fc == true);
hbujanda 2:2ee1b6d51df2 185 #endif
hbujanda 2:2ee1b6d51df2 186
spastor 0:fcaad0dfa051 187 _initializing = false;
spastor 0:fcaad0dfa051 188 if (_modem_status_handler != NULL) {
spastor 0:fcaad0dfa051 189 const ApiFrame frame = ApiFrame(ApiFrame::AtModemStatus, (uint8_t *)&_modem_status, sizeof(_modem_status));
spastor 0:fcaad0dfa051 190 _modem_status_handler->process_frame_data(&frame);
spastor 4:629712865107 191 }
spastor 0:fcaad0dfa051 192
spastor 0:fcaad0dfa051 193 return Success;
spastor 0:fcaad0dfa051 194 }
spastor 0:fcaad0dfa051 195
spastor 0:fcaad0dfa051 196 uint64_t XBee::get_addr64() const
spastor 0:fcaad0dfa051 197 {
spastor 0:fcaad0dfa051 198 return _dev_addr64;
spastor 0:fcaad0dfa051 199 }
spastor 0:fcaad0dfa051 200
spastor 0:fcaad0dfa051 201 RadioStatus XBee::hardware_reset()
spastor 0:fcaad0dfa051 202 {
spastor 0:fcaad0dfa051 203 if (_reset != NULL) {
spastor 0:fcaad0dfa051 204 volatile uint16_t * const rst_cnt_p = &_hw_reset_cnt;
spastor 0:fcaad0dfa051 205 const uint16_t init_rst_cnt = *rst_cnt_p;
spastor 0:fcaad0dfa051 206 *_reset = 0;
spastor 0:fcaad0dfa051 207 wait_ms(10);
spastor 0:fcaad0dfa051 208 *_reset = 1;
spastor 0:fcaad0dfa051 209 return wait_for_module_to_reset(rst_cnt_p, init_rst_cnt);
spastor 0:fcaad0dfa051 210 }
spastor 0:fcaad0dfa051 211
spastor 0:fcaad0dfa051 212 return Failure;
spastor 0:fcaad0dfa051 213 }
spastor 0:fcaad0dfa051 214
spastor 0:fcaad0dfa051 215 RadioStatus XBee::device_reset()
spastor 0:fcaad0dfa051 216 {
spastor 4:629712865107 217 if (hardware_reset() == Success) {
spastor 0:fcaad0dfa051 218 return Success;
spastor 4:629712865107 219 }
spastor 0:fcaad0dfa051 220
spastor 0:fcaad0dfa051 221 return software_reset();
spastor 0:fcaad0dfa051 222 }
spastor 0:fcaad0dfa051 223
spastor 0:fcaad0dfa051 224 RadioStatus XBee::wait_for_module_to_reset(volatile uint16_t *rst_cnt_p, uint16_t init_rst_cnt)
spastor 0:fcaad0dfa051 225 {
spastor 4:629712865107 226 Timer timer = Timer();
spastor 4:629712865107 227 timer.start();
spastor 4:629712865107 228
spastor 4:629712865107 229 while (*rst_cnt_p == init_rst_cnt && timer.read_ms() < RESET_TIMEOUT_MS) {
spastor 0:fcaad0dfa051 230 wait_ms(100);
spastor 0:fcaad0dfa051 231 }
spastor 0:fcaad0dfa051 232
spastor 4:629712865107 233 if (*rst_cnt_p == init_rst_cnt) {
spastor 0:fcaad0dfa051 234 digi_log(LogLevelWarning, "Reset Timeout\r\n");
spastor 0:fcaad0dfa051 235 return Failure;
spastor 0:fcaad0dfa051 236 }
spastor 0:fcaad0dfa051 237 return Success;
spastor 0:fcaad0dfa051 238 }
spastor 0:fcaad0dfa051 239
spastor 0:fcaad0dfa051 240 /** Callback function called when data is received on the serial port */
spastor 0:fcaad0dfa051 241 void XBee::uart_read_cb(void)
spastor 0:fcaad0dfa051 242 {
spastor 0:fcaad0dfa051 243 static uint8_t rxstate = WAITING_FOR_START_FRAME;
spastor 0:fcaad0dfa051 244 static uint16_t framelen = 0;
spastor 0:fcaad0dfa051 245 static uint16_t bytes_read;
spastor 0:fcaad0dfa051 246 static uint8_t chksum;
spastor 0:fcaad0dfa051 247 static ApiFrame *frame = NULL;
spastor 0:fcaad0dfa051 248 static bool last_byte_escaped = false;
spastor 4:629712865107 249 static FrameBuffer * framebuf = NULL;
spastor 4:629712865107 250
spastor 0:fcaad0dfa051 251 while (_uart->readable()) {
spastor 0:fcaad0dfa051 252 uint8_t data = _uart->getc();
spastor 4:629712865107 253
spastor 0:fcaad0dfa051 254 if (IS_API2() && rxstate != WAITING_FOR_START_FRAME) {
spastor 0:fcaad0dfa051 255 if (last_byte_escaped) {
spastor 0:fcaad0dfa051 256 data = data ^ DR_ESCAPE_XOR_BYTE;
spastor 0:fcaad0dfa051 257 last_byte_escaped = false;
spastor 0:fcaad0dfa051 258 } else if (data == DR_ESCAPE_BYTE) {
spastor 0:fcaad0dfa051 259 last_byte_escaped = true;
spastor 0:fcaad0dfa051 260 continue;
spastor 0:fcaad0dfa051 261 }
spastor 0:fcaad0dfa051 262 }
spastor 4:629712865107 263
spastor 0:fcaad0dfa051 264 switch (rxstate) {
spastor 0:fcaad0dfa051 265 case WAITING_FOR_START_FRAME:
spastor 4:629712865107 266 if (data == DR_START_OF_FRAME) {
spastor 0:fcaad0dfa051 267 rxstate = WAITING_FOR_LENGTH_MSB;
spastor 4:629712865107 268 }
spastor 0:fcaad0dfa051 269 break;
spastor 4:629712865107 270
spastor 0:fcaad0dfa051 271 case WAITING_FOR_LENGTH_MSB:
spastor 0:fcaad0dfa051 272 framelen = data << 8;
spastor 0:fcaad0dfa051 273 rxstate = WAITING_FOR_LENGTH_LSB;
spastor 0:fcaad0dfa051 274 break;
spastor 0:fcaad0dfa051 275
spastor 0:fcaad0dfa051 276 case WAITING_FOR_LENGTH_LSB:
spastor 0:fcaad0dfa051 277 framelen |= data;
spastor 4:629712865107 278 rxstate = WAITING_FOR_PAYLOAD;
spastor 0:fcaad0dfa051 279 bytes_read = 0;
spastor 0:fcaad0dfa051 280 chksum = 0;
spastor 0:fcaad0dfa051 281 /* Sanity check that the frame is smaller than... */
spastor 0:fcaad0dfa051 282 if (framelen > MAX_FRAME_PAYLOAD_LEN) {
spastor 0:fcaad0dfa051 283 digi_log(LogLevelDebug, "framelen=%d too long\r\n", framelen);
spastor 0:fcaad0dfa051 284 digi_log(LogLevelWarning, "Frame dropped, frame too long. Increase MAX_FRAME_PAYLOAD_LEN define\r\n");
spastor 0:fcaad0dfa051 285 rxstate = WAITING_FOR_START_FRAME;
spastor 0:fcaad0dfa051 286 }
spastor 0:fcaad0dfa051 287 break;
spastor 0:fcaad0dfa051 288
spastor 0:fcaad0dfa051 289 case WAITING_FOR_PAYLOAD:
spastor 4:629712865107 290 #define CACHED_SIZE 3
spastor 4:629712865107 291 static uint8_t frame_cached[CACHED_SIZE];
spastor 4:629712865107 292
spastor 4:629712865107 293 if (framelen <= CACHED_SIZE) {
spastor 4:629712865107 294 if (!bytes_read) {
spastor 4:629712865107 295 const ApiFrame::ApiFrameType frame_type = (ApiFrame::ApiFrameType)data;
spastor 4:629712865107 296 switch (frame_type)
spastor 4:629712865107 297 {
hbujanda 6:06522f3a6642 298 case ApiFrame::AtCmdResp:
hbujanda 6:06522f3a6642 299 case ApiFrame::RemoteCmdResp:
hbujanda 6:06522f3a6642 300 case ApiFrame::TxStatusZBDM:
hbujanda 6:06522f3a6642 301 case ApiFrame::TxStatus:
spastor 4:629712865107 302 framebuf = &_framebuf_syncr;
spastor 4:629712865107 303 break;
spastor 4:629712865107 304
hbujanda 6:06522f3a6642 305 case ApiFrame::RxPacket64Bit:
hbujanda 6:06522f3a6642 306 case ApiFrame::RxPacket16Bit:
hbujanda 6:06522f3a6642 307 case ApiFrame::Io64Bit:
hbujanda 6:06522f3a6642 308 case ApiFrame::Io16Bit:
hbujanda 6:06522f3a6642 309 case ApiFrame::AtModemStatus:
hbujanda 6:06522f3a6642 310 case ApiFrame::RxPacketAO0:
hbujanda 6:06522f3a6642 311 case ApiFrame::IoSampleRxZBDM:
spastor 4:629712865107 312 framebuf = &_framebuf_app;
spastor 4:629712865107 313 break;
spastor 4:629712865107 314
hbujanda 6:06522f3a6642 315 case ApiFrame::RxPacketAO1:
hbujanda 6:06522f3a6642 316 case ApiFrame::SensorRxIndAO0:
hbujanda 6:06522f3a6642 317 case ApiFrame::NodeIdentIndAO0:
hbujanda 6:06522f3a6642 318 case ApiFrame::OtaFwUpStatus:
hbujanda 6:06522f3a6642 319 case ApiFrame::RouteRecInd:
hbujanda 6:06522f3a6642 320 case ApiFrame::Many2OneRRInd:
hbujanda 6:06522f3a6642 321 case ApiFrame::TxReq64Bit:
hbujanda 6:06522f3a6642 322 case ApiFrame::TxReq16Bit:
hbujanda 6:06522f3a6642 323 case ApiFrame::AtCmd:
hbujanda 6:06522f3a6642 324 case ApiFrame::AtCmdQueuePV:
hbujanda 6:06522f3a6642 325 case ApiFrame::TxReqZBDM:
hbujanda 6:06522f3a6642 326 case ApiFrame::ExpAddrCmd:
hbujanda 6:06522f3a6642 327 case ApiFrame::RemoteCmdReq:
hbujanda 6:06522f3a6642 328 case ApiFrame::CreateSrcRoute:
hbujanda 6:06522f3a6642 329 case ApiFrame::Invalid:
hbujanda 6:06522f3a6642 330 case ApiFrame::RouteInfo:
hbujanda 6:06522f3a6642 331 case ApiFrame::AggregateAddr:
spastor 4:629712865107 332 framebuf = NULL;
spastor 4:629712865107 333 break;
spastor 4:629712865107 334 }
spastor 4:629712865107 335
spastor 4:629712865107 336 if (framebuf == NULL) {
spastor 4:629712865107 337 digi_log(LogLevelWarning, "Discarding not supported frame type %02x\r\n", frame_type);
spastor 4:629712865107 338 rxstate = WAITING_FOR_START_FRAME;
spastor 4:629712865107 339 } else {
spastor 4:629712865107 340 frame = framebuf->get_next_free_frame();
spastor 4:629712865107 341 if (frame == NULL) {
spastor 4:629712865107 342 /* It's not possible to achive this condition as we discard older frames and only one frame can be used by syncr. commands */
spastor 4:629712865107 343 assert(frame != NULL);
spastor 4:629712865107 344 rxstate = WAITING_FOR_START_FRAME;
spastor 4:629712865107 345 } else {
spastor 4:629712865107 346 frame->set_data_len(framelen - 1);
spastor 4:629712865107 347 }
spastor 4:629712865107 348
spastor 4:629712865107 349 frame->set_frame_type(frame_type);
spastor 4:629712865107 350 }
spastor 4:629712865107 351 } else {
spastor 4:629712865107 352 frame->set_data(data, bytes_read - 1);
spastor 4:629712865107 353 }
spastor 4:629712865107 354 chksum += data;
spastor 4:629712865107 355 bytes_read++;
spastor 4:629712865107 356 if (bytes_read == framelen) {
spastor 4:629712865107 357 rxstate = WAITING_FOR_CHECKSUM;
spastor 4:629712865107 358 }
spastor 4:629712865107 359 break;
spastor 4:629712865107 360 }
spastor 4:629712865107 361
spastor 4:629712865107 362
spastor 4:629712865107 363 if (bytes_read < CACHED_SIZE) {
spastor 4:629712865107 364 frame_cached[bytes_read] = data;
spastor 4:629712865107 365 }
spastor 4:629712865107 366 else if (bytes_read == CACHED_SIZE) {
spastor 4:629712865107 367 const ApiFrame::ApiFrameType frame_type = (ApiFrame::ApiFrameType)frame_cached[0];
spastor 4:629712865107 368 switch (frame_type)
spastor 4:629712865107 369 {
hbujanda 6:06522f3a6642 370 case ApiFrame::RemoteCmdResp:
hbujanda 6:06522f3a6642 371 case ApiFrame::TxStatusZBDM:
hbujanda 6:06522f3a6642 372 case ApiFrame::TxStatus:
spastor 4:629712865107 373 framebuf = &_framebuf_syncr;
spastor 4:629712865107 374 break;
spastor 4:629712865107 375
hbujanda 6:06522f3a6642 376 case ApiFrame::AtCmdResp:
spastor 4:629712865107 377 if ((frame_cached[1] != _node_by_ni_frame_id ) && (frame_cached[2] == 'N') && (data == 'D'))
spastor 4:629712865107 378 {
spastor 4:629712865107 379 framebuf = &_framebuf_app;
spastor 4:629712865107 380 } else {
spastor 4:629712865107 381 framebuf = &_framebuf_syncr;
spastor 4:629712865107 382 }
spastor 4:629712865107 383 break;
spastor 4:629712865107 384
hbujanda 6:06522f3a6642 385 case ApiFrame::RxPacket64Bit:
hbujanda 6:06522f3a6642 386 case ApiFrame::RxPacket16Bit:
hbujanda 6:06522f3a6642 387 case ApiFrame::Io64Bit:
hbujanda 6:06522f3a6642 388 case ApiFrame::Io16Bit:
hbujanda 6:06522f3a6642 389 case ApiFrame::AtModemStatus:
hbujanda 6:06522f3a6642 390 case ApiFrame::RxPacketAO0:
hbujanda 6:06522f3a6642 391 case ApiFrame::IoSampleRxZBDM:
spastor 4:629712865107 392 framebuf = &_framebuf_app;
spastor 4:629712865107 393 break;
spastor 4:629712865107 394
hbujanda 6:06522f3a6642 395 case ApiFrame::RxPacketAO1:
hbujanda 6:06522f3a6642 396 case ApiFrame::SensorRxIndAO0:
hbujanda 6:06522f3a6642 397 case ApiFrame::NodeIdentIndAO0:
hbujanda 6:06522f3a6642 398 case ApiFrame::OtaFwUpStatus:
hbujanda 6:06522f3a6642 399 case ApiFrame::RouteRecInd:
hbujanda 6:06522f3a6642 400 case ApiFrame::Many2OneRRInd:
hbujanda 6:06522f3a6642 401 case ApiFrame::TxReq64Bit:
hbujanda 6:06522f3a6642 402 case ApiFrame::TxReq16Bit:
hbujanda 6:06522f3a6642 403 case ApiFrame::AtCmd:
hbujanda 6:06522f3a6642 404 case ApiFrame::AtCmdQueuePV:
hbujanda 6:06522f3a6642 405 case ApiFrame::TxReqZBDM:
hbujanda 6:06522f3a6642 406 case ApiFrame::ExpAddrCmd:
hbujanda 6:06522f3a6642 407 case ApiFrame::RemoteCmdReq:
hbujanda 6:06522f3a6642 408 case ApiFrame::CreateSrcRoute:
hbujanda 6:06522f3a6642 409 case ApiFrame::Invalid:
hbujanda 6:06522f3a6642 410 case ApiFrame::RouteInfo:
hbujanda 6:06522f3a6642 411 case ApiFrame::AggregateAddr:
spastor 4:629712865107 412 framebuf = NULL;
spastor 4:629712865107 413 break;
spastor 4:629712865107 414 }
spastor 4:629712865107 415
spastor 4:629712865107 416 if (framebuf == NULL) {
spastor 4:629712865107 417 digi_log(LogLevelWarning, "Discarding not supported frame type %02x\r\n", frame_type);
spastor 4:629712865107 418 rxstate = WAITING_FOR_START_FRAME;
spastor 4:629712865107 419 } else {
spastor 4:629712865107 420 frame = framebuf->get_next_free_frame();
spastor 4:629712865107 421 if (frame == NULL) {
spastor 4:629712865107 422 /* It's not possible to achive this condition as we discard older frames and only one frame can be used by syncr. commands */
spastor 4:629712865107 423 assert(frame != NULL);
spastor 4:629712865107 424 rxstate = WAITING_FOR_START_FRAME;
spastor 4:629712865107 425 } else {
spastor 4:629712865107 426 frame->set_data_len(framelen - 1);
spastor 4:629712865107 427 }
spastor 4:629712865107 428
spastor 4:629712865107 429 frame->set_frame_type(frame_type);
spastor 4:629712865107 430 frame->set_data(frame_cached[1], 0);
spastor 4:629712865107 431 frame->set_data(frame_cached[2], 1);
spastor 4:629712865107 432 frame->set_data(data, 2);
spastor 4:629712865107 433 }
spastor 4:629712865107 434 } else {
spastor 0:fcaad0dfa051 435 frame->set_data(data, bytes_read - 1);
spastor 0:fcaad0dfa051 436 }
spastor 0:fcaad0dfa051 437 chksum += data;
spastor 0:fcaad0dfa051 438 bytes_read++;
spastor 4:629712865107 439 if (bytes_read == framelen) {
spastor 0:fcaad0dfa051 440 rxstate = WAITING_FOR_CHECKSUM;
spastor 4:629712865107 441 }
spastor 0:fcaad0dfa051 442 break;
spastor 0:fcaad0dfa051 443
spastor 0:fcaad0dfa051 444 case WAITING_FOR_CHECKSUM:
spastor 0:fcaad0dfa051 445 chksum += data;
spastor 0:fcaad0dfa051 446 if (chksum == 0xFF) {
spastor 0:fcaad0dfa051 447 /* We got a valid frame!! */
spastor 0:fcaad0dfa051 448 frame->dump();
spastor 4:629712865107 449
spastor 0:fcaad0dfa051 450 /* If its a _modem status frame, process it to update the status info of the library.
spastor 0:fcaad0dfa051 451 * The frame is also queued to allow processing it other handlers registered.
spastor 0:fcaad0dfa051 452 * Note that radio_status_update() has to be fast to minimize the impact of processing
spastor 0:fcaad0dfa051 453 * the funcion here */
spastor 0:fcaad0dfa051 454 if (frame->get_frame_type() == ApiFrame::AtModemStatus) {
spastor 0:fcaad0dfa051 455 radio_status_update((AtCmdFrame::ModemStatus)frame->get_data_at(0));
spastor 4:629712865107 456 if (_initializing) {
spastor 4:629712865107 457 framebuf->free_frame(frame);
spastor 4:629712865107 458 } else {
spastor 4:629712865107 459 framebuf->complete_frame(frame);
spastor 4:629712865107 460 }
spastor 4:629712865107 461 } else {
spastor 4:629712865107 462 framebuf->complete_frame(frame);
spastor 0:fcaad0dfa051 463 /* Note, the frame will be released elsewhere, once it has been processed */
spastor 0:fcaad0dfa051 464 }
spastor 0:fcaad0dfa051 465 } else {
spastor 4:629712865107 466 framebuf->free_frame(frame);
spastor 0:fcaad0dfa051 467 digi_log(LogLevelWarning, "Checksum error, got %02x, %02x\r\n", data, chksum);
spastor 0:fcaad0dfa051 468 }
spastor 0:fcaad0dfa051 469 /* Intentional fall-through */
spastor 0:fcaad0dfa051 470 default:
spastor 0:fcaad0dfa051 471 rxstate = WAITING_FOR_START_FRAME;
spastor 0:fcaad0dfa051 472 break;
spastor 4:629712865107 473 }
spastor 0:fcaad0dfa051 474 }
spastor 0:fcaad0dfa051 475 /* TODO, signal the thread processing incoming frames */
spastor 0:fcaad0dfa051 476 }
spastor 0:fcaad0dfa051 477
spastor 0:fcaad0dfa051 478 /* This is a pure virtual function, but exists here because its called from this class to
spastor 4:629712865107 479 * to update the status of the object, and can be called before the construction of the
spastor 0:fcaad0dfa051 480 * object has been completed and the virtual functions filled */
spastor 0:fcaad0dfa051 481 void XBee::radio_status_update(AtCmdFrame::ModemStatus modem_status)
spastor 0:fcaad0dfa051 482 {
hbujanda 2:2ee1b6d51df2 483 UNUSED_PARAMETER(modem_status);
spastor 0:fcaad0dfa051 484 }
spastor 0:fcaad0dfa051 485
spastor 0:fcaad0dfa051 486 void XBee::set_timeout(uint16_t timeout_ms)
spastor 0:fcaad0dfa051 487 {
spastor 4:629712865107 488 this->_timeout_ms = timeout_ms;
spastor 0:fcaad0dfa051 489 }
spastor 0:fcaad0dfa051 490
spastor 0:fcaad0dfa051 491 uint16_t XBee::get_timeout(void) const
spastor 0:fcaad0dfa051 492 {
spastor 0:fcaad0dfa051 493 return _timeout_ms;
spastor 0:fcaad0dfa051 494 }
spastor 0:fcaad0dfa051 495
spastor 4:629712865107 496 ApiFrame * XBee::get_this_api_frame(uint8_t id, ApiFrame::ApiFrameType type,
spastor 0:fcaad0dfa051 497 ApiFrame::ApiFrameType type2)
spastor 0:fcaad0dfa051 498 {
spastor 4:629712865107 499 Timer timer = Timer();
spastor 4:629712865107 500 timer.start();
spastor 0:fcaad0dfa051 501
spastor 4:629712865107 502 while (timer.read_ms() < _timeout_ms) {
spastor 4:629712865107 503 ApiFrame * frame = _framebuf_syncr.get_next_complete_frame();
spastor 0:fcaad0dfa051 504 if (frame == NULL) {
spastor 0:fcaad0dfa051 505 wait_ms(10);
spastor 0:fcaad0dfa051 506 continue;
spastor 0:fcaad0dfa051 507 }
spastor 0:fcaad0dfa051 508
spastor 0:fcaad0dfa051 509 if ((frame->get_frame_type() != type) &&
spastor 0:fcaad0dfa051 510 (frame->get_frame_type() != type2)) {
spastor 4:629712865107 511 _framebuf_syncr.complete_frame(frame);
spastor 0:fcaad0dfa051 512 wait_ms(1);
spastor 0:fcaad0dfa051 513 continue;
spastor 0:fcaad0dfa051 514 }
spastor 0:fcaad0dfa051 515
spastor 4:629712865107 516 if (frame->get_data_at(ATCMD_RESP_FRAME_ID_OFFSET) != id) {
spastor 4:629712865107 517 _framebuf_syncr.complete_frame(frame);
spastor 4:629712865107 518 wait_ms(1);
spastor 4:629712865107 519 continue;
spastor 4:629712865107 520 }
spastor 4:629712865107 521
spastor 4:629712865107 522 /* frame found */
spastor 0:fcaad0dfa051 523 return frame;
spastor 0:fcaad0dfa051 524 }
spastor 4:629712865107 525
spastor 0:fcaad0dfa051 526 digi_log(LogLevelWarning, "Frame type: %02x, id: %02x, timeout\r\n", (uint8_t)type, id);
spastor 0:fcaad0dfa051 527
spastor 0:fcaad0dfa051 528 return NULL;
spastor 0:fcaad0dfa051 529 }
spastor 0:fcaad0dfa051 530
spastor 0:fcaad0dfa051 531 void XBee::send_byte_escaping_if(uint8_t data)
spastor 0:fcaad0dfa051 532 {
spastor 0:fcaad0dfa051 533 if (IS_API2()) {
spastor 0:fcaad0dfa051 534 switch (data) {
spastor 0:fcaad0dfa051 535 case DR_START_OF_FRAME:
spastor 0:fcaad0dfa051 536 case DR_ESCAPE_BYTE:
spastor 0:fcaad0dfa051 537 case DR_XON_BYTE:
spastor 0:fcaad0dfa051 538 case DR_XOFF_BYTE:
spastor 0:fcaad0dfa051 539 _uart->putc(DR_ESCAPE_BYTE);
spastor 0:fcaad0dfa051 540 _uart->putc(data ^ DR_ESCAPE_XOR_BYTE);
spastor 0:fcaad0dfa051 541 break;
spastor 0:fcaad0dfa051 542 default:
spastor 0:fcaad0dfa051 543 _uart->putc(data);
spastor 0:fcaad0dfa051 544 }
spastor 0:fcaad0dfa051 545 } else {
spastor 0:fcaad0dfa051 546 _uart->putc(data);
spastor 4:629712865107 547 }
spastor 0:fcaad0dfa051 548 }
spastor 0:fcaad0dfa051 549
spastor 0:fcaad0dfa051 550 void XBee::send_api_frame(ApiFrame *frame)
spastor 0:fcaad0dfa051 551 {
spastor 0:fcaad0dfa051 552 uint8_t chksum;
spastor 0:fcaad0dfa051 553 const uint8_t *data;
spastor 0:fcaad0dfa051 554 uint16_t bytes_sent = 0, frame_len;
spastor 4:629712865107 555
spastor 0:fcaad0dfa051 556 frame->dump();
spastor 4:629712865107 557
spastor 0:fcaad0dfa051 558 frame_len = 1 + frame->get_data_len(); /* frame type + frame payload */
spastor 0:fcaad0dfa051 559 data = frame->get_data();
spastor 4:629712865107 560
spastor 0:fcaad0dfa051 561 /* Send the start of frame delimiter */
spastor 0:fcaad0dfa051 562 _uart->putc(DR_START_OF_FRAME);
spastor 4:629712865107 563
spastor 0:fcaad0dfa051 564 /* Now the length */
spastor 0:fcaad0dfa051 565 send_byte_escaping_if((uint8_t)(frame_len >> 8));
spastor 0:fcaad0dfa051 566 send_byte_escaping_if((uint8_t)frame_len);
spastor 0:fcaad0dfa051 567
spastor 0:fcaad0dfa051 568 /* Send the Frame type and then the payload */
spastor 0:fcaad0dfa051 569 chksum = (uint8_t)frame->get_frame_type();
spastor 0:fcaad0dfa051 570 send_byte_escaping_if(chksum);
spastor 0:fcaad0dfa051 571 bytes_sent++;
spastor 0:fcaad0dfa051 572
spastor 0:fcaad0dfa051 573 /* And now, send the packet payload */
spastor 0:fcaad0dfa051 574 while (bytes_sent++ < frame_len) {
spastor 0:fcaad0dfa051 575 chksum += *data;
spastor 0:fcaad0dfa051 576 send_byte_escaping_if(*data++);
spastor 0:fcaad0dfa051 577 }
spastor 4:629712865107 578
spastor 0:fcaad0dfa051 579 /* And finally send the checksum */
spastor 0:fcaad0dfa051 580 send_byte_escaping_if(~chksum);
spastor 0:fcaad0dfa051 581 }
spastor 4:629712865107 582
spastor 0:fcaad0dfa051 583 RadioStatus XBee::register_frame_handler(FrameHandler *const handler)
spastor 0:fcaad0dfa051 584 {
spastor 0:fcaad0dfa051 585 if (handler != NULL) {
spastor 0:fcaad0dfa051 586 for (int i = 0; i < MAX_FRAME_HANDLERS; i++) {
spastor 4:629712865107 587 if (_fhandlers[i] != NULL) {
spastor 0:fcaad0dfa051 588 continue;
spastor 4:629712865107 589 }
spastor 0:fcaad0dfa051 590 _fhandlers[i] = handler;
spastor 0:fcaad0dfa051 591 return Success;
spastor 0:fcaad0dfa051 592 }
spastor 0:fcaad0dfa051 593 }
spastor 0:fcaad0dfa051 594
spastor 0:fcaad0dfa051 595 digi_log(LogLevelError, "No more Frame Handlers available. Increase MAX_FRAME_HANDLERS define\r\n");
spastor 4:629712865107 596
spastor 0:fcaad0dfa051 597 return Failure;
spastor 4:629712865107 598 }
spastor 0:fcaad0dfa051 599
spastor 0:fcaad0dfa051 600 RadioStatus XBee::unregister_frame_handler(FrameHandler *const handler)
spastor 0:fcaad0dfa051 601 {
spastor 0:fcaad0dfa051 602 int i;
spastor 0:fcaad0dfa051 603
spastor 0:fcaad0dfa051 604 if (handler != NULL) {
spastor 0:fcaad0dfa051 605 for (i = 0; i < MAX_FRAME_HANDLERS; i++) {
spastor 4:629712865107 606 if (_fhandlers[i] == handler) {
spastor 0:fcaad0dfa051 607 break;
spastor 4:629712865107 608 }
spastor 0:fcaad0dfa051 609 }
spastor 4:629712865107 610
spastor 4:629712865107 611 if (i == MAX_FRAME_HANDLERS) {
spastor 0:fcaad0dfa051 612 return Failure;
spastor 4:629712865107 613 }
spastor 4:629712865107 614
spastor 0:fcaad0dfa051 615 do {
spastor 4:629712865107 616 if (i == MAX_FRAME_HANDLERS - 1) {
spastor 0:fcaad0dfa051 617 _fhandlers[i] = NULL;
spastor 4:629712865107 618 } else {
spastor 0:fcaad0dfa051 619 _fhandlers[i] = _fhandlers[i + 1];
spastor 4:629712865107 620 }
spastor 0:fcaad0dfa051 621 } while (++i < MAX_FRAME_HANDLERS);
spastor 0:fcaad0dfa051 622 }
spastor 0:fcaad0dfa051 623
spastor 0:fcaad0dfa051 624 return Success;
spastor 0:fcaad0dfa051 625 }
spastor 0:fcaad0dfa051 626
spastor 0:fcaad0dfa051 627 XBee::RadioProtocol XBee::get_radio_protocol(void) const
spastor 0:fcaad0dfa051 628 {
spastor 0:fcaad0dfa051 629 enum HardwareVersion {
spastor 0:fcaad0dfa051 630 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 631 X09_009 = 0x01,
spastor 0:fcaad0dfa051 632 X09_019 = 0x02,
spastor 0:fcaad0dfa051 633 XH9_009 = 0x03,
spastor 0:fcaad0dfa051 634 XH9_019 = 0x04,
spastor 0:fcaad0dfa051 635 X24_009 = 0x05,
spastor 0:fcaad0dfa051 636 X24_019 = 0x06,
spastor 0:fcaad0dfa051 637 X09_001 = 0x07,
spastor 0:fcaad0dfa051 638 XH9_001 = 0x08,
spastor 0:fcaad0dfa051 639 X08_004 = 0x09,
spastor 0:fcaad0dfa051 640 XC09_009 = 0x0A,
spastor 0:fcaad0dfa051 641 XC09_038 = 0x0B,
spastor 0:fcaad0dfa051 642 X24_038 = 0x0C,
spastor 0:fcaad0dfa051 643 X09_009_TX = 0x0D,
spastor 0:fcaad0dfa051 644 X09_019_TX = 0x0E,
spastor 0:fcaad0dfa051 645 XH9_009_TX = 0x0F,
spastor 0:fcaad0dfa051 646 XH9_019_TX = 0x10,
spastor 0:fcaad0dfa051 647 X09_001_TX = 0x11,
spastor 0:fcaad0dfa051 648 XH9_001_TX = 0x12,
spastor 0:fcaad0dfa051 649 XT09B_XXX = 0x13,
spastor 0:fcaad0dfa051 650 XT09_XXX = 0x14,
spastor 0:fcaad0dfa051 651 XC08_009 = 0x15,
spastor 0:fcaad0dfa051 652 XC08_038 = 0x16,
spastor 0:fcaad0dfa051 653 #endif
spastor 0:fcaad0dfa051 654 XB24_AXX_XX = 0x17,
spastor 0:fcaad0dfa051 655 XBP24_AXX_XX = 0x18,
spastor 0:fcaad0dfa051 656 XB24_BXIX_XXX = 0x19,
spastor 0:fcaad0dfa051 657 XBP24_BXIX_XXX = 0x1A,
spastor 0:fcaad0dfa051 658 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 659 XBP09_DXIX_XXX = 0x1B,
spastor 0:fcaad0dfa051 660 XBP09_XCXX_XXX = 0x1C,
spastor 0:fcaad0dfa051 661 XBP08_DXXX_XXX = 0x1D,
spastor 0:fcaad0dfa051 662 #endif
spastor 0:fcaad0dfa051 663 XBP24B = 0x1E,
spastor 0:fcaad0dfa051 664 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 665 XB24_WF = 0x1F,
spastor 0:fcaad0dfa051 666 AMBER_MBUS = 0x20,
spastor 0:fcaad0dfa051 667 #endif
spastor 0:fcaad0dfa051 668 XBP24C = 0x21,
spastor 0:fcaad0dfa051 669 XB24C = 0x22,
spastor 0:fcaad0dfa051 670 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 671 XSC_GEN3 = 0x23,
spastor 0:fcaad0dfa051 672 SRD_868_GEN3 = 0x24,
spastor 0:fcaad0dfa051 673 ABANDONATED = 0x25,
spastor 0:fcaad0dfa051 674 SMT_900LP = 0x26,
spastor 0:fcaad0dfa051 675 WIFI_ATHEROS = 0x27,
spastor 0:fcaad0dfa051 676 SMT_WIFI_ATHEROS = 0x28,
spastor 0:fcaad0dfa051 677 SMT_475LP = 0x29,
spastor 0:fcaad0dfa051 678 XBEE_CELL_TH = 0x2A,
spastor 0:fcaad0dfa051 679 XLR_MODULE = 0x2B,
spastor 0:fcaad0dfa051 680 XB900HP_NZ = 0x2C,
spastor 0:fcaad0dfa051 681 XBP24C_TH_DIP = 0x2D,
spastor 0:fcaad0dfa051 682 XB24C_TH_DIP = 0x2E,
hbujanda 5:da2ea7a76243 683 XLR_BASEBOARD = 0x2F,
hbujanda 5:da2ea7a76243 684 XBP24C_S2C_SMT = 0x30
spastor 0:fcaad0dfa051 685 #endif
spastor 0:fcaad0dfa051 686 };
spastor 0:fcaad0dfa051 687 const bool fw_4_bytes_len = _fw_version > 0x0FFF && _fw_version < 0xFFFF;
spastor 0:fcaad0dfa051 688 const uint8_t fw_nibble_3 = (_fw_version >> (4 * 3)) & 0x000F;
spastor 0:fcaad0dfa051 689 const uint8_t fw_nibble_1 = (_fw_version >> (4 * 1)) & 0x000F;
spastor 0:fcaad0dfa051 690 const uint8_t fw_nibble_0 = (_fw_version >> (4 * 0)) & 0x000F;
spastor 0:fcaad0dfa051 691 const uint8_t hw_version_msb = _hw_version >> 8;
spastor 0:fcaad0dfa051 692
spastor 0:fcaad0dfa051 693 if (hw_version_msb == XB24_AXX_XX || hw_version_msb == XBP24_AXX_XX) {
spastor 0:fcaad0dfa051 694 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 695 if (fw_4_bytes_len && fw_nibble_3 == 8) {
spastor 0:fcaad0dfa051 696 return DigiMesh;
spastor 0:fcaad0dfa051 697 }
spastor 0:fcaad0dfa051 698 return Raw_802_15_4;
spastor 0:fcaad0dfa051 699 #else
spastor 0:fcaad0dfa051 700 if (!(fw_4_bytes_len && fw_nibble_3 == 8)) {
spastor 0:fcaad0dfa051 701 return Raw_802_15_4;
spastor 0:fcaad0dfa051 702 }
spastor 0:fcaad0dfa051 703 #endif
spastor 0:fcaad0dfa051 704 } else if (hw_version_msb == XB24_BXIX_XXX || hw_version_msb == XBP24_BXIX_XXX) {
spastor 0:fcaad0dfa051 705 if (fw_4_bytes_len && ((fw_nibble_3 == 1 && fw_nibble_1 == 2 && fw_nibble_0 == 0) || fw_nibble_3 == 2)) {
spastor 0:fcaad0dfa051 706 return ZigBee;
spastor 0:fcaad0dfa051 707 }
spastor 0:fcaad0dfa051 708 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 709 if (fw_4_bytes_len && fw_nibble_3 == 3) {
spastor 0:fcaad0dfa051 710 return SmartEnergy;
spastor 0:fcaad0dfa051 711 }
spastor 0:fcaad0dfa051 712 return ZNet;
spastor 0:fcaad0dfa051 713 } else if (hw_version_msb == XBP09_DXIX_XXX) {
spastor 0:fcaad0dfa051 714 if (fw_4_bytes_len && (fw_nibble_3 == 8 || fw_nibble_1 == 8)) {
spastor 0:fcaad0dfa051 715 return DigiMesh;
spastor 0:fcaad0dfa051 716 }
spastor 0:fcaad0dfa051 717 return DigiPoint;
spastor 0:fcaad0dfa051 718 } else if (hw_version_msb == XBP08_DXXX_XXX) {
spastor 0:fcaad0dfa051 719 return DigiPoint;
spastor 0:fcaad0dfa051 720 #endif
spastor 0:fcaad0dfa051 721 } else if (hw_version_msb == XBP24B) {
spastor 0:fcaad0dfa051 722 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 723 if (fw_4_bytes_len && fw_nibble_3 == 3) {
spastor 0:fcaad0dfa051 724 return SmartEnergy;
spastor 0:fcaad0dfa051 725 }
spastor 0:fcaad0dfa051 726 return ZigBee;
spastor 0:fcaad0dfa051 727 #else
spastor 0:fcaad0dfa051 728 if (!(fw_4_bytes_len && fw_nibble_3 == 3)) {
spastor 0:fcaad0dfa051 729 return ZigBee;
spastor 0:fcaad0dfa051 730 }
spastor 0:fcaad0dfa051 731 #endif
spastor 0:fcaad0dfa051 732 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 733 } else if (hw_version_msb == XB24_WF || hw_version_msb == WIFI_ATHEROS || hw_version_msb == SMT_WIFI_ATHEROS) {
spastor 0:fcaad0dfa051 734 return XBeeWiFi;
spastor 0:fcaad0dfa051 735 #endif
spastor 0:fcaad0dfa051 736 } else if (hw_version_msb == XBP24C || hw_version_msb == XB24C) {
hbujanda 5:da2ea7a76243 737 if (fw_4_bytes_len && fw_nibble_3 == 2) {
hbujanda 5:da2ea7a76243 738 return Raw_802_15_4;
hbujanda 5:da2ea7a76243 739 }
spastor 0:fcaad0dfa051 740 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 741 if (fw_4_bytes_len && fw_nibble_3 == 5) {
spastor 0:fcaad0dfa051 742 return SmartEnergy;
spastor 0:fcaad0dfa051 743 }
spastor 0:fcaad0dfa051 744 return ZigBee;
spastor 0:fcaad0dfa051 745 #else
spastor 0:fcaad0dfa051 746 if (!(fw_4_bytes_len && fw_nibble_3 == 5)) {
spastor 0:fcaad0dfa051 747 return ZigBee;
spastor 0:fcaad0dfa051 748 }
spastor 0:fcaad0dfa051 749 #endif
spastor 0:fcaad0dfa051 750 #ifdef EXTRA_XBEE_PROTOCOLS
spastor 0:fcaad0dfa051 751 } else if (hw_version_msb == XSC_GEN3 || hw_version_msb == SRD_868_GEN3) {
spastor 0:fcaad0dfa051 752 if (fw_4_bytes_len && fw_nibble_3 == 8) {
spastor 0:fcaad0dfa051 753 return DigiMesh;
spastor 0:fcaad0dfa051 754 } else if (fw_4_bytes_len && fw_nibble_3 == 1) {
spastor 0:fcaad0dfa051 755 return DigiPoint;
spastor 0:fcaad0dfa051 756 }
spastor 0:fcaad0dfa051 757 return None;
spastor 0:fcaad0dfa051 758 } else if (hw_version_msb == XBEE_CELL_TH) {
spastor 0:fcaad0dfa051 759 return None;
spastor 0:fcaad0dfa051 760 } else if (hw_version_msb == XLR_MODULE) {
spastor 0:fcaad0dfa051 761 return None;
spastor 0:fcaad0dfa051 762 } else if (hw_version_msb == XLR_BASEBOARD) {
spastor 0:fcaad0dfa051 763 return None;
spastor 0:fcaad0dfa051 764 } else if (hw_version_msb == XB900HP_NZ) {
spastor 0:fcaad0dfa051 765 return DigiPoint;
hbujanda 5:da2ea7a76243 766 } else if (hw_version_msb == XBP24C_TH_DIP || hw_version_msb == XB24C_TH_DIP || hw_version_msb == XBP24C_S2C_SMT) {
hbujanda 6:06522f3a6642 767 if (fw_4_bytes_len && fw_nibble_3 == 9) {
hbujanda 6:06522f3a6642 768 return DigiMesh;
hbujanda 6:06522f3a6642 769 }
hbujanda 5:da2ea7a76243 770 if (fw_4_bytes_len && fw_nibble_3 == 5) {
hbujanda 5:da2ea7a76243 771 return SmartEnergy;
hbujanda 5:da2ea7a76243 772 }
hbujanda 5:da2ea7a76243 773 if (fw_4_bytes_len && fw_nibble_3 == 2) {
hbujanda 5:da2ea7a76243 774 return Raw_802_15_4;
hbujanda 5:da2ea7a76243 775 }
hbujanda 5:da2ea7a76243 776 return ZigBee;
spastor 0:fcaad0dfa051 777 }
spastor 0:fcaad0dfa051 778 #else
spastor 0:fcaad0dfa051 779 }
spastor 0:fcaad0dfa051 780 #endif
spastor 0:fcaad0dfa051 781
spastor 0:fcaad0dfa051 782 return None;
spastor 0:fcaad0dfa051 783 }
spastor 0:fcaad0dfa051 784
spastor 0:fcaad0dfa051 785 #define TX_STATUS_OFFSET_ZB 4
spastor 0:fcaad0dfa051 786 #define TX_STATUS_OFFSET_802 1
spastor 0:fcaad0dfa051 787
spastor 0:fcaad0dfa051 788 TxStatus XBee::send_data(ApiFrame *frame)
spastor 0:fcaad0dfa051 789 {
spastor 0:fcaad0dfa051 790 TxStatus resp = TxStatusTimeout;
spastor 0:fcaad0dfa051 791 ApiFrame *resp_frame;
spastor 0:fcaad0dfa051 792
spastor 0:fcaad0dfa051 793 send_api_frame(frame);
spastor 0:fcaad0dfa051 794
spastor 4:629712865107 795 /* Wait for the transmit status response packet */
spastor 4:629712865107 796 resp_frame = get_this_api_frame(frame->get_frame_id(),
hbujanda 6:06522f3a6642 797 ApiFrame::TxStatusZBDM, ApiFrame::TxStatus);
spastor 4:629712865107 798 if (resp_frame == NULL) {
spastor 0:fcaad0dfa051 799 return resp;
spastor 4:629712865107 800 }
spastor 4:629712865107 801
hbujanda 6:06522f3a6642 802 uint8_t index = resp_frame->get_frame_type() == ApiFrame::TxStatusZBDM ?
spastor 0:fcaad0dfa051 803 TX_STATUS_OFFSET_ZB : TX_STATUS_OFFSET_802;
spastor 4:629712865107 804
spastor 0:fcaad0dfa051 805 resp = (TxStatus)resp_frame->get_data_at(index);
spastor 4:629712865107 806
spastor 0:fcaad0dfa051 807 /* Once processed, remove the frame from the buffer */
spastor 4:629712865107 808 _framebuf_syncr.free_frame(resp_frame);
spastor 4:629712865107 809
spastor 0:fcaad0dfa051 810 return resp;
spastor 0:fcaad0dfa051 811 }
spastor 0:fcaad0dfa051 812
spastor 3:8662ebe83570 813 TxStatus XBee::send_data_broadcast(const uint8_t *const data, uint16_t len, bool syncr)
spastor 0:fcaad0dfa051 814 {
spastor 0:fcaad0dfa051 815 const RemoteXBee remoteDevice = RemoteXBee(ADDR64_BROADCAST);
spastor 3:8662ebe83570 816 return send_data(remoteDevice, data, len, syncr);
spastor 0:fcaad0dfa051 817 }
spastor 0:fcaad0dfa051 818
spastor 4:629712865107 819 uint32_t XBee::process_rx_frames()
spastor 0:fcaad0dfa051 820 {
spastor 0:fcaad0dfa051 821 ApiFrame *frame = NULL;
spastor 0:fcaad0dfa051 822
spastor 4:629712865107 823 while ((frame = _framebuf_app.get_next_complete_frame()) != NULL) {
spastor 0:fcaad0dfa051 824 for (int i = 0; i < MAX_FRAME_HANDLERS; i++) {
spastor 0:fcaad0dfa051 825
spastor 0:fcaad0dfa051 826 if (_fhandlers[i] == NULL) {
spastor 0:fcaad0dfa051 827 /* No more handlers, break here */
spastor 0:fcaad0dfa051 828 break;
spastor 0:fcaad0dfa051 829 }
spastor 0:fcaad0dfa051 830
spastor 0:fcaad0dfa051 831 /* Check if frame and handler match, if not... go for the next one */
spastor 0:fcaad0dfa051 832 if (frame->get_frame_type() != _fhandlers[i]->get_type()) {
spastor 0:fcaad0dfa051 833 continue;
spastor 0:fcaad0dfa051 834 }
spastor 0:fcaad0dfa051 835
spastor 0:fcaad0dfa051 836 _fhandlers[i]->process_frame_data(frame);
spastor 0:fcaad0dfa051 837 }
spastor 4:629712865107 838
spastor 0:fcaad0dfa051 839 /* Once processed, remove the frame from the buffer */
spastor 4:629712865107 840 _framebuf_app.free_frame(frame);
spastor 4:629712865107 841 }
spastor 0:fcaad0dfa051 842
spastor 4:629712865107 843 const uint32_t dropped_frames = _framebuf_app.get_dropped_frames_count();
spastor 4:629712865107 844 if (dropped_frames != 0) {
spastor 4:629712865107 845 digi_log(LogLevelWarning, "process_rx_frames: %d frames dropped!!!\r\n", dropped_frames);
spastor 4:629712865107 846 }
spastor 4:629712865107 847
spastor 4:629712865107 848 return dropped_frames;
spastor 0:fcaad0dfa051 849 }
spastor 0:fcaad0dfa051 850
spastor 0:fcaad0dfa051 851 void XBee::register_modem_status_cb(modem_status_cb_t function)
spastor 0:fcaad0dfa051 852 {
spastor 0:fcaad0dfa051 853 if (_modem_status_handler == NULL) {
spastor 0:fcaad0dfa051 854 _modem_status_handler = new FH_ModemStatus();
spastor 0:fcaad0dfa051 855 register_frame_handler(_modem_status_handler);
spastor 0:fcaad0dfa051 856 }
spastor 0:fcaad0dfa051 857 _modem_status_handler->register_modem_status_cb(function);
spastor 0:fcaad0dfa051 858 }
spastor 0:fcaad0dfa051 859
spastor 0:fcaad0dfa051 860 void XBee::unregister_modem_status_cb()
spastor 0:fcaad0dfa051 861 {
spastor 0:fcaad0dfa051 862 if (_modem_status_handler != NULL) {
spastor 0:fcaad0dfa051 863 _modem_status_handler->unregister_modem_status_cb();
spastor 0:fcaad0dfa051 864 unregister_frame_handler(_modem_status_handler);
spastor 0:fcaad0dfa051 865 delete _modem_status_handler;
spastor 0:fcaad0dfa051 866 _modem_status_handler = NULL; /* as delete does not set to NULL */
spastor 0:fcaad0dfa051 867 }
spastor 0:fcaad0dfa051 868 }
spastor 0:fcaad0dfa051 869
spastor 4:629712865107 870 int XBee::get_AI(void)
spastor 4:629712865107 871 {
spastor 4:629712865107 872 uint32_t atai;
spastor 4:629712865107 873 const AtCmdFrame::AtCmdResp status = get_param("AI", &atai);
spastor 4:629712865107 874
spastor 4:629712865107 875 if (status != AtCmdFrame::AtCmdRespOk) {
spastor 4:629712865107 876 digi_log(LogLevelError, "get_association_indication() failed with %d\r\n", status);
spastor 4:629712865107 877 return -1;
spastor 4:629712865107 878 }
spastor 4:629712865107 879 return atai;
spastor 4:629712865107 880 }