A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers XBee.cpp Source File

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 }