Color sensor reset at the end of calibration added. sensor id auto assignment was changed to be a fixed value assignment to avoid sensor id shift when some sensor is absent.
Dependencies: UniGraphic mbed vt100
Diff: afLib/afLib.cpp
- Revision:
- 0:ce97f6d34336
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/afLib/afLib.cpp Fri Feb 23 05:40:22 2018 +0000 @@ -0,0 +1,957 @@ +/** + * Copyright 2015 Afero, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed.h" +#include "afLib.h" +#include "afErrors.h" +#include "msg_types.h" +/* added by Motoo Tanaka on 26-Dec-2017 for watchdog */ +#include "edge_reset_mgr.h" + +#define IS_MCU_ATTR(x) (x >= 0 && x < 1024) + +static iafLib *_iaflib = NULL; + +#define MAX_SYNC_RETRIES 10 +static long lastSync = 0; +static int syncRetries = 0; + +/** + * create + * + * The public constructor for the afLib. This allows us to create the afLib object once and hold a reference to it. + */ +iafLib *iafLib::create(PinName mcuInterrupt, isr isrWrapper, + onAttributeSet attrSet, onAttributeSetComplete attrSetComplete, afSPI *theSPI) +{ + if (_iaflib == NULL) { + _iaflib = new afLib( mcuInterrupt, isrWrapper, attrSet, attrSetComplete, theSPI); + } + + return _iaflib; +} + +void iafLib::destroy() +{ + afLib *p = (afLib*)_iaflib; + delete p; + _iaflib = NULL; +} + +/** + * getRequestId + * by Motoo Tanaka on 16-Nov-2017 + */ +int afLib::getRequestId(void) +{ + return( _requestId ) ; +} + +/** + * afLib + * + * The private constructor for the afLib. This one actually initializes the afLib and prepares it for use. + */ +afLib::afLib(PinName mcuInterrupt, isr isrWrapper, + onAttributeSet attrSet, onAttributeSetComplete attrSetComplete, afSPI *theSPI) : fco(mcuInterrupt) +{ + checkLastSync = new Timer(); + checkLastSync->start(); + queueInit(); + _theSPI= theSPI; + _request.p_value = NULL; + + //_spiSettings = SPISettings(1000000, LSBFIRST, SPI_MODE0); + _interrupts_pending = 0; + _state = STATE_IDLE; + + _writeCmd = NULL; + _writeCmdOffset = 0; + + _outstandingSetGetAttrId = 0; + + _readCmd = NULL; + _readCmdOffset = 0; + _readBufferLen = 0; + + _txStatus = new StatusCommand(); + _rxStatus = new StatusCommand(); + + _onAttrSet = attrSet; + _onAttrSetComplete = attrSetComplete; + _theSPI->begin(); + + // AJS where does this get moved to?? + #ifdef ARDUINO + pinMode(mcuInterrupt, INPUT); + attachInterrupt(mcuInterrupt, isrWrapper, FALLING); + #endif + fco.fall(isrWrapper); + SERIAL_PRINT_DBG_ASR("afLib init done!!\n"); +} +//wsugi 20161128 +afLib::~afLib() +{ + SERIAL_PRINT_DBG_ASR("deleted\n"); + if(_readBuffer != NULL) + { + delete[] (_readBuffer); + _readBuffer = NULL; + } + + if(_writeBuffer != NULL) + { + delete[] (_writeBuffer); + _writeBuffer = NULL; + } + + if(_readCmd != NULL) + { + delete (_readCmd); + _readCmd = NULL; + } + + if(_writeCmd != NULL) + { + delete (_writeCmd); + _writeCmd = NULL; + } + + if(_txStatus != NULL) + { + delete (_txStatus); + _txStatus = NULL; + } + + if(_rxStatus != NULL) + { + delete (_rxStatus); + _rxStatus = NULL; + } + + for (int i = 0; i < REQUEST_QUEUE_SIZE; i++) + { + if (_requestQueue[i].p_value != NULL) + { + delete[] (_requestQueue[i].p_value); + _requestQueue[i].p_value = NULL; + } + } + + if(checkLastSync != NULL) + { + delete (checkLastSync); + checkLastSync = NULL; + } + + _iaflib = NULL; +} +//wsugi 20161128 +/** + * loop + * + * This is how the afLib gets time to run its state machine. This method should be called periodically from the + * loop() function of the Arduino sketch. + * This function pulls pending attribute operations from the queue. It takes approximately 4 calls to loop() to + * complete one attribute operation. + */ +void afLib::loop(void) { + reset_watch_dog() ; /* 26-Dec-2017 by Motoo Tanaka */ + if (isIdle() && (queueGet(&_request.messageType, &_request.requestId, &_request.attrId, &_request.valueLen, + &_request.p_value) == afSUCCESS)) { + switch (_request.messageType) { + case MSG_TYPE_GET: + doGetAttribute(_request.requestId, _request.attrId); + break; + + case MSG_TYPE_SET: + doSetAttribute(_request.requestId, _request.attrId, _request.valueLen, _request.p_value); + break; + + case MSG_TYPE_UPDATE: + doUpdateAttribute(_request.requestId, _request.attrId, 0, _request.valueLen, _request.p_value); + break; + + default: + SERIAL_PRINT_DBG_ASR("%s\n","loop: request type!"); + } + } + + if (_request.p_value != NULL) { + delete[] (_request.p_value); //wsugi delete (_request.p_value); + _request.p_value = NULL; + } + runStateMachine(); +} + +/** + * updateIntsPending + * + * Interrupt-safe method for updating the interrupt count. This is called to increment and decrement the interrupt count + * as interrupts are received and handled. + */ +void afLib::updateIntsPending(int amount) { +// fco.disable_irq(); + __disable_irq() ; // Disable Interrupts + _interrupts_pending += amount; + __enable_irq() ; // Enable Interrupts +// fco.enable_irq(); +} + +/** + * sendCommand + * + * This increments the interrupt count to kick off the state machine in the next call to loop(). + */ +/** + * In this fucntion, only disable/enable fco irq is enough + */ +void afLib::sendCommand(void) { + fco.disable_irq(); + if (_interrupts_pending == 0 && _state == STATE_IDLE) { + updateIntsPending(1); + } + fco.enable_irq(); +} + +/** + * getAttribute + * + * The public getAttribute method. This method queues the operation and returns immediately. Applications must call + * loop() for the operation to complete. + */ +int afLib::getAttribute(const uint16_t attrId) { + _requestId++; + uint8_t dummy; // This value isn't actually used. +// return queuePut(MSG_TYPE_GET, _requestId++, attrId, 0, &dummy); + return queuePut(MSG_TYPE_GET, _requestId, attrId, 0, &dummy); /* by moto on 17-Nov-2017 */ +} + +/** + * The many moods of setAttribute + * + * These are the public versions of the setAttribute method. + * These methods queue the operation and return immediately. Applications must call loop() for the operation to complete. + */ +int afLib::setAttributeBool(const uint16_t attrId, const bool value) { + _requestId++; + uint8_t val = value ? 1 : 0; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(val), + (uint8_t *)&val); +} + +int afLib::setAttribute8(const uint16_t attrId, const int8_t value) { + _requestId++; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), + (uint8_t *)&value); +} + +int afLib::setAttribute16(const uint16_t attrId, const int16_t value) { + _requestId++; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), + (uint8_t *) &value); +} + +int afLib::setAttribute32(const uint16_t attrId, const int32_t value) { + _requestId++; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), + (uint8_t *) &value); +} + +int afLib::setAttribute64(const uint16_t attrId, const int64_t value) { + _requestId++; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), + (uint8_t *) &value); +} + +int afLib::setAttribute(const uint16_t attrId, const string &value) { + _requestId++; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, value.length(), + (uint8_t *) value.c_str()); +} + +int afLib::setAttribute(const uint16_t attrId, const uint16_t valueLen, const char *value) { + if (valueLen > MAX_ATTRIBUTE_SIZE) { + return afERROR_INVALID_PARAM; + } + + if (value == NULL) { + return afERROR_INVALID_PARAM; + } + + _requestId++; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, valueLen, + (const uint8_t *) value); +} + +int afLib::setAttribute(const uint16_t attrId, const uint16_t valueLen, const uint8_t *value) { + if (valueLen > MAX_ATTRIBUTE_SIZE) { + return afERROR_INVALID_PARAM; + } + + if (value == NULL) { + return afERROR_INVALID_PARAM; + } + + _requestId++; + return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, valueLen, value); +} + +int afLib::setAttributeComplete(uint8_t requestId, const uint16_t attrId, const uint16_t valueLen, const uint8_t *value) { + if (valueLen > MAX_ATTRIBUTE_SIZE) { + return afERROR_INVALID_PARAM; + } + + if (value == NULL) { + return afERROR_INVALID_PARAM; + } + + return queuePut(MSG_TYPE_UPDATE, requestId, attrId, valueLen, value); +} + +/** + * doGetAttribute + * + * The private version of getAttribute. This version actually calls sendCommand() to kick off the state machine and + * execute the operation. + */ +int afLib::doGetAttribute(uint8_t requestId, uint16_t attrId) { + if (_interrupts_pending > 0 || _writeCmd != NULL) { + return afERROR_BUSY; + } + + _writeCmd = new Command(requestId, MSG_TYPE_GET, attrId); + if (!_writeCmd->isValid()) { + SERIAL_PRINT_DBG_ASR("getAttribute invalid command:"); + _writeCmd->dumpBytes(); + _writeCmd->dump(); + delete (_writeCmd); + _writeCmd = NULL; + return afERROR_INVALID_COMMAND; + } + + _outstandingSetGetAttrId = attrId; + + // Start the transmission. + sendCommand(); + + return afSUCCESS; +} + +/** + * doSetAttribute + * + * The private version of setAttribute. This version actually calls sendCommand() to kick off the state machine and + * execute the operation. + */ +int afLib::doSetAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value) { + if (_interrupts_pending > 0 || _writeCmd != NULL) { + return afERROR_BUSY; + } + _writeCmd = new Command(requestId, MSG_TYPE_SET, attrId, valueLen, value); + if (!_writeCmd->isValid()) { + SERIAL_PRINT_DBG_ASR("setAttributeComplete invalid command:"); + _writeCmd->dumpBytes(); + _writeCmd->dump(); + delete (_writeCmd); + _writeCmd = NULL; + return afERROR_INVALID_COMMAND; + } + + _outstandingSetGetAttrId = attrId; + + // Start the transmission. + sendCommand(); + + return afSUCCESS; +} + +/** + * doUpdateAttribute + * + * setAttribute calls on MCU attributes turn into updateAttribute calls. See documentation on the SPI protocol for + * more information. This method calls sendCommand() to kick off the state machine and execute the operation. + */ +int afLib::doUpdateAttribute(uint8_t requestId, uint16_t attrId, uint8_t status, uint16_t valueLen, uint8_t *value) { + if (_interrupts_pending > 0 || _writeCmd != NULL) { + return afERROR_BUSY; + } + + _writeCmd = new Command(requestId, MSG_TYPE_UPDATE, attrId, status, 3 /* MCU Set it */, valueLen, value); + if (!_writeCmd->isValid()) { + SERIAL_PRINT_DBG_ASR("updateAttribute invalid command:"); + _writeCmd->dumpBytes(); + _writeCmd->dump(); + delete (_writeCmd); + return afERROR_INVALID_COMMAND; + } + + // Start the transmission. + sendCommand(); + + return afSUCCESS; +} + +/** + * parseCommand + * + * A debug method for parsing a string into a command. This is not required for library operation and is only supplied + * as an example of how to execute attribute operations from a command line interface. + */ +#ifdef ATTRIBUTE_CLI +int afLib::parseCommand(const char *cmd) { + if (_interrupts_pending > 0 || _writeCmd != NULL) { + _theLog->print("Busy: "); + _theLog->print(_interrupts_pending); + _theLog->print(", "); + _theLog->println(_writeCmd != NULL); + return afERROR_BUSY; + } + + int reqId = _requestId++; + _writeCmd = new Command(_theLog,reqId, cmd); + if (!_writeCmd->isValid()) { + _theLog->print("BAD: "); + _theLog->println(cmd); + _writeCmd->dumpBytes(); + _writeCmd->dump(); + delete (_writeCmd); + _writeCmd = NULL; + return afERROR_INVALID_COMMAND; + } + + // Start the transmission. + sendCommand(); + + return afSUCCESS; +} +#endif + +/** + * runStateMachine + * + * The state machine for afLib. This state machine is responsible for implementing the KSP SPI protocol and executing + * attribute operations. + * This method is run: + * 1. In response to receiving an interrupt from the ASR-1. + * 2. When an attribute operation is pulled out of the queue and executed. + */ +void afLib::runStateMachine(void) { + if (_interrupts_pending > 0) { + switch (_state) { + case STATE_IDLE: + //deathWish.attach(&afLib::kick_the_bucket,10); + onStateIdle(); + return; + + case STATE_STATUS_SYNC: + onStateSync(); + break; + + case STATE_STATUS_ACK: + onStateAck(); + break; + + case STATE_SEND_BYTES: + onStateSendBytes(); + break; + + case STATE_RECV_BYTES: + onStateRecvBytes(); + break; + + case STATE_CMD_COMPLETE: + onStateCmdComplete(); + break; + } + + updateIntsPending(-1); + } else { + if (syncRetries > 0 && syncRetries < MAX_SYNC_RETRIES && checkLastSync->read_ms() - lastSync > 1000) { + updateIntsPending(1); + } else if (syncRetries >= MAX_SYNC_RETRIES) { + SERIAL_PRINT_DBG_ASR("No response from ASR-1 - does profile have MCU enabled?\n"); +#if defined(TARGET_KL25Z) +// WatchDogWrapper::getSelf()->kick_the_bucket(); +#endif //TARGET_KL25Z + syncRetries = 0; + _state = STATE_IDLE; + } + } +} + +/** + * onStateIdle + * + * If there is a command to be written, update the bytes to send. Otherwise we're sending a zero-sync message. + * Either way advance the state to send a sync message. + */ +void afLib::onStateIdle(void) { + if (_writeCmd != NULL) { + // Include 2 bytes for length + _bytesToSend = _writeCmd->getSize() + 2; + } else { + _bytesToSend = 0; + } + _state = STATE_STATUS_SYNC; + printState(_state); +} + +/** + * onStateSync + * + * Write a sync message over SPI to let the ASR-1 know that we want to send some data. + * Check for a "collision" which occurs if the ASR-1 is trying to send us data at the same time. + */ +void afLib::onStateSync(void) { + int result; + + _txStatus->setAck(false); + _txStatus->setBytesToSend(_bytesToSend); + _txStatus->setBytesToRecv(0); + + result = exchangeStatus(_txStatus, _rxStatus); + + if (result == afSUCCESS && _rxStatus->isValid() && inSync(_txStatus, _rxStatus)) { + syncRetries = 0; // Flag that sync completed. + _state = STATE_STATUS_ACK; + if (_txStatus->getBytesToSend() == 0 && _rxStatus->getBytesToRecv() > 0) { + _bytesToRecv = _rxStatus->getBytesToRecv(); + } + } else { + // Try resending the preamble + _state = STATE_STATUS_SYNC; + lastSync = checkLastSync->read_ms(); + syncRetries++; +// _txStatus->dumpBytes(); +// _rxStatus->dumpBytes(); + } + printState(_state); +} + +/** + * onStateAck + * + * Acknowledge the previous sync message and advance the state. + * If there are bytes to send, advance to send bytes state. + * If there are bytes to receive, advance to receive bytes state. + * Otherwise it was a zero-sync so advance to command complete. + */ +void afLib::onStateAck(void) { + int result; + + _txStatus->setAck(true); + _txStatus->setBytesToRecv(_rxStatus->getBytesToRecv()); + _bytesToRecv = _rxStatus->getBytesToRecv(); + result = writeStatus(_txStatus); + if (result != afSUCCESS) { + _state = STATE_STATUS_SYNC; + printState(_state); + return; + } + if (_bytesToSend > 0) { + _writeBufferLen = (uint16_t) _writeCmd->getSize(); + _writeBuffer = new uint8_t[_bytesToSend]; + memcpy(_writeBuffer, (uint8_t * ) & _writeBufferLen, 2); + _writeCmd->getBytes(&_writeBuffer[2]); + _state = STATE_SEND_BYTES; + } else if (_bytesToRecv > 0) { + _state = STATE_RECV_BYTES; + } else { + _state = STATE_CMD_COMPLETE; + } + printState(_state); +} + +/** + * onStateSendBytes + * + * Send the required number of bytes to the ASR-1 and then advance to command complete. + */ +void afLib::onStateSendBytes(void) { +// _theLog->print("send bytes: "); _theLog->println(_bytesToSend); + sendBytes(); + + if (_bytesToSend == 0) { + _writeBufferLen = 0; + delete[] (_writeBuffer); //wsugi delete (_writeBuffer); + _writeBuffer = NULL; + _state = STATE_CMD_COMPLETE; + printState(_state); + } +} + +/** + * onStateRecvBytes + * + * Receive the required number of bytes from the ASR-1 and then advance to command complete. + */ +void afLib::onStateRecvBytes(void) { +// _theLog->print("receive bytes: "); _theLog->println(_bytesToRecv); + recvBytes(); + if (_bytesToRecv == 0) { + _state = STATE_CMD_COMPLETE; + printState(_state); + _readCmd = new Command(_readBufferLen, &_readBuffer[2]); + delete[] (_readBuffer); //wsugi delete (_readBuffer); + _readBuffer = NULL; + } +} + +/** + * onStateCmdComplete + * + * Call the appropriate sketch callback to report the result of the command. + * Clear the command object and go back to waiting for the next interrupt or command. + */ +void afLib::onStateCmdComplete(void) { + _state = STATE_IDLE; + printState(_state); + if (_readCmd != NULL) { + uint8_t *val = new uint8_t[_readCmd->getValueLen()]; + _readCmd->getValue(val); + + switch (_readCmd->getCommand()) { + case MSG_TYPE_SET: + _onAttrSet(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val); + break; + + case MSG_TYPE_UPDATE: + if (_readCmd->getAttrId() == _outstandingSetGetAttrId) { + _outstandingSetGetAttrId = 0; + } + _onAttrSetComplete(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val); + break; + + default: + break; + } + delete[] (val); //wsugi delete (val); + delete (_readCmd); + _readCmdOffset = 0; + _readCmd = NULL; + } + + if (_writeCmd != NULL) { + // Fake a callback here for MCU attributes as we don't get one from the module. + if (_writeCmd->getCommand() == MSG_TYPE_UPDATE && IS_MCU_ATTR(_writeCmd->getAttrId())) { + _onAttrSetComplete(_writeCmd->getReqId(), _writeCmd->getAttrId(), _writeCmd->getValueLen(), _writeCmd->getValueP()); + } + delete (_writeCmd); + _writeCmdOffset = 0; + _writeCmd = NULL; + } +} + +/** + * exchangeStatus + * + * Write a status command object to the ASR-1 and clock in a status object from the ASR-1 at the same time. + */ +int afLib::exchangeStatus(StatusCommand *tx, StatusCommand *rx) { + int result = afSUCCESS; + uint16_t len = tx->getSize(); + int bytes[len]; + char rbytes[len+1]; + int index = 0; + tx->getBytes(bytes); + +// _theSPI->beginSPI(); + + for (int i=0;i<len;i++) + { + rbytes[i]=bytes[i]; + } + rbytes[len]=tx->getChecksum(); + + printTransaction((uint8_t*)rbytes,len+1); + + _theSPI->beginSPI(); + _theSPI->transfer(rbytes,len+1); + _theSPI->endSPI(); + + printTransaction((uint8_t*)rbytes,len+1); + + uint8_t cmd = bytes[index++]; + if (cmd != 0x30 && cmd != 0x31) { + SERIAL_PRINT_DBG_ASR("exchangeStatus bad cmd: 0x%02x\n",cmd); + result = afERROR_INVALID_COMMAND; + } + + rx->setBytesToSend(rbytes[index + 0] | (rbytes[index + 1] << 8)); + rx->setBytesToRecv(rbytes[index + 2] | (rbytes[index + 3] << 8)); + rx->setChecksum(rbytes[index+4]); + //_theSPI->endSPI(); + return result; +} + +/** + * inSync + * + * Check to make sure the Arduino and the ASR-1 aren't trying to send data at the same time. + * Return true only if there is no collision. + */ +bool afLib::inSync(StatusCommand *tx, StatusCommand *rx) { + return (tx->getBytesToSend() == 0 && rx->getBytesToRecv() == 0) || + (tx->getBytesToSend() > 0 && rx->getBytesToRecv() == 0) || + (tx->getBytesToSend() == 0 && rx->getBytesToRecv() > 0); +} + +/** + * writeStatus + * + * Write a status command to the ASR-1 and ignore the result. If you want to read bytes at the same time, use + * exchangeStatus instead. + */ +int afLib::writeStatus(StatusCommand *c) { + int result = afSUCCESS; + uint16_t len = c->getSize(); + int bytes[len]; + char rbytes[len+1]; + int index = 0; + c->getBytes(bytes); + + _theSPI->beginSPI(); + + for (int i=0;i<len;i++) + { + rbytes[i]=bytes[i]; + } + rbytes[len]=c->getChecksum(); + printTransaction((uint8_t*)rbytes,len+1); + _theSPI->transfer(rbytes,len+1); + printTransaction((uint8_t*)rbytes,len+1); + uint8_t cmd = rbytes[index++]; + if (cmd != 0x30 && cmd != 0x31) { + SERIAL_PRINT_DBG_ASR("writeStatus bad cmd: 0x%02x\n",cmd); + result = afERROR_INVALID_COMMAND; + } + + + _theSPI->endSPI(); + +// c->dump(); +// c->dumpBytes(); + + return result; +} + +/** + * sendBytes + * + * Send the specified number of data bytes to the ASR-1. Do this in chunks of SPI_FRAME_LEN bytes. + */ +void afLib::sendBytes() { + uint16_t len = _bytesToSend > SPI_FRAME_LEN ? SPI_FRAME_LEN : _bytesToSend; + uint8_t bytes[SPI_FRAME_LEN]; + memset(bytes, 0xff, sizeof(bytes)); + + memcpy(bytes, &_writeBuffer[_writeCmdOffset], len); + + _theSPI->beginSPI(); + printTransaction(bytes,len+1); + _theSPI->transfer((char *)bytes,len); + printTransaction(bytes,len+1); + _theSPI->endSPI(); + +// dumpBytes("Sending:", len, bytes); + + _writeCmdOffset += len; + _bytesToSend -= len; +} + +/** + * recvBytes + * + * Receive the specified number of data bytes from the ASR-1. Do this in chunks of SPI_FRAME_LEN bytes. + */ +void afLib::recvBytes() { + uint16_t len = _bytesToRecv > SPI_FRAME_LEN ? SPI_FRAME_LEN : _bytesToRecv; + + if (_readCmdOffset == 0) { + _readBufferLen = _bytesToRecv; + _readBuffer = new uint8_t[_readBufferLen]; + } + + _theSPI->beginSPI(); + + + char * start =(char*)_readBuffer + _readCmdOffset; + printTransaction((uint8_t*)start,len+1); + _theSPI->transfer(start,len); + printTransaction((uint8_t*)start,len+1); + + _theSPI->endSPI(); + +// dumpBytes("Receiving:", len, _readBuffer); + + _readCmdOffset += len; + _bytesToRecv -= len; +} + +/** + * isIdle + * + * Provide a way for the sketch to know if we're idle. Returns true if there are no attribute operations in progress. + */ +bool afLib::isIdle() { + return _interrupts_pending == 0 && _state == STATE_IDLE && _outstandingSetGetAttrId == 0; +} + +/** + * These methods are required to disable/enable interrupts for the Linux version of afLib. + * They are no-ops on Arduino. + */ +#ifndef ARDUINO +void noInterrupts(){} + void interrupts(){} +#endif + +void afLib::mcuISR() { +// _theLog->println("mcu"); + updateIntsPending(1); +} + +/**************************************************************************** + * Queue Methods * + ****************************************************************************/ +/** + * queueInit + * + * Create a small queue to prevent flooding the ASR-1 with attribute operations. + * The initial size is small to allow running on small boards like UNO. + * Size can be increased on larger boards. + */ +void afLib::queueInit() { + for (int i = 0; i < REQUEST_QUEUE_SIZE; i++) { + _requestQueue[i].p_value = NULL; + } +} + +/** + * queuePut + * + * Add an item to the end of the queue. Return an error if we're out of space in the queue. + */ +int afLib::queuePut(uint8_t messageType, uint8_t requestId, const uint16_t attributeId, uint16_t valueLen, + const uint8_t *value) { + for (int i = 0; i < REQUEST_QUEUE_SIZE; i++) { + if (_requestQueue[i].p_value == NULL) { + _requestQueue[i].messageType = messageType; + _requestQueue[i].attrId = attributeId; + _requestQueue[i].requestId = requestId; + _requestQueue[i].valueLen = valueLen; + _requestQueue[i].p_value = new uint8_t[valueLen]; + memcpy(_requestQueue[i].p_value, value, valueLen); + return afSUCCESS; + } + } + + return afERROR_QUEUE_OVERFLOW; +} + +/** + * queueGet + * + * Pull and return the oldest item from the queue. Return an error if the queue is empty. + */ +int afLib::queueGet(uint8_t *messageType, uint8_t *requestId, uint16_t *attributeId, uint16_t *valueLen, + uint8_t **value) { + for (int i = 0; i < REQUEST_QUEUE_SIZE; i++) { + if (_requestQueue[i].p_value != NULL) { + *messageType = _requestQueue[i].messageType; + *attributeId = _requestQueue[i].attrId; + *requestId = _requestQueue[i].requestId; + *valueLen = _requestQueue[i].valueLen; + *value = new uint8_t[*valueLen]; + memcpy(*value, _requestQueue[i].p_value, *valueLen); + delete[] (_requestQueue[i].p_value); //wsugi delete (_requestQueue[i].p_value); + _requestQueue[i].p_value = NULL; + return afSUCCESS; + } + } + + return afERROR_QUEUE_UNDERFLOW; +} + +/**************************************************************************** + * Debug Methods * + ****************************************************************************/ +/** + * dumpBytes + * + * Dump a byte buffer to the debug log. + */ +void afLib::dumpBytes(char *label, int len, uint8_t *bytes) { + SERIAL_PRINT_DBG_ASR("%s\n",label); + for (int i = 0; i < len; i++) { + if (i > 0) { + SERIAL_PRINT_DBG_ASR(", "); + } + uint8_t b = bytes[i] & 0xff; + + if (b < 0x10) { + SERIAL_PRINT_DBG_ASR("0x02x", b); + } else { + //_theLog->print("0x"); + SERIAL_PRINT_DBG_ASR("0x02x",b);//, HEX); + } + } + SERIAL_PRINT_DBG_ASR("\n"); +} + +/** + * printState + * + * Print the current state of the afLib state machine. For debugging, just remove the return statement. + */ +void afLib::printState(int state) { +// return; + switch (state) { + case STATE_IDLE: + SERIAL_PRINT_DBG_ASR("STATE_IDLE\n"); + break; + case STATE_STATUS_SYNC: + SERIAL_PRINT_DBG_ASR("STATE_STATUS_SYNC\n"); + break; + case STATE_STATUS_ACK: + SERIAL_PRINT_DBG_ASR("STATE_STATUS_ACK\n"); + break; + case STATE_SEND_BYTES: + SERIAL_PRINT_DBG_ASR("STATE_SEND_BYTES\n"); + break; + case STATE_RECV_BYTES: + SERIAL_PRINT_DBG_ASR("STATE_RECV_BYTES\n"); + break; + case STATE_CMD_COMPLETE: + SERIAL_PRINT_DBG_ASR("STATE_CMD_COMPLETE\n"); + break; + default: + SERIAL_PRINT_DBG_ASR("Unknown State!\n"); + break; + } +} + +void afLib::printTransaction(uint8_t *rbytes, int len) +{ + //return; + int i = 0; + for(;i<=len;++i) + { + SERIAL_PRINT_DBG_ASR("0x%02x:",rbytes[i]); + } + SERIAL_PRINT_DBG_ASR("\n"); +} \ No newline at end of file