pwm period is now 200us instead of the default 20ms veml6040 config is now AF_BIT | TRIG_BIT

Dependencies:   mbed MMA8451Q USBDevice WakeUp vt100

Fork of afero_node_suntory_2017_06_15 by Orefatoi

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers afLib.cpp Source File

afLib.cpp

00001 /**
00002  * Copyright 2015 Afero, Inc.
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 "afLib.h"
00019 #include "afErrors.h"
00020 #include "msg_types.h"
00021 
00022 #define IS_MCU_ATTR(x) (x >= 0 && x < 1024)
00023 
00024 static iafLib *_iaflib = NULL;
00025 
00026 #define MAX_SYNC_RETRIES    10
00027 static long lastSync = 0;
00028 static int syncRetries = 0;
00029 
00030 /**
00031  * create
00032  *
00033  * The public constructor for the afLib. This allows us to create the afLib object once and hold a reference to it.
00034  */
00035 iafLib *iafLib::create(PinName mcuInterrupt, isr isrWrapper,
00036         onAttributeSet attrSet, onAttributeSetComplete attrSetComplete, afSPI *theSPI)
00037 {
00038     if (_iaflib == NULL) {
00039         _iaflib = new afLib( mcuInterrupt, isrWrapper, attrSet, attrSetComplete, theSPI);
00040     }
00041 
00042     return _iaflib;
00043 }
00044 
00045 void iafLib::destroy()
00046 {
00047     afLib *p = (afLib*)_iaflib;
00048     delete p;
00049     _iaflib = NULL;
00050 }
00051 /**
00052  * afLib
00053  *
00054  * The private constructor for the afLib. This one actually initializes the afLib and prepares it for use.
00055  */
00056 afLib::afLib(PinName mcuInterrupt, isr isrWrapper,
00057     onAttributeSet attrSet, onAttributeSetComplete attrSetComplete, afSPI *theSPI) : fco(mcuInterrupt)
00058 {
00059     checkLastSync = new Timer();
00060     checkLastSync->start();
00061     queueInit();
00062     _theSPI= theSPI;
00063     _request.p_value = NULL;
00064 
00065     //_spiSettings = SPISettings(1000000, LSBFIRST, SPI_MODE0);
00066     _interrupts_pending = 0;
00067     _state = STATE_IDLE;
00068 
00069     _writeCmd = NULL;
00070     _writeCmdOffset = 0;
00071 
00072     _outstandingSetGetAttrId = 0;
00073 
00074     _readCmd = NULL;
00075     _readCmdOffset = 0;
00076     _readBufferLen = 0;
00077 
00078     _txStatus = new StatusCommand();
00079     _rxStatus = new StatusCommand();
00080 
00081     _onAttrSet = attrSet;
00082     _onAttrSetComplete = attrSetComplete;
00083     _theSPI->begin();
00084 
00085     // AJS where does this get moved to??
00086     #ifdef ARDUINO
00087     pinMode(mcuInterrupt, INPUT);
00088     attachInterrupt(mcuInterrupt, isrWrapper, FALLING);
00089     #endif
00090     fco.fall(isrWrapper);
00091     SERIAL_PRINT_DBG_ASR("afLib init done!!\n");
00092 }
00093 //wsugi 20161128
00094 afLib::~afLib()
00095 {
00096     SERIAL_PRINT_DBG_ASR("deleted\n");
00097     if(_readBuffer != NULL)
00098     {
00099         delete[] (_readBuffer);
00100         _readBuffer = NULL;
00101     }
00102     
00103     if(_writeBuffer != NULL)
00104     {
00105         delete[] (_writeBuffer);
00106         _writeBuffer = NULL;
00107     }
00108     
00109     if(_readCmd != NULL)
00110     {
00111         delete (_readCmd);
00112         _readCmd = NULL;
00113     }
00114     
00115     if(_writeCmd != NULL)
00116     {
00117         delete (_writeCmd);
00118         _writeCmd = NULL;
00119     }
00120     
00121     if(_txStatus != NULL)
00122     {
00123         delete (_txStatus);
00124         _txStatus = NULL;
00125     }
00126     
00127     if(_rxStatus != NULL)
00128     {
00129         delete (_rxStatus);
00130         _rxStatus = NULL;
00131     }
00132     
00133     for (int i = 0; i < REQUEST_QUEUE_SIZE; i++)
00134     {
00135         if (_requestQueue[i].p_value != NULL)
00136         {
00137             delete[] (_requestQueue[i].p_value);
00138             _requestQueue[i].p_value = NULL;
00139         }
00140     }
00141     
00142     if(checkLastSync != NULL)
00143     {
00144         delete (checkLastSync);
00145         checkLastSync = NULL;
00146     }
00147     
00148     _iaflib = NULL;
00149 }
00150 //wsugi 20161128
00151 /**
00152  * loop
00153  *
00154  * This is how the afLib gets time to run its state machine. This method should be called periodically from the
00155  * loop() function of the Arduino sketch.
00156  * This function pulls pending attribute operations from the queue. It takes approximately 4 calls to loop() to
00157  * complete one attribute operation.
00158  */
00159 void afLib::loop(void) {
00160     if (isIdle())
00161     {
00162         deathWish.attach(callback(WatchDogWrapper::getSelf(), &WatchDogWrapper::kick_the_bucket),10);
00163 //        deathWish.attach(&afLib::kick_the_bucket,10);
00164     }
00165     if (isIdle() && (queueGet(&_request.messageType, &_request.requestId, &_request.attrId, &_request.valueLen,
00166                               &_request.p_value) == afSUCCESS)) {
00167         switch (_request.messageType) {
00168             case MSG_TYPE_GET:
00169                 doGetAttribute(_request.requestId, _request.attrId);
00170                 break;
00171 
00172             case MSG_TYPE_SET:
00173                 doSetAttribute(_request.requestId, _request.attrId, _request.valueLen, _request.p_value);
00174                 break;
00175 
00176             case MSG_TYPE_UPDATE:
00177                 doUpdateAttribute(_request.requestId, _request.attrId, 0, _request.valueLen, _request.p_value);
00178                 break;
00179 
00180             default:
00181                 SERIAL_PRINT_DBG_ASR("%s\n","loop: request type!");
00182         }
00183     }
00184 
00185     if (_request.p_value != NULL) {
00186         delete[] (_request.p_value); //wsugi delete (_request.p_value);
00187         _request.p_value = NULL;
00188     }
00189     runStateMachine();
00190 }
00191 
00192 /**
00193  * updateIntsPending
00194  *
00195  * Interrupt-safe method for updating the interrupt count. This is called to increment and decrement the interrupt count
00196  * as interrupts are received and handled.
00197  */
00198 void afLib::updateIntsPending(int amount) {
00199     fco.disable_irq();
00200     _interrupts_pending += amount;
00201     fco.enable_irq();
00202 }
00203 
00204 /**
00205  * sendCommand
00206  *
00207  * This increments the interrupt count to kick off the state machine in the next call to loop().
00208  */
00209 void afLib::sendCommand(void) {
00210     fco.disable_irq();
00211     if (_interrupts_pending == 0 && _state == STATE_IDLE) {
00212         updateIntsPending(1);
00213     }
00214     fco.enable_irq();
00215 }
00216 
00217 /**
00218  * getAttribute
00219  *
00220  * The public getAttribute method. This method queues the operation and returns immediately. Applications must call
00221  * loop() for the operation to complete.
00222  */
00223 int afLib::getAttribute(const uint16_t attrId) {
00224     _requestId++;
00225     uint8_t dummy; // This value isn't actually used.
00226     return queuePut(MSG_TYPE_GET, _requestId++, attrId, 0, &dummy);
00227 }
00228 
00229 /**
00230  * The many moods of setAttribute
00231  *
00232  * These are the public versions of the setAttribute method.
00233  * These methods queue the operation and return immediately. Applications must call loop() for the operation to complete.
00234  */
00235 int afLib::setAttributeBool(const uint16_t attrId, const bool value) {
00236     _requestId++;
00237     uint8_t val = value ? 1 : 0;
00238     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(val),
00239                     (uint8_t *)&val);
00240 }
00241 
00242 int afLib::setAttribute8(const uint16_t attrId, const int8_t value) {
00243     _requestId++;
00244     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
00245                     (uint8_t *)&value);
00246 }
00247 
00248 int afLib::setAttribute16(const uint16_t attrId, const int16_t value) {
00249     _requestId++;
00250     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
00251                     (uint8_t *) &value);
00252 }
00253 
00254 int afLib::setAttribute32(const uint16_t attrId, const int32_t value) {
00255     _requestId++;
00256     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
00257                     (uint8_t *) &value);
00258 }
00259 
00260 int afLib::setAttribute64(const uint16_t attrId, const int64_t value) {
00261     _requestId++;
00262     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
00263                     (uint8_t *) &value);
00264 }
00265 
00266 int afLib::setAttribute(const uint16_t attrId, const string &value) {
00267     _requestId++;
00268     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, value.length(),
00269                     (uint8_t *) value.c_str());
00270 }
00271 
00272 int afLib::setAttribute(const uint16_t attrId, const uint16_t valueLen, const char *value) {
00273     if (valueLen > MAX_ATTRIBUTE_SIZE) {
00274         return afERROR_INVALID_PARAM;
00275     }
00276 
00277     if (value == NULL) {
00278         return afERROR_INVALID_PARAM;
00279     }
00280 
00281     _requestId++;
00282     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, valueLen,
00283                     (const uint8_t *) value);
00284 }
00285 
00286 int afLib::setAttribute(const uint16_t attrId, const uint16_t valueLen, const uint8_t *value) {
00287     if (valueLen > MAX_ATTRIBUTE_SIZE) {
00288         return afERROR_INVALID_PARAM;
00289     }
00290 
00291     if (value == NULL) {
00292         return afERROR_INVALID_PARAM;
00293     }
00294 
00295     _requestId++;
00296     return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, valueLen, value);
00297 }
00298 
00299 int afLib::setAttributeComplete(uint8_t requestId, const uint16_t attrId, const uint16_t valueLen, const uint8_t *value) {
00300     if (valueLen > MAX_ATTRIBUTE_SIZE) {
00301         return afERROR_INVALID_PARAM;
00302     }
00303 
00304     if (value == NULL) {
00305         return afERROR_INVALID_PARAM;
00306     }
00307 
00308     return queuePut(MSG_TYPE_UPDATE, requestId, attrId, valueLen, value);
00309 }
00310 
00311 /**
00312  * doGetAttribute
00313  *
00314  * The private version of getAttribute. This version actually calls sendCommand() to kick off the state machine and
00315  * execute the operation.
00316  */
00317 int afLib::doGetAttribute(uint8_t requestId, uint16_t attrId) {
00318     if (_interrupts_pending > 0 || _writeCmd != NULL) {
00319         return afERROR_BUSY;
00320     }
00321 
00322     _writeCmd = new Command(requestId, MSG_TYPE_GET, attrId);
00323     if (!_writeCmd->isValid()) {
00324         SERIAL_PRINT_DBG_ASR("getAttribute invalid command:");
00325         _writeCmd->dumpBytes();
00326         _writeCmd->dump();
00327         delete (_writeCmd);
00328         _writeCmd = NULL;
00329         return afERROR_INVALID_COMMAND;
00330     }
00331 
00332     _outstandingSetGetAttrId = attrId;
00333 
00334     // Start the transmission.
00335     sendCommand();
00336 
00337     return afSUCCESS;
00338 }
00339 
00340 /**
00341  * doSetAttribute
00342  *
00343  * The private version of setAttribute. This version actually calls sendCommand() to kick off the state machine and
00344  * execute the operation.
00345  */
00346 int afLib::doSetAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value) {
00347     if (_interrupts_pending > 0 || _writeCmd != NULL) {
00348         return afERROR_BUSY;
00349     }
00350     _writeCmd = new Command(requestId, MSG_TYPE_SET, attrId, valueLen, value);
00351     if (!_writeCmd->isValid()) {
00352         SERIAL_PRINT_DBG_ASR("setAttributeComplete invalid command:");
00353         _writeCmd->dumpBytes();
00354         _writeCmd->dump();
00355         delete (_writeCmd);
00356         _writeCmd = NULL;
00357         return afERROR_INVALID_COMMAND;
00358     }
00359 
00360     _outstandingSetGetAttrId = attrId;
00361 
00362     // Start the transmission.
00363     sendCommand();
00364 
00365     return afSUCCESS;
00366 }
00367 
00368 /**
00369  * doUpdateAttribute
00370  *
00371  * setAttribute calls on MCU attributes turn into updateAttribute calls. See documentation on the SPI protocol for
00372  * more information. This method calls sendCommand() to kick off the state machine and execute the operation.
00373  */
00374 int afLib::doUpdateAttribute(uint8_t requestId, uint16_t attrId, uint8_t status, uint16_t valueLen, uint8_t *value) {
00375     if (_interrupts_pending > 0 || _writeCmd != NULL) {
00376         return afERROR_BUSY;
00377     }
00378 
00379     _writeCmd = new Command(requestId, MSG_TYPE_UPDATE, attrId, status, 3 /* MCU Set it */, valueLen, value);
00380     if (!_writeCmd->isValid()) {
00381         SERIAL_PRINT_DBG_ASR("updateAttribute invalid command:");
00382         _writeCmd->dumpBytes();
00383         _writeCmd->dump();
00384         delete (_writeCmd);
00385         return afERROR_INVALID_COMMAND;
00386     }
00387 
00388     // Start the transmission.
00389     sendCommand();
00390 
00391     return afSUCCESS;
00392 }
00393 
00394 /**
00395  * parseCommand
00396  *
00397  * A debug method for parsing a string into a command. This is not required for library operation and is only supplied
00398  * as an example of how to execute attribute operations from a command line interface.
00399  */
00400 #ifdef ATTRIBUTE_CLI
00401 int afLib::parseCommand(const char *cmd) {
00402     if (_interrupts_pending > 0 || _writeCmd != NULL) {
00403         _theLog->print("Busy: ");
00404         _theLog->print(_interrupts_pending);
00405         _theLog->print(", ");
00406         _theLog->println(_writeCmd != NULL);
00407         return afERROR_BUSY;
00408     }
00409 
00410     int reqId = _requestId++;
00411     _writeCmd = new Command(_theLog,reqId, cmd);
00412     if (!_writeCmd->isValid()) {
00413         _theLog->print("BAD: ");
00414         _theLog->println(cmd);
00415         _writeCmd->dumpBytes();
00416         _writeCmd->dump();
00417         delete (_writeCmd);
00418         _writeCmd = NULL;
00419         return afERROR_INVALID_COMMAND;
00420     }
00421 
00422     // Start the transmission.
00423     sendCommand();
00424 
00425     return afSUCCESS;
00426 }
00427 #endif
00428 
00429 /**
00430  * runStateMachine
00431  *
00432  * The state machine for afLib. This state machine is responsible for implementing the KSP SPI protocol and executing
00433  * attribute operations.
00434  * This method is run:
00435  *      1. In response to receiving an interrupt from the ASR-1.
00436  *      2. When an attribute operation is pulled out of the queue and executed.
00437  */
00438 void afLib::runStateMachine(void) {
00439     if (_interrupts_pending > 0) {
00440         switch (_state) {
00441             case STATE_IDLE:
00442                 //deathWish.attach(&afLib::kick_the_bucket,10);
00443                 onStateIdle();
00444                 return;
00445 
00446             case STATE_STATUS_SYNC:
00447                 onStateSync();
00448                 break;
00449 
00450             case STATE_STATUS_ACK:
00451                 onStateAck();
00452                 break;
00453 
00454             case STATE_SEND_BYTES:
00455                 onStateSendBytes();
00456                 break;
00457 
00458             case STATE_RECV_BYTES:
00459                 onStateRecvBytes();
00460                 break;
00461 
00462             case STATE_CMD_COMPLETE:
00463                 onStateCmdComplete();
00464                 break;
00465         }
00466 
00467         updateIntsPending(-1);
00468     } else {
00469         if (syncRetries > 0 && syncRetries < MAX_SYNC_RETRIES && checkLastSync->read_ms() - lastSync > 1000) {
00470             updateIntsPending(1);
00471         } else if (syncRetries >= MAX_SYNC_RETRIES) {
00472             SERIAL_PRINT_DBG_ASR("No response from ASR-1 - does profile have MCU enabled?\n");
00473 #if defined(TARGET_KL25Z)
00474             WatchDogWrapper::getSelf()->kick_the_bucket();
00475 #endif //TARGET_KL25Z
00476             syncRetries = 0;
00477             _state = STATE_IDLE;
00478         }
00479     }
00480 }
00481 
00482 /**
00483  * onStateIdle
00484  *
00485  * If there is a command to be written, update the bytes to send. Otherwise we're sending a zero-sync message.
00486  * Either way advance the state to send a sync message.
00487  */
00488 void afLib::onStateIdle(void) {
00489     if (_writeCmd != NULL) {
00490         // Include 2 bytes for length
00491         _bytesToSend = _writeCmd->getSize() + 2;
00492     } else {
00493         _bytesToSend = 0;
00494     }
00495     _state = STATE_STATUS_SYNC;
00496     printState(_state);
00497 }
00498 
00499 /**
00500  * onStateSync
00501  *
00502  * Write a sync message over SPI to let the ASR-1 know that we want to send some data.
00503  * Check for a "collision" which occurs if the ASR-1 is trying to send us data at the same time.
00504  */
00505 void afLib::onStateSync(void) {
00506     int result;
00507 
00508     _txStatus->setAck(false);
00509     _txStatus->setBytesToSend(_bytesToSend);
00510     _txStatus->setBytesToRecv(0);
00511 
00512     result = exchangeStatus(_txStatus, _rxStatus);
00513     
00514     if (result == afSUCCESS && _rxStatus->isValid() && inSync(_txStatus, _rxStatus)) {
00515         syncRetries = 0;   // Flag that sync completed.
00516         _state = STATE_STATUS_ACK;
00517         if (_txStatus->getBytesToSend() == 0 && _rxStatus->getBytesToRecv() > 0) {
00518             _bytesToRecv = _rxStatus->getBytesToRecv();
00519         }
00520     } else {
00521         // Try resending the preamble
00522         _state = STATE_STATUS_SYNC;
00523         lastSync = checkLastSync->read_ms();
00524         syncRetries++;
00525 //          _txStatus->dumpBytes();
00526 //          _rxStatus->dumpBytes();
00527     }
00528     printState(_state);
00529 }
00530 
00531 /**
00532  * onStateAck
00533  *
00534  * Acknowledge the previous sync message and advance the state.
00535  * If there are bytes to send, advance to send bytes state.
00536  * If there are bytes to receive, advance to receive bytes state.
00537  * Otherwise it was a zero-sync so advance to command complete.
00538  */
00539 void afLib::onStateAck(void) {
00540     int result;
00541 
00542     _txStatus->setAck(true);
00543     _txStatus->setBytesToRecv(_rxStatus->getBytesToRecv());
00544     _bytesToRecv = _rxStatus->getBytesToRecv();
00545     result = writeStatus(_txStatus);
00546     if (result != afSUCCESS) {
00547         _state = STATE_STATUS_SYNC;
00548         printState(_state);
00549         return;
00550     }
00551     if (_bytesToSend > 0) {
00552         _writeBufferLen = (uint16_t) _writeCmd->getSize();
00553         _writeBuffer = new uint8_t[_bytesToSend];
00554         memcpy(_writeBuffer, (uint8_t * ) & _writeBufferLen, 2);
00555         _writeCmd->getBytes(&_writeBuffer[2]);
00556         _state = STATE_SEND_BYTES;
00557     } else if (_bytesToRecv > 0) {
00558         _state = STATE_RECV_BYTES;
00559     } else {
00560         _state = STATE_CMD_COMPLETE;
00561     }
00562     printState(_state);
00563 }
00564 
00565 /**
00566  * onStateSendBytes
00567  *
00568  * Send the required number of bytes to the ASR-1 and then advance to command complete.
00569  */
00570 void afLib::onStateSendBytes(void) {
00571 //        _theLog->print("send bytes: "); _theLog->println(_bytesToSend);
00572     sendBytes();
00573 
00574     if (_bytesToSend == 0) {
00575         _writeBufferLen = 0;
00576         delete[] (_writeBuffer); //wsugi delete (_writeBuffer);
00577         _writeBuffer = NULL;
00578         _state = STATE_CMD_COMPLETE;
00579         printState(_state);
00580     }
00581 }
00582 
00583 /**
00584  * onStateRecvBytes
00585  *
00586  * Receive the required number of bytes from the ASR-1 and then advance to command complete.
00587  */
00588 void afLib::onStateRecvBytes(void) {
00589 //        _theLog->print("receive bytes: "); _theLog->println(_bytesToRecv);
00590     recvBytes();
00591     if (_bytesToRecv == 0) {
00592         _state = STATE_CMD_COMPLETE;
00593         printState(_state);
00594         _readCmd = new Command(_readBufferLen, &_readBuffer[2]);
00595         delete[] (_readBuffer); //wsugi delete (_readBuffer);
00596         _readBuffer = NULL;
00597     }
00598 }
00599 
00600 /**
00601  * onStateCmdComplete
00602  *
00603  * Call the appropriate sketch callback to report the result of the command.
00604  * Clear the command object and go back to waiting for the next interrupt or command.
00605  */
00606 void afLib::onStateCmdComplete(void) {
00607     _state = STATE_IDLE;
00608     printState(_state);
00609     if (_readCmd != NULL) {
00610         uint8_t *val = new uint8_t[_readCmd->getValueLen()];
00611         _readCmd->getValue(val);
00612 
00613         switch (_readCmd->getCommand()) {
00614             case MSG_TYPE_SET:
00615                 _onAttrSet(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val);
00616                 break;
00617 
00618             case MSG_TYPE_UPDATE:
00619                 if (_readCmd->getAttrId() == _outstandingSetGetAttrId) {
00620                     _outstandingSetGetAttrId = 0;
00621                 }
00622                 _onAttrSetComplete(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val);
00623                 break;
00624 
00625             default:
00626                 break;
00627         }
00628         delete[] (val); //wsugi delete (val);
00629         delete (_readCmd);
00630         _readCmdOffset = 0;
00631         _readCmd = NULL;
00632     }
00633 
00634     if (_writeCmd != NULL) {
00635         // Fake a callback here for MCU attributes as we don't get one from the module.
00636         if (_writeCmd->getCommand() == MSG_TYPE_UPDATE && IS_MCU_ATTR(_writeCmd->getAttrId())) {
00637             _onAttrSetComplete(_writeCmd->getReqId(), _writeCmd->getAttrId(), _writeCmd->getValueLen(), _writeCmd->getValueP());
00638         }
00639         delete (_writeCmd);
00640         _writeCmdOffset = 0;
00641         _writeCmd = NULL;
00642     }
00643 }
00644 
00645 /**
00646  * exchangeStatus
00647  *
00648  * Write a status command object to the ASR-1 and clock in a status object from the ASR-1 at the same time.
00649  */
00650 int afLib::exchangeStatus(StatusCommand *tx, StatusCommand *rx) {
00651     int result = afSUCCESS;
00652     uint16_t len = tx->getSize();
00653     int bytes[len];
00654     char rbytes[len+1];
00655     int index = 0;
00656     tx->getBytes(bytes);
00657 
00658 //    _theSPI->beginSPI();
00659 
00660     for (int i=0;i<len;i++)
00661     {
00662       rbytes[i]=bytes[i];
00663     }
00664     rbytes[len]=tx->getChecksum();
00665     
00666     printTransaction((uint8_t*)rbytes,len+1);
00667 
00668     _theSPI->beginSPI();
00669     _theSPI->transfer(rbytes,len+1);
00670     _theSPI->endSPI();
00671     
00672     printTransaction((uint8_t*)rbytes,len+1);
00673 
00674     uint8_t cmd = bytes[index++];
00675     if (cmd != 0x30 && cmd != 0x31) {
00676         SERIAL_PRINT_DBG_ASR("exchangeStatus bad cmd: 0x%02x\n",cmd);
00677         result = afERROR_INVALID_COMMAND;
00678     }
00679 
00680     rx->setBytesToSend(rbytes[index + 0] | (rbytes[index + 1] << 8));
00681     rx->setBytesToRecv(rbytes[index + 2] | (rbytes[index + 3] << 8));
00682     rx->setChecksum(rbytes[index+4]);
00683     //_theSPI->endSPI();
00684     return result;
00685 }
00686 
00687 /**
00688  * inSync
00689  *
00690  * Check to make sure the Arduino and the ASR-1 aren't trying to send data at the same time.
00691  * Return true only if there is no collision.
00692  */
00693 bool afLib::inSync(StatusCommand *tx, StatusCommand *rx) {
00694     return (tx->getBytesToSend() == 0 && rx->getBytesToRecv() == 0) ||
00695            (tx->getBytesToSend() > 0 && rx->getBytesToRecv() == 0) ||
00696            (tx->getBytesToSend() == 0 && rx->getBytesToRecv() > 0);
00697 }
00698 
00699 /**
00700  * writeStatus
00701  *
00702  * Write a status command to the ASR-1 and ignore the result. If you want to read bytes at the same time, use
00703  * exchangeStatus instead.
00704  */
00705 int afLib::writeStatus(StatusCommand *c) {
00706     int result = afSUCCESS;
00707     uint16_t len = c->getSize();
00708     int bytes[len];
00709     char rbytes[len+1];
00710     int index = 0;
00711     c->getBytes(bytes);
00712 
00713     _theSPI->beginSPI();
00714 
00715     for (int i=0;i<len;i++)
00716     {
00717       rbytes[i]=bytes[i];
00718     }
00719     rbytes[len]=c->getChecksum();
00720     printTransaction((uint8_t*)rbytes,len+1);
00721     _theSPI->transfer(rbytes,len+1);
00722     printTransaction((uint8_t*)rbytes,len+1);
00723     uint8_t cmd = rbytes[index++];
00724     if (cmd != 0x30 && cmd != 0x31) {
00725         SERIAL_PRINT_DBG_ASR("writeStatus bad cmd: 0x%02x\n",cmd);
00726         result = afERROR_INVALID_COMMAND;
00727     }
00728 
00729 
00730     _theSPI->endSPI();
00731 
00732 //  c->dump();
00733 //  c->dumpBytes();
00734 
00735     return result;
00736 }
00737 
00738 /**
00739  * sendBytes
00740  *
00741  * Send the specified number of data bytes to the ASR-1. Do this in chunks of SPI_FRAME_LEN bytes.
00742  */
00743 void afLib::sendBytes() {
00744     uint16_t len = _bytesToSend > SPI_FRAME_LEN ? SPI_FRAME_LEN : _bytesToSend;
00745     uint8_t bytes[SPI_FRAME_LEN];
00746     memset(bytes, 0xff, sizeof(bytes));
00747 
00748     memcpy(bytes, &_writeBuffer[_writeCmdOffset], len);
00749 
00750     _theSPI->beginSPI();
00751     printTransaction(bytes,len+1);
00752     _theSPI->transfer((char *)bytes,len);
00753     printTransaction(bytes,len+1);
00754     _theSPI->endSPI();
00755 
00756 //  dumpBytes("Sending:", len, bytes);
00757 
00758     _writeCmdOffset += len;
00759     _bytesToSend -= len;
00760 }
00761 
00762 /**
00763  * recvBytes
00764  *
00765  * Receive the specified number of data bytes from the ASR-1. Do this in chunks of SPI_FRAME_LEN bytes.
00766  */
00767 void afLib::recvBytes() {
00768     uint16_t len = _bytesToRecv > SPI_FRAME_LEN ? SPI_FRAME_LEN : _bytesToRecv;
00769 
00770     if (_readCmdOffset == 0) {
00771         _readBufferLen = _bytesToRecv;
00772         _readBuffer = new uint8_t[_readBufferLen];
00773     }
00774 
00775     _theSPI->beginSPI();
00776 
00777 
00778     char * start =(char*)_readBuffer + _readCmdOffset;
00779     printTransaction((uint8_t*)start,len+1);
00780     _theSPI->transfer(start,len);
00781     printTransaction((uint8_t*)start,len+1);
00782 
00783     _theSPI->endSPI();
00784 
00785 //  dumpBytes("Receiving:", len, _readBuffer);
00786 
00787     _readCmdOffset += len;
00788     _bytesToRecv -= len;
00789 }
00790 
00791 /**
00792  * isIdle
00793  *
00794  * Provide a way for the sketch to know if we're idle. Returns true if there are no attribute operations in progress.
00795  */
00796 bool afLib::isIdle() {
00797     return _interrupts_pending == 0 && _state == STATE_IDLE && _outstandingSetGetAttrId == 0;
00798 }
00799 
00800 /**
00801  * These methods are required to disable/enable interrupts for the Linux version of afLib.
00802  * They are no-ops on Arduino.
00803  */
00804 #ifndef ARDUINO
00805 void noInterrupts(){}
00806     void interrupts(){}
00807 #endif
00808 
00809 void afLib::mcuISR() {
00810 //  _theLog->println("mcu");
00811     updateIntsPending(1);
00812 }
00813 
00814 /****************************************************************************
00815  *                              Queue Methods                               *
00816  ****************************************************************************/
00817 /**
00818  * queueInit
00819  *
00820  * Create a small queue to prevent flooding the ASR-1 with attribute operations.
00821  * The initial size is small to allow running on small boards like UNO.
00822  * Size can be increased on larger boards.
00823  */
00824 void afLib::queueInit() {
00825     for (int i = 0; i < REQUEST_QUEUE_SIZE; i++) {
00826         _requestQueue[i].p_value = NULL;
00827     }
00828 }
00829 
00830 /**
00831  * queuePut
00832  *
00833  * Add an item to the end of the queue. Return an error if we're out of space in the queue.
00834  */
00835 int afLib::queuePut(uint8_t messageType, uint8_t requestId, const uint16_t attributeId, uint16_t valueLen,
00836                     const uint8_t *value) {
00837     for (int i = 0; i < REQUEST_QUEUE_SIZE; i++) {
00838         if (_requestQueue[i].p_value == NULL) {
00839             _requestQueue[i].messageType = messageType;
00840             _requestQueue[i].attrId = attributeId;
00841             _requestQueue[i].requestId = requestId;
00842             _requestQueue[i].valueLen = valueLen;
00843             _requestQueue[i].p_value = new uint8_t[valueLen];
00844             memcpy(_requestQueue[i].p_value, value, valueLen);
00845             return afSUCCESS;
00846         }
00847     }
00848 
00849     return afERROR_QUEUE_OVERFLOW;
00850 }
00851 
00852 /**
00853  * queueGet
00854  *
00855  * Pull and return the oldest item from the queue. Return an error if the queue is empty.
00856  */
00857 int afLib::queueGet(uint8_t *messageType, uint8_t *requestId, uint16_t *attributeId, uint16_t *valueLen,
00858                     uint8_t **value) {
00859     for (int i = 0; i < REQUEST_QUEUE_SIZE; i++) {
00860         if (_requestQueue[i].p_value != NULL) {
00861             *messageType = _requestQueue[i].messageType;
00862             *attributeId = _requestQueue[i].attrId;
00863             *requestId = _requestQueue[i].requestId;
00864             *valueLen = _requestQueue[i].valueLen;
00865             *value = new uint8_t[*valueLen];
00866             memcpy(*value, _requestQueue[i].p_value, *valueLen);
00867             delete[] (_requestQueue[i].p_value); //wsugi delete (_requestQueue[i].p_value);
00868             _requestQueue[i].p_value = NULL;
00869             return afSUCCESS;
00870         }
00871     }
00872 
00873     return afERROR_QUEUE_UNDERFLOW;
00874 }
00875 
00876 /****************************************************************************
00877  *                              Debug Methods                               *
00878  ****************************************************************************/
00879 /**
00880  * dumpBytes
00881  *
00882  * Dump a byte buffer to the debug log.
00883  */
00884 void afLib::dumpBytes(char *label, int len, uint8_t *bytes) {
00885     SERIAL_PRINT_DBG_ASR("%s\n",label);
00886     for (int i = 0; i < len; i++) {
00887         if (i > 0) {
00888             SERIAL_PRINT_DBG_ASR(", ");
00889         }
00890         uint8_t b = bytes[i] & 0xff;
00891 
00892         if (b < 0x10) {
00893             SERIAL_PRINT_DBG_ASR("0x02x", b);
00894         } else {
00895             //_theLog->print("0x");
00896             SERIAL_PRINT_DBG_ASR("0x02x",b);//, HEX);
00897         }
00898     }
00899     SERIAL_PRINT_DBG_ASR("\n");
00900 }
00901 
00902 /**
00903  * printState
00904  *
00905  * Print the current state of the afLib state machine. For debugging, just remove the return statement.
00906  */
00907 void afLib::printState(int state) {
00908 //    return;
00909     switch (state) {
00910         case STATE_IDLE:
00911             SERIAL_PRINT_DBG_ASR("STATE_IDLE\n");
00912             break;
00913         case STATE_STATUS_SYNC:
00914             SERIAL_PRINT_DBG_ASR("STATE_STATUS_SYNC\n");
00915             break;
00916         case STATE_STATUS_ACK:
00917             SERIAL_PRINT_DBG_ASR("STATE_STATUS_ACK\n");
00918             break;
00919         case STATE_SEND_BYTES:
00920             SERIAL_PRINT_DBG_ASR("STATE_SEND_BYTES\n");
00921             break;
00922         case STATE_RECV_BYTES:
00923             SERIAL_PRINT_DBG_ASR("STATE_RECV_BYTES\n");
00924             break;
00925         case STATE_CMD_COMPLETE:
00926             SERIAL_PRINT_DBG_ASR("STATE_CMD_COMPLETE\n");
00927             break;
00928         default:
00929             SERIAL_PRINT_DBG_ASR("Unknown State!\n");
00930             break;
00931     }
00932 }
00933 
00934 void afLib::printTransaction(uint8_t *rbytes, int len)
00935 {
00936     //return;
00937     int i = 0;
00938     for(;i<=len;++i)
00939     {
00940         SERIAL_PRINT_DBG_ASR("0x%02x:",rbytes[i]);
00941     }
00942     SERIAL_PRINT_DBG_ASR("\n");
00943 }