A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.
Fork of EALib by
XBee.cpp
00001 /* 00002 * Copyright 2013 Embedded Artists AB 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "mbed.h" 00018 #include "mbed_debug.h" 00019 #include "XBee.h" 00020 00021 #define XBEE_END_CMD ("\r") 00022 #define CR (0x0D) 00023 #define RESP_OK ("OK") 00024 00025 #define XBEE_START_DEL (0x7E) 00026 00027 #define XBEE_API_ID_TX_64 (0x00) 00028 #define XBEE_API_ID_AT_CMD (0x08) 00029 #define XBEE_API_ID_AT_RESP (0x88) 00030 #define XBEE_API_ID_TX_STAT (0x89) 00031 #define XBEE_API_ID_RX_64 (0x80) 00032 #define XBEE_API_ID_RX_16 (0x81) 00033 #define XBEE_API_ID_MOD_STAT (0x8A) 00034 00035 #define XBEE_MOD_STAT_HW_RESET (0) 00036 #define XBEE_MOD_STAT_WD_RESET (1) 00037 #define XBEE_MOD_STAT_ASSOC (2) 00038 #define XBEE_MOD_STAT_DIASSOC (3) 00039 #define XBEE_MOD_STAT_SYNC_LOST (4) 00040 #define XBEE_MOD_STAT_COORD_REALG (5) 00041 #define XBEE_MOD_STAT_COORD_START (6) 00042 00043 #define XBEE_TX_STAT_SUCCESS (0) 00044 #define XBEE_TX_STAT_NOACK (1) 00045 #define XBEE_TX_STAT_CCA_FAIL (2) 00046 #define XBEE_TX_STAT_PURGED (3) 00047 00048 #define XBEE_RECV_FRAME_TO (2000) 00049 00050 XBee::XBee(PinName tx, PinName rx, PinName reset, PinName sleep) : 00051 _serial(tx, rx), _reset(reset), _sleep(sleep) { 00052 _serial.baud(9600); 00053 _serial.format(8, Serial::None, 1); 00054 00055 _serial.attach(this, &XBee::uartRxIrq, Serial::RxIrq); 00056 00057 rxqIn = 0; 00058 rxqOut = 0; 00059 _rfFrameTimeout = 0; 00060 _rfFrameTimer.reset(); 00061 00062 _rfState = RfStateFrame; 00063 _rfPos = 0; 00064 _rfFrameLen = 0; 00065 _rfFrameId = 0; 00066 00067 _initialized = false; 00068 _type = Coordinator; 00069 00070 _addrHi = 0; 00071 _addrLo = 0; 00072 _rssi = 0; 00073 _frameId = 0; 00074 _txStatus = TxStatusOk; 00075 _recvData = NULL; 00076 _recvLen = 0; 00077 00078 // we enter sleep when sleep pin is high 00079 _sleep = 0; 00080 } 00081 00082 XBee::XBeeError XBee::init(XBeeType type, const char* panId) { 00083 XBeeError err = Ok; 00084 char idBuf[10]; 00085 00086 resetModule(); 00087 00088 _type = type; 00089 00090 do { 00091 00092 if (panId == NULL || strlen(panId) != 4) { 00093 err = ArgumentError; 00094 break; 00095 } 00096 00097 err = commandMode(); 00098 if (err != Ok) { 00099 debug("XBee: +++ failed\n"); 00100 break; 00101 } 00102 00103 // set the sleep mode to Hibernate 00104 err = atSet("ATSM1"); 00105 if (err != Ok) { 00106 debug("Xbee: ATSM1 failed\r\n"); 00107 break; 00108 } 00109 00110 // change PAN ID to EAEA 00111 sprintf(idBuf, "ATID%s", panId); 00112 err = atSet(idBuf); 00113 if (err != Ok) { 00114 debug("Xbee: ATID failed\r\n"); 00115 break; 00116 } 00117 00118 // use 64-bit addressing 00119 err = atSet("ATMYFFFE"); 00120 if (err != Ok) { 00121 debug("Xbee: ATMYFFFE failed\r\n"); 00122 break; 00123 } 00124 00125 // Coordinator 00126 if (type == Coordinator) { 00127 00128 // - will not perform Active Scan to locate PAN ID 00129 // - will not perform Energy Scan to determine free channel 00130 // - allow End devices to associate with this coordinator 00131 err = atSet("ATA24"); 00132 if (err != Ok) { 00133 debug("Xbee: ATA24 failed\r\n"); 00134 break; 00135 } 00136 00137 // set this node as coordinator 00138 err = atSet("ATCE1"); 00139 if (err != Ok) { 00140 debug("Xbee: ATCE1 failed\r\n"); 00141 break; 00142 } 00143 } 00144 else { 00145 // - only associates with Coordinator on matching PAN ID 00146 // - only associates with Coordinator on matching channel 00147 // - device attempts association until success 00148 err = atSet("ATA14"); 00149 if (err != Ok) { 00150 debug("Xbee: ATA14 failed\r\n"); 00151 break; 00152 } 00153 } 00154 00155 00156 // change to API mode 00157 err = atSet("ATAP1"); 00158 if (err != Ok) { 00159 debug("Xbee: ATAP1 failed\r\n"); 00160 break; 00161 } 00162 00163 } while(0); 00164 00165 00166 return err; 00167 } 00168 00169 void XBee::process() { 00170 uint32_t len = 0; 00171 char data = 0; 00172 00173 if (_rfFrameTimeout > 0 && (int)_rfFrameTimeout < _rfFrameTimer.read_ms()) { 00174 _rfState = RfStateFrame; 00175 debug("Xbee: Frame timer expired\r\n"); 00176 _rfFrameTimeout = 0; 00177 _rfFrameTimer.stop(); 00178 } 00179 00180 if (!uartRxQIsEmpty()) { 00181 00182 len = uartReceive(&data, 1); 00183 if (len > 0) { 00184 processByte(data); 00185 } 00186 00187 } 00188 } 00189 00190 XBee::XBeeError XBee::getRemoteAddress(uint32_t* addrHi, uint32_t* addrLo) { 00191 if (!_initialized) { 00192 return NotInitializedError; 00193 } 00194 00195 if (addrHi == NULL || addrLo == NULL) { 00196 return ArgumentError; 00197 } 00198 00199 *addrHi = _addrHi; 00200 *addrLo = _addrLo; 00201 00202 return Ok; 00203 } 00204 00205 XBee::XBeeError XBee::getRssi(uint8_t* rssi ) { 00206 if (!_initialized) { 00207 return NotInitializedError; 00208 } 00209 00210 if (rssi == NULL) { 00211 return ArgumentError; 00212 } 00213 00214 *rssi = _rssi; 00215 00216 return Ok; 00217 } 00218 00219 XBee::XBeeError XBee::getTxStatus(uint8_t* frameId, XBeeTxStatus* status) { 00220 if (!_initialized) { 00221 return NotInitializedError; 00222 } 00223 00224 if (frameId == NULL || status == NULL) { 00225 return ArgumentError; 00226 } 00227 00228 *frameId = _frameId; 00229 *status = _txStatus; 00230 00231 return Ok; 00232 } 00233 00234 XBee::XBeeError XBee::getData(char** data, uint8_t* len) { 00235 if (!_initialized) { 00236 return NotInitializedError; 00237 } 00238 00239 if (data == NULL || len == NULL) { 00240 return ArgumentError; 00241 } 00242 00243 *data = _recvData; 00244 *len = _recvLen; 00245 00246 return Ok; 00247 } 00248 00249 XBee::XBeeError XBee::send(uint32_t addrHi, uint32_t addrLo, char* data, 00250 uint8_t len, uint8_t* frameId) 00251 { 00252 if (!_initialized) { 00253 return NotInitializedError; 00254 } 00255 00256 return apiTx64(addrHi, addrLo, data, len, frameId); 00257 } 00258 00259 XBee::XBeeError XBee::discoverNodes() { 00260 if (!_initialized) { 00261 return NotInitializedError; 00262 } 00263 00264 return apiAtCmd("ND", 0, false); 00265 } 00266 00267 00268 XBee::XBeeError XBee::enterSleep() { 00269 _sleep = 1; 00270 00271 return Ok; 00272 } 00273 00274 XBee::XBeeError XBee::exitSleep() { 00275 _sleep = 0; 00276 00277 return Ok; 00278 } 00279 00280 00281 void XBee::uartRxIrq() { 00282 while(_serial.readable()) { 00283 uartRxQPut(_serial.getc()); 00284 } 00285 } 00286 00287 void XBee::uartRxQPut(uint8_t data) 00288 { 00289 // full 00290 if (rxqOut == (rxqIn + 1) % RX_BUF_SIZE) { 00291 return; 00292 } 00293 00294 rxq[rxqIn] = data; 00295 rxqIn = (rxqIn + 1) % RX_BUF_SIZE; 00296 } 00297 00298 uint8_t XBee::uartRxQGet() 00299 { 00300 uint8_t d = 0; 00301 // empty 00302 if (rxqIn == rxqOut) { 00303 return 0; 00304 } 00305 00306 d = rxq[rxqOut]; 00307 rxqOut = (rxqOut + 1) % RX_BUF_SIZE; 00308 00309 return d; 00310 } 00311 00312 bool XBee::uartRxQIsEmpty() 00313 { 00314 return (rxqIn == rxqOut); 00315 } 00316 00317 uint32_t XBee::uartReceive(char *buf, uint32_t buflen) 00318 { 00319 00320 uint32_t pos = 0; 00321 00322 while(buflen > 0 && !uartRxQIsEmpty()) { 00323 buf[pos] = uartRxQGet(); 00324 pos++; 00325 buflen--; 00326 } 00327 00328 return pos; 00329 } 00330 00331 int32_t XBee::uartReadLine(char* buf, uint32_t bufLen, uint32_t timeout) 00332 { 00333 uint32_t pos = 0; 00334 uint32_t len = 0; 00335 Timer tim; 00336 00337 tim.reset(); 00338 tim.start(); 00339 00340 while(pos < bufLen && tim.read_ms() < (int)timeout) { 00341 00342 len = uartReceive(&buf[pos], 1); 00343 if (len > 0 && buf[pos] == CR) { 00344 buf[pos] = '\0'; 00345 break; 00346 } 00347 00348 pos += len; 00349 } 00350 00351 if (pos >= bufLen) { 00352 return BufTooSmallError; 00353 } 00354 00355 if (tim.read_ms() > (int)timeout) { 00356 return TimeOutError; 00357 } 00358 00359 return pos; 00360 } 00361 00362 void XBee::resetModule() { 00363 // reset pulse must be at least 200 ns. Using 1 ms. 00364 _reset = 0; 00365 wait_ms(1); 00366 _reset = 1; 00367 00368 // wait to make sure the module has started 00369 wait_ms(500); 00370 rxqIn = 0; 00371 rxqOut = 0; 00372 } 00373 00374 XBee::XBeeError XBee::commandMode() { 00375 XBeeError err = Ok; 00376 int32_t lineLen = 0; 00377 char ebuf[10]; 00378 00379 _serial.printf("+++"); 00380 00381 lineLen = uartReadLine(ebuf, 10, 1200); 00382 00383 do { 00384 if (lineLen < 0) { 00385 // error while reading 00386 err = ReadError; 00387 break; 00388 } 00389 00390 if (strcmp(RESP_OK, (char*)ebuf) != 0) { 00391 // didn't receive OK 00392 err = CmdError; 00393 break; 00394 } 00395 } while(0); 00396 00397 return err; 00398 } 00399 00400 XBee::XBeeError XBee::atGet(const char* atCmd, char* resp, uint32_t respLen) 00401 { 00402 00403 int32_t lineLen = 0; 00404 XBeeError err = Ok; 00405 00406 _serial.printf("%s%s", atCmd, XBEE_END_CMD); 00407 00408 do { 00409 00410 // a response is expected 00411 if (resp != NULL && respLen > 0) { 00412 lineLen = uartReadLine(resp, respLen, 1000); 00413 00414 if (lineLen < 0) { 00415 // error while reading 00416 err = ReadError; 00417 break; 00418 } 00419 00420 } 00421 00422 } while(0); 00423 00424 return err; 00425 } 00426 00427 XBee::XBeeError XBee::atSet(const char* atCmd) 00428 { 00429 char b[10]; 00430 XBeeError err = Ok; 00431 00432 err = atGet(atCmd, b, 10); 00433 if (err == Ok) { 00434 00435 if (strcmp(RESP_OK, (char*)b) != 0) { 00436 // didn't receive OK 00437 err = CmdError; 00438 } 00439 } 00440 00441 return err; 00442 } 00443 00444 void XBee::processByte(char data) 00445 { 00446 switch(_rfState) { 00447 case RfStateFrame: 00448 if (data == XBEE_START_DEL) { 00449 _rfPos = 0; 00450 _rfFrameLen = 0; 00451 _rfState = RfStateLength; 00452 00453 // start timer to make sure an entire frame is received 00454 // within a specific time 00455 _rfFrameTimeout = XBEE_RECV_FRAME_TO; 00456 _rfFrameTimer.reset(); 00457 _rfFrameTimer.start(); 00458 } 00459 00460 break; 00461 case RfStateLength: 00462 _rfFrameLen |= (data << (8*(1-_rfPos))); 00463 _rfPos++; 00464 if (_rfPos == 2) { 00465 _rfPos = 0; 00466 _rfState = RfStateData; 00467 00468 if (_rfFrameLen > XBEE_BUF_SZ) { 00469 debug("Xbee: Frame len %d > max buffer len %d\r\n", 00470 (int)_rfFrameLen, (int)XBEE_BUF_SZ); 00471 _rfFrameLen = XBEE_BUF_SZ; 00472 } 00473 00474 } 00475 break; 00476 case RfStateData: 00477 _rfBuf[_rfPos++] = data; 00478 // read up until checksum (1 byte) 00479 if (_rfPos == _rfFrameLen+1) { 00480 _rfState = RfStateFrame; 00481 00482 // cancel timer 00483 _rfFrameTimeout = 0; 00484 _rfFrameTimer.stop(); 00485 00486 processFrame(_rfBuf, _rfPos); 00487 } 00488 break; 00489 00490 } 00491 } 00492 00493 void XBee::processFrame(char* buf, uint32_t len) 00494 { 00495 00496 uint32_t addrLo = 0; 00497 uint32_t addrHi = 0; 00498 char* b = NULL; 00499 uint32_t bLen = 0; 00500 00501 if (len < 2) { 00502 debug("Xbee: Invalid frame length (%d)\r\n", (int)len); 00503 return; 00504 } 00505 00506 // verify checksum 00507 if (checksum(buf, len) != 0) { 00508 debug("Xbee: Invalid checksum\r\n"); 00509 return; 00510 } 00511 00512 switch(buf[0]) { 00513 case XBEE_API_ID_AT_RESP: 00514 if (len < 5) { 00515 debug("Xbee: AT resp data too small: %d\r\n ", (int)len); 00516 return; 00517 } 00518 00519 // there is a value 00520 if (len > 6) { 00521 b = &buf[5]; 00522 bLen = len-5-1; 00523 } 00524 00525 handleAtResponse(buf[1], &buf[2], buf[4], b, bLen); 00526 break; 00527 case XBEE_API_ID_TX_STAT: 00528 handleTxStatus(buf[1], buf[2]); 00529 break; 00530 case XBEE_API_ID_RX_64: 00531 if (len < 12) { 00532 debug("Xbee: RX data too small: %d\r\n ", (int)len); 00533 return; 00534 } 00535 addrHi = bufTo32bitInt(&buf[1]); 00536 addrLo = bufTo32bitInt(&buf[5]); 00537 00538 processData(addrHi, addrLo, buf[9], buf[10], &buf[11], len-11-1); 00539 break; 00540 case XBEE_API_ID_RX_16: 00541 debug("Xbee: RX 16 bit (unhandled)\r\n"); 00542 break; 00543 case XBEE_API_ID_MOD_STAT: 00544 handleModemStatus(buf[1]); 00545 break; 00546 default: 00547 debug("Xbee: Unhandled API ID: %x\r\n ", buf[0]); 00548 00549 break; 00550 } 00551 00552 } 00553 00554 void XBee::handleAtResponse(uint8_t frameId, char* atBuf, uint8_t status, 00555 char* valueBuf, uint32_t valueLen) 00556 { 00557 00558 if (strncmp("ND", (char*)atBuf, 2) == 0) { 00559 handleDiscovery(status, valueBuf, valueLen); 00560 } 00561 00562 } 00563 00564 void XBee::handleDiscovery(uint8_t status, char* buf, uint32_t len) 00565 { 00566 00567 if (status == 0 && len >= 11) { 00568 _addrHi = bufTo32bitInt(&buf[2]); 00569 _addrLo = bufTo32bitInt(&buf[6]); 00570 _rssi = buf[10]; 00571 00572 _callbacks[CbNodeFound].call(); 00573 00574 } 00575 } 00576 00577 void XBee::handleTxStatus(uint8_t frameId, uint8_t status) 00578 { 00579 _frameId = frameId; 00580 switch(status) { 00581 case XBEE_TX_STAT_SUCCESS: 00582 _txStatus = TxStatusOk; 00583 break; 00584 case XBEE_TX_STAT_NOACK: 00585 _txStatus = TxStatusNoAck; 00586 break; 00587 case XBEE_TX_STAT_CCA_FAIL: 00588 _txStatus = TxStatusCCA; 00589 break; 00590 case XBEE_TX_STAT_PURGED: 00591 _txStatus = TxStatusPurged; 00592 break; 00593 } 00594 00595 _callbacks[CbTxStat].call(); 00596 00597 } 00598 00599 void XBee::processData(uint32_t addrHi, uint32_t addrLo, uint8_t rssi, 00600 uint8_t opt, char* buf, uint32_t len) 00601 { 00602 _addrHi = addrHi; 00603 _addrLo = addrLo; 00604 _rssi = rssi; 00605 _recvData = buf; 00606 _recvLen = len; 00607 00608 _callbacks[CbDataAvailable].call(); 00609 } 00610 00611 void XBee::handleModemStatus(uint8_t status) { 00612 00613 if (_type == Coordinator && status == XBEE_MOD_STAT_COORD_START) { 00614 _initialized = true; 00615 _callbacks[CbDeviceUp].call(); 00616 } 00617 else if (_type == EndDevice && status == XBEE_MOD_STAT_ASSOC) { 00618 _initialized = 1; 00619 _callbacks[CbDeviceUp].call(); 00620 } 00621 else if (_type == EndDevice && status == XBEE_MOD_STAT_DIASSOC) { 00622 _initialized = false; 00623 _callbacks[CbDeviceDown].call(); 00624 } 00625 00626 } 00627 00628 char XBee::checksum(char* buf, uint32_t len) 00629 { 00630 int i = 0; 00631 char cs = 0; 00632 00633 for (i = 0; i < (int)len; i++) { 00634 cs += buf[i]; 00635 } 00636 00637 return (0xFF - cs); 00638 } 00639 00640 uint32_t XBee::bufTo32bitInt(const char* buf) 00641 { 00642 uint32_t v = 0; 00643 00644 v |= (buf[0] << 24); 00645 v |= (buf[1] << 16); 00646 v |= (buf[2] << 8); 00647 v |= (buf[3]); 00648 00649 return v; 00650 } 00651 00652 void XBee::int32bitToBuf(uint32_t v, char* buf) 00653 { 00654 00655 buf[0] = ((v >> 24) & 0xff); 00656 buf[1] = ((v >> 16) & 0xff); 00657 buf[2] = ((v >> 8) & 0xff); 00658 buf[3] = ((v >> 0) & 0xff); 00659 00660 } 00661 00662 00663 XBee::XBeeError XBee::apiTx64(uint32_t addrHi, uint32_t addrLo, char* data, 00664 uint32_t len, uint8_t* frameId) 00665 { 00666 char buf[100]; 00667 00668 00669 // limiting to 85 bytes data. Remaining 15 bytes belong to the 00670 // frame 00671 if (len > 85) { 00672 return ArgumentError; 00673 } 00674 00675 buf[0] = XBEE_START_DEL; 00676 00677 // length 00678 buf[1] = 0; 00679 buf[2] = 11+len; 00680 00681 // AP ID 00682 buf[3] = XBEE_API_ID_TX_64; 00683 00684 // frame ID 00685 buf[4] = getFrameId(); 00686 00687 00688 // address 00689 int32bitToBuf(addrHi, &buf[5]); 00690 int32bitToBuf(addrLo, &buf[9]); 00691 00692 // options 00693 buf[13] = 0; 00694 00695 // data 00696 memcpy(&buf[14], data, len); 00697 00698 // checksum 00699 buf[14+len] = checksum(&buf[3], buf[2]); 00700 00701 if (frameId != NULL) { 00702 *frameId = buf[4]; 00703 } 00704 00705 00706 for (int i = 0; i < (15+len); i++) { 00707 _serial.putc(buf[i]); 00708 } 00709 00710 00711 return Ok; 00712 } 00713 00714 XBee::XBeeError XBee::apiAtCmd(const char* atCmd, uint32_t param, bool useParameter) 00715 { 00716 char buf[12]; 00717 int pos = 0; 00718 00719 buf[0] = XBEE_START_DEL; 00720 00721 // length 00722 buf[1] = 0; 00723 buf[2] = 4; 00724 if (useParameter) { 00725 buf[2] += 4; 00726 } 00727 00728 // AP ID 00729 buf[3] = XBEE_API_ID_AT_CMD; 00730 00731 // frame ID 00732 buf[4] = getFrameId(); 00733 00734 // AT cmd 00735 buf[5] = atCmd[0]; 00736 buf[6] = atCmd[1]; 00737 pos = 7; 00738 00739 // AT parameter 00740 if (useParameter) { 00741 buf[pos++] = ((param >> 24) & 0xff); 00742 buf[pos++] = ((param >> 16) & 0xff); 00743 buf[pos++] = ((param >> 8) & 0xff); 00744 buf[pos++] = ((param >> 0) & 0xff); 00745 } 00746 00747 // checksum 00748 buf[pos] = checksum(&buf[3], pos-3); 00749 pos++; 00750 00751 for (int i = 0; i < pos; i++) { 00752 _serial.putc(buf[i]); 00753 } 00754 00755 return Ok; 00756 } 00757 00758 uint8_t XBee::getFrameId(void) 00759 { 00760 _rfFrameId++; 00761 if (_rfFrameId == 0) { 00762 _rfFrameId = 1; 00763 } 00764 00765 return _rfFrameId; 00766 }
Generated on Wed Jul 13 2022 02:29:31 by 1.7.2