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