Release candidate version. The pointer in GAS Pressure display is changed to a triangle.
Dependencies: UniGraphic mbed vt100
Please note, at 2-Mar-2018 the current version of mbed-lib has a defect in Ticker.
https://os.mbed.com/forum/bugs-suggestions/topic/29287/
So, mbed lib version 157 is intentionally being used.
Please do not update mbed library until the problem in the above URL is fixed.
In this version, format of GAS Pressure Display has been changed.
moto
Diff: afLib/afLib.cpp
- Revision:
- 0:774324cbc5a6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/afLib/afLib.cpp Fri Mar 02 07:56:09 2018 +0000 @@ -0,0 +1,958 @@ +/** + * 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); + printf("afLib init done!!\n"); +} +//wsugi 20161128 +afLib::~afLib() +{ + printf("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: + printf("%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()) { + printf("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()) { + printf("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()) { + printf("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) { + printf("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) { + printf("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) { + printf("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) { + return ; + printf("%s\n",label); + for (int i = 0; i < len; i++) { + if (i > 0) { + printf(", "); + } + uint8_t b = bytes[i] & 0xff; + + if (b < 0x10) { + printf("0x02x", b); + } else { + //_theLog->print("0x"); + printf("0x02x",b);//, HEX); + } + } + printf("\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: + printf("STATE_IDLE\n"); + break; + case STATE_STATUS_SYNC: + printf("STATE_STATUS_SYNC\n"); + break; + case STATE_STATUS_ACK: + printf("STATE_STATUS_ACK\n"); + break; + case STATE_SEND_BYTES: + printf("STATE_SEND_BYTES\n"); + break; + case STATE_RECV_BYTES: + printf("STATE_RECV_BYTES\n"); + break; + case STATE_CMD_COMPLETE: + printf("STATE_CMD_COMPLETE\n"); + break; + default: + printf("Unknown State!\n"); + break; + } +} + +void afLib::printTransaction(uint8_t *rbytes, int len) +{ + return; + int i = 0; + for(;i<=len;++i) + { + printf("0x%02x:",rbytes[i]); + } + printf("\n"); +} \ No newline at end of file