Fork of my MQTTGateway

Dependencies:   mbed-http

Committer:
vpcola
Date:
Sat Apr 08 14:45:51 2017 +0000
Revision:
0:f1d3878b8dd9
Initial commit

Who changed what in which revision?

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