Added a GPIO to power on/off for external I2C sensor(s) (with LEDs)

Dependencies:   UniGraphic mbed vt100

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