XBee modules

Dependencies:   DigiLogger

Fork of XBeeLib by Digi International Inc.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers XBeeZB.cpp Source File

XBeeZB.cpp

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