Xbee s2b for lpc11u24

Dependencies:   DigiLogger

Dependents:  

Fork of XBeeLib by Digi International Inc.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers XBee802.cpp Source File

XBee802.cpp

00001 /**
00002  * Copyright (c) 2015 Digi International Inc.,
00003  * All rights not expressly granted are reserved.
00004  *
00005  * This Source Code Form is subject to the terms of the Mozilla Public
00006  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
00007  * You can obtain one at http://mozilla.org/MPL/2.0/.
00008  *
00009  * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
00010  * =======================================================================
00011  */
00012 #include "XBee802.h"
00013 #include "IO/IOSample802.h"
00014 #include "Frames/802_Frames.h"
00015 #include "FrameHandlers/FH_ModemStatus.h"
00016 
00017 using namespace XBeeLib;
00018 
00019 /* Class constructor */
00020 XBee802::XBee802(PinName tx, PinName rx, PinName reset, PinName rts, PinName cts, int baud) :
00021         XBee(tx, rx, reset, rts, cts, baud),
00022         _nd_handler(NULL), _rx_64b_handler(NULL), _rx_16b_handler(NULL),
00023         _io_data_64b_handler(NULL), _io_data_16b_handler(NULL)
00024 {
00025 
00026 }
00027 
00028 /* Class destructor */
00029 XBee802::~XBee802()
00030 {
00031     unregister_node_discovery_cb();
00032     unregister_receive_cb();
00033     unregister_io_sample_cb();
00034 }
00035 
00036 RadioStatus XBee802::init()
00037 {
00038     RadioStatus retval = XBee::init();
00039     uint16_t addr16;
00040     RadioStatus error = get_network_address(&addr16);
00041     if (error == Success) {
00042         digi_log(LogLevelInfo, "ADDR16: %04x\r\n", addr16);
00043     } else {
00044         digi_log(LogLevelInfo, "ADDR16: UNKNOWN\r\n");
00045     }
00046 
00047     const RadioProtocol radioProtocol = get_radio_protocol();
00048     if (radioProtocol != Raw_802_15_4) {
00049         digi_log(LogLevelError, "Radio protocol does not match, needed a %d got a %d\r\n", Raw_802_15_4, radioProtocol);
00050         retval = Failure;
00051     }
00052     assert(radioProtocol == Raw_802_15_4);
00053 
00054     return retval;
00055 }
00056 
00057 RadioStatus XBee802::set_channel(uint8_t  channel)
00058 {
00059     AtCmdFrame::AtCmdResp cmdresp;
00060 
00061     /* Pro and Non-Pro modules have different channels available. The at 
00062        command will return an error if the selected channel is not available */
00063     cmdresp = set_param("CH", channel);
00064     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00065         return Failure;
00066     }
00067     return Success;
00068 }
00069 
00070 RadioStatus XBee802::get_channel(uint8_t * const  channel)
00071 {
00072     if (channel == NULL) {
00073         return Failure;
00074     }
00075     AtCmdFrame::AtCmdResp cmdresp;
00076 
00077     uint32_t var32;
00078     cmdresp = get_param("CH", &var32);
00079     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00080         return Failure;
00081     }
00082     *channel = var32;
00083     return Success;
00084 }
00085 
00086 RadioStatus XBee802::set_panid(uint16_t  panid)
00087 {
00088     AtCmdFrame::AtCmdResp cmdresp;
00089 
00090     cmdresp = set_param("ID", panid);
00091     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00092         return Failure;
00093     }
00094     return Success;
00095 }
00096 
00097 RadioStatus XBee802::get_panid(uint16_t * const  panid)
00098 {
00099     if (panid == NULL) {
00100         return Failure;
00101     }
00102     AtCmdFrame::AtCmdResp cmdresp;
00103 
00104     uint32_t var32;
00105     cmdresp = get_param("ID", &var32);
00106     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00107         return Failure;
00108     }
00109     *panid = var32;
00110     return Success;
00111 }
00112 
00113 RadioStatus XBee802::get_network_address(uint16_t * const  addr16)
00114 {
00115     if (addr16 == NULL) {
00116         return Failure;
00117     }
00118     AtCmdFrame::AtCmdResp cmdresp;
00119 
00120     uint32_t var32;
00121     cmdresp = get_param("MY", &var32);
00122     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00123         return Failure;
00124     }
00125     *addr16 = var32;
00126     return Success;
00127 }
00128 
00129 RadioStatus XBee802::set_network_address(uint16_t  addr16)
00130 {
00131     AtCmdFrame::AtCmdResp cmdresp;
00132 
00133     cmdresp = set_param("MY", addr16);
00134     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00135         return Failure;
00136     }
00137     return Success;
00138 }
00139 
00140 RadioStatus XBee802::get_node_discovery_timeout(uint16_t * const timeout_ms)
00141 {
00142     AtCmdFrame::AtCmdResp cmdresp;
00143     uint32_t var32;
00144 
00145     cmdresp = get_param("NT", &var32);
00146     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00147         return Failure;
00148     }
00149     *timeout_ms = (uint16_t)var32;
00150 
00151     /* No N? command available for this protocol. Add a fix 1s guard time */
00152     *timeout_ms += 1000;
00153 
00154     return Success;
00155 }
00156 
00157 RadioStatus XBee802::get_node_discovery_timeout(uint16_t * const timeout_ms, bool * const wait_for_complete_timeout)
00158 {
00159     const RadioStatus status = get_node_discovery_timeout(timeout_ms);
00160 
00161     /* This protocol requires to wait for the complete timeout before attempting
00162        to execute other commands */
00163     *wait_for_complete_timeout = true;
00164 
00165     return status;
00166 }
00167 
00168 void XBee802::radio_status_update(AtCmdFrame::ModemStatus modem_status)
00169 {
00170     /* Update the radio status variables */
00171     if (modem_status == AtCmdFrame::HwReset) {
00172         _hw_reset_cnt++;
00173     } else if (modem_status == AtCmdFrame::WdReset) {
00174         _wd_reset_cnt++;
00175     }
00176 
00177     _modem_status = modem_status;
00178 
00179     digi_log(LogLevelDebug, "\r\nUpdating radio status: %02x\r\n", modem_status);
00180 }
00181 
00182 TxStatus XBee802::send_data(const RemoteXBee& remote, const uint8_t *const data, uint16_t len, bool syncr)
00183 {
00184     if (remote.is_valid_addr64b()) {
00185         const uint64_t remote64 =  remote.get_addr64();
00186 
00187         digi_log(LogLevelDebug, "send_data ADDR64: %08x:%08x\r\n", UINT64_HI32(remote64), UINT64_LO32(remote64));
00188 
00189         TxFrame802 frame = TxFrame802(remote64, _tx_options, data, len);
00190 
00191         if (syncr) {
00192             return send_data(&frame);
00193         } else {
00194             frame.set_data(0, 0); /* Set frame id to 0 so there is no answer */
00195             send_api_frame(&frame);
00196             return TxStatusSuccess;
00197         }
00198     }
00199 
00200     if (remote.is_valid_addr16b()) {
00201         const uint16_t remote16 = remote.get_addr16();
00202 
00203         digi_log(LogLevelDebug, "send_data ADDR16: %04x\r\n", remote16);
00204 
00205         TxFrame802 frame = TxFrame802(remote16, _tx_options, data, len);
00206 
00207         if (syncr) {
00208             return send_data(&frame);
00209         } else {
00210             frame.set_data(0, 0); /* Set frame id to 0 so there is no answer */
00211             send_api_frame(&frame);
00212             return TxStatusSuccess;
00213         }
00214     }
00215 
00216     return TxStatusInvalidAddr;
00217 }
00218 
00219 XBee802::AssocStatus  XBee802::get_assoc_status(void)
00220 {
00221     return (AssocStatus )get_AI();
00222 }
00223 
00224 RemoteXBee802 XBee802::get_remote_node_by_id(const char * const node_id)
00225 {
00226     uint64_t addr64;
00227     uint16_t addr16;
00228 
00229     _get_remote_node_by_id(node_id, &addr64, &addr16);
00230     return RemoteXBee802(addr64, addr16);
00231 }
00232 
00233 void XBee802::register_node_discovery_cb(node_discovery_802_cb_t function)
00234 {
00235     if (_nd_handler == NULL) {
00236         _nd_handler = new FH_NodeDiscovery802();
00237         register_frame_handler(_nd_handler);
00238     }
00239     _nd_handler->register_node_discovery_cb(function);
00240 }
00241 
00242 void XBee802::unregister_node_discovery_cb()
00243 {
00244     if (_nd_handler != NULL) {
00245         _nd_handler->unregister_node_discovery_cb();
00246         unregister_frame_handler(_nd_handler);
00247         delete _nd_handler;
00248         _nd_handler = NULL; /* as delete does not set to NULL */
00249     }
00250 }
00251 
00252 void XBee802::register_receive_cb(receive_802_cb_t function)
00253 {
00254     if (_rx_64b_handler == NULL) {
00255         _rx_64b_handler = new FH_RxPacket64b802();
00256         register_frame_handler(_rx_64b_handler);
00257     }
00258     _rx_64b_handler->register_receive_cb(function);
00259 
00260     if (_rx_16b_handler == NULL) {
00261         _rx_16b_handler = new FH_RxPacket16b802();
00262         register_frame_handler(_rx_16b_handler);
00263     }
00264     _rx_16b_handler->register_receive_cb(function);
00265 }
00266 
00267 void XBee802::unregister_receive_cb()
00268 {
00269     if (_rx_64b_handler != NULL) {
00270         _rx_64b_handler->unregister_receive_cb();
00271         unregister_frame_handler(_rx_64b_handler);
00272         delete _rx_64b_handler;
00273         _rx_64b_handler = NULL; /* as delete does not set to NULL */
00274     }
00275 
00276     if (_rx_16b_handler != NULL) {
00277         _rx_16b_handler->unregister_receive_cb();
00278         unregister_frame_handler(_rx_16b_handler);
00279         delete _rx_16b_handler;
00280         _rx_16b_handler = NULL; /* as delete does not set to NULL */
00281     }
00282 }
00283 
00284 void XBee802::register_io_sample_cb(io_data_cb_802_t function)
00285 {
00286     if (_io_data_64b_handler == NULL) {
00287         _io_data_64b_handler = new FH_IoDataSampe64b802();
00288         register_frame_handler(_io_data_64b_handler);
00289     }
00290     _io_data_64b_handler->register_io_data_cb(function);
00291 
00292     if (_io_data_16b_handler == NULL) {
00293         _io_data_16b_handler = new FH_IoDataSampe16b802();
00294         register_frame_handler(_io_data_16b_handler);
00295     }
00296     _io_data_16b_handler->register_io_data_cb(function);
00297 }
00298 
00299 void XBee802::unregister_io_sample_cb()
00300 {
00301     if (_io_data_64b_handler != NULL) {
00302         _io_data_64b_handler->unregister_io_data_cb();
00303         unregister_frame_handler(_io_data_64b_handler);
00304         delete _io_data_64b_handler;
00305         _io_data_64b_handler = NULL; /* as delete does not set to NULL */
00306     }
00307 
00308     if (_io_data_16b_handler != NULL) {
00309         _io_data_16b_handler->unregister_io_data_cb();
00310         unregister_frame_handler(_io_data_16b_handler);
00311         delete _io_data_16b_handler;
00312         _io_data_16b_handler = NULL; /* as delete does not set to NULL */
00313     }
00314 }
00315 
00316 AtCmdFrame::AtCmdResp XBee802::get_param(const RemoteXBee& remote, const char * const param, uint32_t * const data)
00317 {
00318     uint16_t len = sizeof *data;
00319     AtCmdFrame::AtCmdResp atCmdResponse;
00320 
00321     if (remote.is_valid_addr64b()) {
00322         const uint64_t dev_addr64 =  remote.get_addr64();
00323 
00324         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr64, param);
00325         atCmdResponse = send_at_cmd(&cmd_frame, (uint8_t *)data, &len, RadioRemote);
00326     } else if (remote.is_valid_addr16b()) {
00327         const uint16_t dev_addr16 = remote.get_addr16();
00328 
00329         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr16, param);
00330         atCmdResponse = send_at_cmd(&cmd_frame, (uint8_t *)data, &len, RadioRemote);
00331     } else {
00332         return AtCmdFrame::AtCmdRespInvalidAddr;
00333     }
00334 
00335     if (atCmdResponse == AtCmdFrame::AtCmdRespOk && len > sizeof *data) {
00336         atCmdResponse = AtCmdFrame::AtCmdRespLenMismatch;
00337     }
00338 
00339     return atCmdResponse;
00340 }
00341 
00342 AtCmdFrame::AtCmdResp XBee802::set_param(const RemoteXBee& remote, const char * const param, uint32_t data)
00343 {
00344     if (remote.is_valid_addr64b()) {
00345         const uint64_t dev_addr64 =  remote.get_addr64();
00346 
00347         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr64, param, data);
00348         return send_at_cmd(&cmd_frame, NULL, NULL, RadioRemote);
00349     }
00350 
00351     if (remote.is_valid_addr16b()) {
00352         const uint16_t dev_addr16 = remote.get_addr16();
00353 
00354         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr16, param, data);
00355         return send_at_cmd(&cmd_frame, NULL, NULL, RadioRemote);
00356     }
00357 
00358     return AtCmdFrame::AtCmdRespInvalidAddr;
00359 }
00360 
00361 AtCmdFrame::AtCmdResp XBee802::set_param(const RemoteXBee& remote, const char * const param, const uint8_t * data, uint16_t len)
00362 {
00363     if (remote.is_valid_addr64b()) {
00364         const uint64_t dev_addr64 =  remote.get_addr64();
00365 
00366         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr64, param, data, len);
00367         return send_at_cmd(&cmd_frame, NULL, NULL, RadioRemote);
00368     }
00369 
00370     if (remote.is_valid_addr16b()) {
00371         const uint16_t dev_addr16 = remote.get_addr16();
00372 
00373         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr16, param, data, len);
00374         return send_at_cmd(&cmd_frame, NULL, NULL, RadioRemote);
00375     }
00376 
00377     return AtCmdFrame::AtCmdRespInvalidAddr;
00378 }
00379 
00380 AtCmdFrame::AtCmdResp XBee802::get_param(const RemoteXBee& remote, const char * const param, uint8_t * const data, uint16_t * const len)
00381 {
00382     if (remote.is_valid_addr64b()) {
00383         uint64_t dev_addr64 = remote.get_addr64();
00384 
00385         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr64, param);
00386         return send_at_cmd(&cmd_frame, data, len, RadioRemote, false);
00387     }
00388 
00389     if (remote.is_valid_addr16b()) {
00390         uint16_t dev_addr16 = remote.get_addr16();
00391 
00392         AtCmdFrame cmd_frame = AtCmdFrame(dev_addr16, param);
00393         return send_at_cmd(&cmd_frame, data, len, RadioRemote, false);
00394     }
00395 
00396     return AtCmdFrame::AtCmdRespInvalidAddr;
00397 }
00398 
00399 static void get_dio_cmd(XBee802::IoLine line, char * const iocmd)
00400 {
00401     if (line >= XBee802::PWM0) {
00402         iocmd[0] = 'P';
00403         iocmd[1] = '0' + line - XBee802::PWM0;
00404     } else {
00405         iocmd[0] = 'D';
00406         iocmd[1] = '0' + line;
00407     }
00408     iocmd[2] = '\0';
00409 }
00410 
00411 RadioStatus XBee802::set_pin_config(const RemoteXBee& remote, IoLine line, IoMode mode)
00412 {
00413     AtCmdFrame::AtCmdResp cmdresp;
00414     char iocmd[3];
00415 
00416     get_dio_cmd(line, iocmd);
00417 
00418     cmdresp = set_param(remote, iocmd, (uint8_t)mode);
00419     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00420         digi_log(LogLevelError, "set_pin_config: set_param returned %d\r\n", cmdresp);
00421         return Failure;
00422     }
00423 
00424     return Success;
00425 }
00426 
00427 RadioStatus XBee802::get_pin_config(const RemoteXBee& remote, IoLine line, IoMode * const mode)
00428 {
00429     AtCmdFrame::AtCmdResp cmdresp;
00430     char iocmd[3];
00431 
00432     get_dio_cmd(line, iocmd);
00433 
00434     uint32_t var32;
00435     cmdresp = get_param(remote, iocmd, &var32);
00436     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00437         return Failure;
00438     }
00439     *mode = (IoMode)var32;
00440 
00441     return Success;
00442 }
00443 
00444 RadioStatus XBee802::set_dio(const RemoteXBee& remote, IoLine line, DioVal val)
00445 {
00446     if (line > DI8) {
00447         digi_log(LogLevelError, "set_dio: Pin %d not supported as IO\r\n", line);
00448         return Failure;
00449     }
00450 
00451     if (val == Low) {
00452         return set_pin_config(remote, line, DigitalOutLow);
00453     } else {
00454         return set_pin_config(remote, line, DigitalOutHigh);
00455     }
00456 }
00457 
00458 RadioStatus XBee802::get_dio(const RemoteXBee& remote, IoLine line, DioVal * const val)
00459 {
00460     return get_iosample(remote).get_dio(line, val);
00461 }
00462 
00463 RadioStatus XBee802::get_adc(const RemoteXBee& remote, IoLine line, uint16_t * const val)
00464 {
00465     return get_iosample(remote).get_adc(line, val);
00466 }
00467 
00468 RadioStatus XBee802::set_pwm(const RemoteXBee& remote, IoLine line, float duty_cycle)
00469 {
00470     AtCmdFrame::AtCmdResp cmdresp;
00471     char iocmd[3] = { 'M', '0', '\0' };
00472 
00473     if (line != PWM0 && line != PWM1) {
00474         return Failure;
00475     }
00476     if (line == PWM1) {
00477         iocmd[1] = '1';
00478     }
00479 
00480     uint16_t pwm_val = (uint16_t)(duty_cycle * DR_PWM_MAX_VAL / 100);
00481 
00482     cmdresp = set_param(remote, iocmd, pwm_val);
00483     return cmdresp == AtCmdFrame::AtCmdRespOk ? Success : Failure;
00484 }
00485 
00486 IOSample802 XBee802::get_iosample(const RemoteXBee& remote)
00487 {
00488     uint8_t io_sample[MAX_IO_SAMPLE_802_LEN];
00489     uint16_t len = sizeof io_sample;
00490 
00491     RadioStatus resp = _get_iosample(remote, io_sample, &len);
00492     if (resp != Success) {
00493         digi_log(LogLevelError, "XBee802::get_iosample failed to get an IOSample\r\n");
00494         len = 0;
00495     }
00496     return IOSample802(io_sample, len);
00497 }
00498 
00499 static uint8_t get_dio_mask(XBee802::IoLine line)
00500 {
00501     switch (line) {
00502         case XBee802::DIO4_AD4:
00503             return (1 << 0);
00504         case XBee802::DIO3_AD3:
00505             return (1 << 1);
00506         case XBee802::DIO2_AD2:
00507             return (1 << 2);
00508         case XBee802::DIO1_AD1:
00509             return (1 << 3);
00510         case XBee802::DIO0_AD0:
00511             return (1 << 4);
00512         case XBee802::DIO6:
00513             return (1 << 5);
00514         case XBee802::DI8:
00515             return (1 << 6);
00516         default:
00517             return 0;
00518     }
00519 }
00520 
00521 RadioStatus XBee802::set_pin_pull_up(const RemoteXBee& remote, IoLine line, bool enable)
00522 {
00523     AtCmdFrame::AtCmdResp cmdresp;
00524     uint32_t var32;
00525     uint8_t pr;
00526 
00527     cmdresp = get_param(remote, "PR", &var32);
00528     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00529         return Failure;
00530     }
00531     pr = var32;
00532 
00533     const uint8_t dio_mask = get_dio_mask(line);
00534     if (dio_mask == 0) {
00535         digi_log(LogLevelError, "XBee802::set_pin_pull_up: invalid pin %d\r\n", line);
00536         return Failure;
00537     }
00538 
00539     if (enable) {
00540         pr |= dio_mask;
00541     } else {
00542         pr &= ~dio_mask;
00543     }
00544 
00545     cmdresp = set_param(remote, "PR", pr);
00546     return cmdresp == AtCmdFrame::AtCmdRespOk ? Success : Failure;
00547 }
00548 
00549 static uint8_t get_dio_ic_mask(XBee802::IoLine line)
00550 {
00551     if (line < XBee802::DI8) {
00552         return (1 << line);
00553     }
00554     return 0;
00555 }
00556 
00557 RadioStatus XBee802::enable_dio_change_detection(const RemoteXBee& remote, IoLine line, bool enable)
00558 {
00559     if (line > DIO7) {
00560         digi_log(LogLevelError, "XBee802::enable_dio_change_detection: pin not supported (%d)\r\n", line);
00561         return Failure;
00562     }
00563 
00564     AtCmdFrame::AtCmdResp cmdresp;
00565     uint32_t var32;
00566     uint8_t ic;
00567 
00568     cmdresp = get_param(remote, "IC", &var32);
00569     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00570         return Failure;
00571     }
00572     ic = var32;
00573 
00574     const uint8_t dio_mask = get_dio_ic_mask(line);
00575     if (dio_mask == 0) {
00576         digi_log(LogLevelError, "XBeeZB::enable_dio_change_detection: invalid pin %d\r\n", line);
00577         return Failure;
00578     }
00579 
00580     if (enable) {
00581         ic |= dio_mask;
00582     } else {
00583         ic &= ~dio_mask;
00584     }
00585 
00586     cmdresp = set_param(remote, "IC", ic);
00587     return cmdresp == AtCmdFrame::AtCmdRespOk ? Success : Failure;
00588 }
00589 
00590 #ifdef GET_PWM_AVAILABLE
00591 RadioStatus XBee802::get_pwm(const RemoteXBee& remote, IoLine line, float * const duty_cycle)
00592 {
00593     AtCmdFrame::AtCmdResp cmdresp;
00594     char iocmd[3] = { 'M', '0', '\0' };
00595 
00596     if (line != PWM0 && line != PWM1) {
00597         return Failure;
00598     }
00599 
00600     if (line == PWM1) {
00601         iocmd[1] = '1';
00602     }
00603 
00604     uint16_t pwm_val;
00605 
00606     cmdresp = get_param(remote, iocmd, &pwm_val);
00607     if (cmdresp != AtCmdFrame::AtCmdRespOk) {
00608         return Failure;
00609     }
00610 
00611     *duty_cycle = (float)(pwm_val * 100 / DR_PWM_MAX_VAL);
00612 
00613     return Success;
00614 }
00615 #endif