an old afLib which supports both SPI and UART
Revision 0:6f371c791202, committed 2018-03-20
- Comitter:
- Rhyme
- Date:
- Tue Mar 20 06:47:25 2018 +0000
- Child:
- 1:112741fe45d1
- Commit message:
- SPI mode started working
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Command.cpp Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,281 @@
+/**
+ * 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 <stdio.h>
+#include "Command.h"
+#include "msg_types.h"
+
+#define CMD_HDR_LEN 4 // 4 byte header on all commands
+#define CMD_VAL_LEN 2 // 2 byte value length for commands that have a value
+
+const char *CMD_NAMES[] = {"SET ", "GET ", "UPDATE"};
+
+
+Command::Command(Stream *serial,uint16_t len, uint8_t *bytes) {
+ _serial = serial;
+ int index = 0;
+
+ _cmd = bytes[index++];
+ _requestId = bytes[index++];
+ _attrId = bytes[index + 0] | bytes[index + 1] << 8;
+ index += 2;
+
+ if (_cmd == MSG_TYPE_GET) {
+ return;
+ }
+ if (_cmd == MSG_TYPE_UPDATE) {
+ _status = bytes[index++];
+ _reason = bytes[index++];
+ }
+
+ _valueLen = bytes[index + 0] | bytes[index + 1] << 8;
+ index += 2;
+ _value = new uint8_t[_valueLen];
+ for (int i = 0; i < _valueLen; i++) {
+ _value[i] = bytes[index + i];
+ }
+}
+
+#if 1
+char *strdup(const char *str)
+{
+ int len ;
+ char *ptr = 0 ;
+ if (str) {
+ len = strlen(str) ;
+ ptr = (char*)malloc(len + 1) ;
+ strcpy(ptr, str) ;
+ }
+ return(ptr) ;
+}
+#endif
+
+Command::Command(Stream *serial,uint8_t requestId, const char *str) {
+ _serial = serial;
+ _requestId = requestId & 0xff;
+
+ char *cp = strdup(str);
+ char *tok = strtok(cp, " ");
+ _cmd = strToCmd(tok);
+
+ tok = strtok(NULL, " ");
+ _attrId = strToAttrId(tok);
+
+ if (_cmd == MSG_TYPE_GET) {
+ _valueLen = 0;
+ _value = NULL;
+ } else {
+ tok = strtok(NULL, " ");
+ _valueLen = strlen(tok) / 2;
+ _value = new uint8_t[_valueLen];
+ strToValue(tok, _value);
+ }
+
+ free(cp);
+}
+
+Command::Command(Stream *serial,uint8_t requestId, uint8_t cmd, uint16_t attrId) {
+ _serial = serial;
+ _requestId = requestId;
+ _cmd = cmd;
+ _attrId = attrId;
+ _valueLen = 0;
+ _value = NULL;
+}
+
+Command::Command(Stream *serial,uint8_t requestId, uint8_t cmd, uint16_t attrId, uint16_t valueLen, uint8_t *value) {
+ _serial = serial;
+ _requestId = requestId;
+ _cmd = cmd;
+ _attrId = attrId;
+ _valueLen = valueLen;
+ _value = new uint8_t[_valueLen];
+ memcpy(_value, value, valueLen);
+}
+
+Command::Command(Stream *serial,uint8_t requestId, uint8_t cmd, uint16_t attrId, uint8_t status, uint8_t reason, uint16_t valueLen,
+ uint8_t *value) {
+ _serial = serial;
+ _requestId = requestId;
+ _cmd = cmd;
+ _attrId = attrId;
+ _status = status;
+ _reason = reason;
+ _valueLen = valueLen;
+ _value = new uint8_t[_valueLen];
+ memcpy(_value, value, valueLen);
+}
+
+Command::Command(Stream *serial) {
+ _serial = serial;
+
+}
+
+Command::~Command() {
+ if (_value != NULL) {
+ delete (_value);
+ }
+}
+
+int Command::strToValue(char *valueStr, uint8_t *value) {
+ for (int i = 0; i < (int) (strlen(valueStr) / 2); i++) {
+ int j = i * 2;
+ value[i] = getVal(valueStr[j + 1]) + (getVal(valueStr[j]) << 4);
+ }
+
+ return 0;
+}
+
+uint16_t Command::strToAttrId(char *attrIdStr) {
+ return atoi(attrIdStr);
+ //return String(attrIdStr).toInt();
+}
+
+uint8_t Command::strToCmd(char *cmdStr) {
+ char c = cmdStr[0];
+ if (c == 'g' || c == 'G') {
+ return MSG_TYPE_GET;
+ } else if (c == 's' || c == 'S') {
+ return MSG_TYPE_SET;
+ } else if (c == 'u' || c == 'U') {
+ return MSG_TYPE_UPDATE;
+ }
+
+ return -1;
+}
+
+uint8_t Command::getCommand() {
+ return _cmd;
+}
+
+uint8_t Command::getReqId() {
+ return _requestId;
+}
+
+uint16_t Command::getAttrId() {
+ return _attrId;
+}
+
+uint16_t Command::getValueLen() {
+ return _valueLen;
+}
+
+void Command::getValue(uint8_t *value) {
+ for (int i = 0; i < _valueLen; i++) {
+ value[i] = _value[i];
+ }
+}
+
+uint8_t *Command::getValueP() {
+ return _value;
+}
+
+uint16_t Command::getSize() {
+ uint16_t len = CMD_HDR_LEN;
+
+ if (_cmd != MSG_TYPE_GET) {
+ len += CMD_VAL_LEN + _valueLen;
+ }
+
+ if (_cmd == MSG_TYPE_UPDATE) {
+ len += 2; // status byte + reason byte
+ }
+
+ return len;
+}
+
+uint16_t Command::getBytes(uint8_t *bytes) {
+ uint16_t len = getSize();
+
+ int index = 0;
+
+ bytes[index++] = (_cmd);
+
+ bytes[index++] = (_requestId);
+
+ bytes[index++] = (_attrId & 0xff);
+ bytes[index++] = ((_attrId >> 8) & 0xff);
+
+ if (_cmd == MSG_TYPE_GET) {
+ return len;
+ }
+
+ if (_cmd == MSG_TYPE_UPDATE) {
+ bytes[index++] = (_status);
+ bytes[index++] = (_reason);
+ }
+
+ bytes[index++] = (_valueLen & 0xff);
+ bytes[index++] = ((_valueLen >> 8) & 0xff);
+
+ for (int i = 0; i < _valueLen; i++) {
+ bytes[index++] = (_value[i]);
+ }
+
+ return len;
+}
+
+uint8_t Command::getReason() {
+ return _reason;
+}
+
+bool Command::isValid() {
+ return (_cmd == MSG_TYPE_SET) || (_cmd == MSG_TYPE_GET) || (_cmd == MSG_TYPE_UPDATE);
+}
+
+void Command::dumpBytes() {
+ uint16_t len = getSize();
+ uint8_t bytes[len];
+ getBytes(bytes);
+
+ _printBuf[0] = 0;
+ sprintf(_printBuf, "len: %d value: ", len);
+ for (int i = 0; i < len; i++) {
+ int b = bytes[i] & 0xff;
+ sprintf(&_printBuf[strlen(_printBuf)], "%02x", b);
+ }
+ _serial->printf(_printBuf);
+}
+
+void Command::dump() {
+ _printBuf[0] = 0;
+ sprintf(_printBuf, "cmd: %s attr: %d value: ",
+ CMD_NAMES[_cmd - MESSAGE_CHANNEL_BASE - 1],
+ _attrId
+ );
+ if (_cmd != MSG_TYPE_GET) {
+ for (int i = 0; i < _valueLen; i++) {
+ int b = _value[i] & 0xff;
+ sprintf(&_printBuf[strlen(_printBuf)], "%02x", b);
+ }
+ }
+ _serial->printf(_printBuf);
+}
+
+uint8_t Command::getVal(char c) {
+ if (c >= '0' && c <= '9')
+ return (uint8_t)(c - '0');
+ else if (c >= 'A' && c <= 'F')
+ return (uint8_t)(c - 'A' + 10);
+ else if (c >= 'a' && c <= 'f')
+ return (uint8_t)(c - 'a' + 10);
+
+ _serial->printf("bad hex char: 0x%02X\n", c);
+
+ return 0;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Command.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,92 @@
+/**
+ * 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.
+ */
+
+#ifndef COMMAND_H__
+#define COMMAND_H__
+
+#include "mbed.h"
+#define Stream Serial
+
+#include "msg_types.h"
+
+#define SPI_CMD_MAX_LEN 256
+
+class Command {
+public:
+ Command(Stream *,uint16_t len, uint8_t *bytes);
+
+ Command(Stream *,uint8_t requestId, const char *str);
+
+ Command(Stream *,uint8_t requestId, uint8_t cmd, uint16_t attrId);
+
+ Command(Stream *,uint8_t requestId, uint8_t cmd, uint16_t attrId, uint16_t valueLen, uint8_t *value);
+
+ Command(Stream *,uint8_t requestId, uint8_t cmd, uint16_t attrId, uint8_t status, uint8_t reason, uint16_t valueLen,
+ uint8_t *value);
+
+ Command(Stream *);
+
+ ~Command();
+
+ uint8_t getCommand();
+
+ uint8_t getReqId();
+
+ uint16_t getAttrId();
+
+ uint16_t getValueLen();
+
+ void getValue(uint8_t *value);
+
+ uint8_t *getValueP();
+
+ uint16_t getSize();
+
+ uint16_t getBytes(uint8_t *bytes);
+
+ uint8_t getReason();
+
+ bool isValid();
+
+ void dump();
+
+ void dumpBytes();
+
+private:
+ uint8_t getVal(char c);
+ int strToValue(char *valueStr, uint8_t *value);
+
+ uint8_t strToCmd(char *cmdStr);
+
+ uint16_t strToAttrId(char *attrIdStr);
+
+ Serial *_serial ; /* Stream *_serial; // Arduino */
+
+ uint16_t _len;
+ uint8_t _cmd;
+ uint8_t _requestId;
+ uint16_t _attrId;
+ uint8_t _status;
+ uint8_t _reason;
+ uint16_t _valueLen;
+ uint8_t *_value;
+
+ char _printBuf[256];
+
+};
+
+#endif // COMMAND_H__
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ModuleCommands.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2016 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.
+ */
+
+#ifndef MODULES_COMMANDS_H__
+#define MODULES_COMMANDS_H__
+
+enum {
+ MODULE_COMMAND_NONE,
+ MODULE_COMMAND_REBOOT
+} module_commands_t;
+
+#endif // MODULES_COMMANDS_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ModuleStates.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,27 @@
+/**
+ * Copyright 2016 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.
+ */
+
+#ifndef MODULE_STATES_H__
+#define MODULE_STATES_H__
+
+typedef enum {
+ MODULE_STATE_REBOOTED,
+ MODULE_STATE_LINKED,
+ MODULE_STATE_UPDATING,
+ MODULE_STATE_UPDATE_READY
+} module_states_t;
+
+#endif // MODULE_STATES_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StatusCommand.cpp Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,133 @@
+/**
+ * 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 "StatusCommand.h"
+
+StatusCommand::StatusCommand(Stream *serial,uint16_t bytesToSend) {
+ _serial = serial;
+ _cmd = 0x30;
+ _bytesToSend = bytesToSend;
+ _bytesToRecv = 0;
+}
+
+StatusCommand::StatusCommand(Stream *serial) {
+ _serial = serial;
+ _cmd = 0x30;
+ _bytesToSend = 0;
+ _bytesToRecv = 0;
+}
+
+StatusCommand::~StatusCommand() {
+}
+
+uint16_t StatusCommand::getSize() {
+ return sizeof(_cmd) + sizeof(_bytesToSend) + sizeof(_bytesToRecv);
+}
+
+uint16_t StatusCommand::getBytes(int *bytes) {
+ int index = 0;
+
+ bytes[index++] = (_cmd);
+ bytes[index++] = (_bytesToSend & 0xff);
+ bytes[index++] = ((_bytesToSend >> 8) & 0xff);
+ bytes[index++] = (_bytesToRecv & 0xff);
+ bytes[index++] = ((_bytesToRecv >> 8) & 0xff);
+
+ return index;
+}
+
+uint8_t StatusCommand::calcChecksum() {
+ uint8_t result = 0;
+
+ result += (_cmd);
+ result += (_bytesToSend & 0xff);
+ result += ((_bytesToSend >> 8) & 0xff);
+ result += (_bytesToRecv & 0xff);
+ result += ((_bytesToRecv >> 8) & 0xff);
+
+ return result;
+}
+
+void StatusCommand::setChecksum(uint8_t checksum) {
+ _checksum = checksum;
+}
+
+uint8_t StatusCommand::getChecksum() {
+ uint8_t result = 0;
+
+ result += (_cmd);
+ result += (_bytesToSend & 0xff);
+ result += ((_bytesToSend >> 8) & 0xff);
+ result += (_bytesToRecv & 0xff);
+ result += ((_bytesToRecv >> 8) & 0xff);
+
+ return result;
+}
+
+void StatusCommand::setAck(bool ack) {
+ _cmd = ack ? 0x31 : 0x30;
+}
+
+void StatusCommand::setBytesToSend(uint16_t bytesToSend) {
+ _bytesToSend = bytesToSend;
+}
+
+uint16_t StatusCommand::getBytesToSend() {
+ return _bytesToSend;
+}
+
+void StatusCommand::setBytesToRecv(uint16_t bytesToRecv) {
+ _bytesToRecv = bytesToRecv;
+}
+
+uint16_t StatusCommand::getBytesToRecv() {
+ return _bytesToRecv;
+}
+
+bool StatusCommand::equals(StatusCommand *statusCommand) {
+ return (_cmd == statusCommand->_cmd && _bytesToSend == statusCommand->_bytesToSend &&
+ _bytesToRecv == statusCommand->_bytesToRecv);
+}
+
+bool StatusCommand::isValid() {
+ return (_checksum == calcChecksum()) && (_cmd == 0x30 || _cmd == 0x31);
+}
+
+void StatusCommand::dumpBytes() {
+ int len = getSize();
+ int bytes[len];
+ getBytes(bytes);
+
+ _serial->printf("len : %d\n", len);
+ _serial->printf("data : ");
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ _serial->printf(", ");
+ }
+ int b = bytes[i] & 0xff;
+ _serial->printf("0x%02X", b) ;
+ }
+ _serial->printf("\n");
+}
+
+void StatusCommand::dump() {
+ _serial->printf("cmd : %s\n", _cmd == 0x30 ? "STATUS" : "STATUS_ACK");
+ _serial->printf("bytes to send : %d\n", _bytesToSend);
+ _serial->printf("bytes to receive : %d\n", _bytesToRecv);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StatusCommand.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+#ifndef STATUS_COMMAND_H__
+#define STATUS_COMMAND_H__
+
+#include "mbed.h"
+#define Stream Serial
+
+class StatusCommand {
+public:
+ StatusCommand(Stream *);
+
+ StatusCommand(Stream *,uint16_t bytesToSend);
+
+ ~StatusCommand();
+
+ uint16_t getSize();
+
+ uint16_t getBytes(int *bytes);
+
+ uint8_t calcChecksum();
+
+ void setChecksum(uint8_t checksum);
+
+ uint8_t getChecksum();
+
+ void setAck(bool ack);
+
+ void setBytesToSend(uint16_t bytesToSend);
+
+ uint16_t getBytesToSend();
+
+ void setBytesToRecv(uint16_t bytesToRecv);
+
+ uint16_t getBytesToRecv();
+
+ bool equals(StatusCommand *statusCommand);
+
+ bool isValid();
+
+ void dump();
+
+ void dumpBytes();
+
+private:
+ Stream * _serial;
+ uint8_t _cmd;
+ uint16_t _bytesToSend;
+ uint16_t _bytesToRecv;
+ uint8_t _checksum;
+};
+
+#endif // STATUS_COMMAND_H__
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/afErrors.h Tue Mar 20 06:47:25 2018 +0000 @@ -0,0 +1,28 @@ +/** + * 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. + */ + +#ifndef AF_ERRORS_H__ +#define AF_ERRORS_H__ + +#define afSUCCESS 0 // Operation completed successfully +#define afERROR_NO_SUCH_ATTRIBUTE -1 // Request was made for unknown attribute id +#define afERROR_BUSY -2 // Request already in progress, try again +#define afERROR_INVALID_COMMAND -3 // Command could not be parsed +#define afERROR_QUEUE_OVERFLOW -4 // Queue is full +#define afERROR_QUEUE_UNDERFLOW -5 // Queue is empty +#define afERROR_INVALID_PARAM -6 // Bad input parameter + +#endif // AF_ERRORS_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/afLib.cpp Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,890 @@
+/**
+ * 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"
+#define Stream Serial
+#include "afLib.h"
+#include "af_queue.h"
+
+/**
+ * Define this to debug your selected transport (ie SPI or UART).
+ * This will cause a println each time an interrupt or ready byte is received from the ASR.
+ * You will also get states printed whenever a SYNC transaction is performed by the afLib.
+ */
+#define DEBUG_TRANSPORT 0
+
+/**
+ * These are required to be able to recognize the MCU trying to reboot the ASR by setting the command
+ * attribute. We used local defines with the aflib prefix to make sure they are always defined and don't
+ * clash with anything the app is using.
+ */
+#define AFLIB_SYSTEM_COMMAND_ATTR_ID (65012)
+#define AFLIB_SYSTEM_COMMAND_REBOOT (1)
+
+/**
+ * Prevent the MCU from spamming us with too many setAttribute requests.
+ * We do this by waiting a small amount of time in between transactions.
+ * This prevents sync retries and allows the module to get it's work done.
+ */
+#define MIN_TIME_BETWEEN_UPDATES_MILLIS (50)
+
+#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;
+static long lastComplete = 0;
+
+AF_QUEUE_DECLARE(s_request_queue, sizeof(request_t), REQUEST_QUEUE_SIZE);
+
+/**
+* Required for the Linux version of afLib.
+*/
+#ifndef ARDUINO
+#if 0
+#include <sys/time.h>
+
+struct timeval start;
+
+long millis() {
+ gettimeofday(&start, NULL);
+ return start.tv_sec;
+}
+#endif /* for 0 */
+#endif /* ARDUINO */
+
+/**
+* These methods are required for the Arduino version of afLib.
+* They are no-ops on linux.
+*/
+void noInterrupts()
+{
+ __disable_irq() ;
+}
+
+void interrupts()
+{
+ __enable_irq() ;
+}
+
+/* for mbed implementation */
+Timer *aflib_timer = 0 ;
+
+long millis(void)
+{
+ if (aflib_timer == 0) {
+ aflib_timer = new Timer() ;
+ aflib_timer->start() ;
+ }
+ return(aflib_timer->read_ms()) ;
+}
+
+/**
+ * getRequestId
+ * by Motoo Tanaka on 20-Mar-2018
+ */
+int afLib::getRequestId(void)
+{
+ return( _requestId ) ;
+}
+
+/**
+ * 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,
+ AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog , afTransport *theTransport)
+{
+ if (_iaflib == NULL) {
+ _iaflib = new afLib( mcuInterrupt, isrWrapper, attrSet, attrNotify, theLog, theTransport);
+ }
+
+ return _iaflib;
+}
+
+/**
+ * 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(AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport)
+{
+ if (_iaflib == NULL) {
+ _iaflib = new afLib(PinName(-1), NULL, attrSet, attrNotify, theLog, theTransport);
+ }
+
+ return _iaflib;
+}
+
+/**
+ * afLib
+ *
+ * The private constructor for the afLib. This one actually initializes the afLib and prepares it for use.
+ */
+afLib::afLib(PinName mcuInterrupt, isr isrWrapper,
+ AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport)
+{
+ queueInit();
+ _theLog= theLog;
+ _theTransport= theTransport;
+ _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(_theLog);
+ _rxStatus = new StatusCommand(_theLog);
+
+ _attrSetHandler = attrSet;
+ _attrNotifyHandler = attrNotify;
+
+
+#ifdef ARDUINO
+ if (mcuInterrupt != -1) {
+ pinMode(mcuInterrupt, INPUT);
+ attachInterrupt(mcuInterrupt, isrWrapper, FALLING);
+ }
+#endif
+/* 20-Mar-2018 by Motoo Tanaka for mbed implementation */
+ if (isrWrapper != 0) {
+ fco = new InterruptIn(mcuInterrupt) ;
+ fco->fall(isrWrapper) ;
+ }
+
+ _interrupts_pending = 0;
+}
+
+/**
+ * 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) {
+ // For UART, we need to look for a magic character on the line as our interrupt.
+ // We call this method to handle that. For other interfaces, the interrupt pin is used and this method does nothing.
+ _theTransport->checkForInterrupt(&_interrupts_pending, isIdle());
+
+ if (isIdle() && (queueGet(&_request.messageType, &_request.requestId, &_request.attrId, &_request.valueLen,
+ &_request.p_value, &_request.status, &_request.reason) == 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, _request.valueLen, _request.p_value, _request.status, _request.reason);
+ break;
+
+ default:
+ _theLog->printf("loop: request type!\n");
+ }
+ }
+
+ if (_request.p_value != NULL) {
+ 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) {
+ noInterrupts();
+ _interrupts_pending += amount;
+ interrupts();
+}
+
+/**
+ * sendCommand
+ *
+ * This increments the interrupt count to kick off the state machine in the next call to loop().
+ */
+void afLib::sendCommand(void) {
+ noInterrupts();
+ if (_interrupts_pending == 0 && _state == STATE_IDLE) {
+ updateIntsPending(1);
+ }
+ interrupts();
+}
+
+/**
+ * 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, 0, 0);
+}
+
+/**
+ * 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, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+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, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+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, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+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, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+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, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+int afLib::setAttributeStr(const uint16_t attrId, const char *value) {
+ _requestId++;
+ return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, strlen(value),
+ (uint8_t *) value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+int afLib::setAttributeCStr(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, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+int afLib::setAttributeBytes(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, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
+}
+
+int afLib::setAttributeComplete(uint8_t requestId, const uint16_t attrId, const uint16_t valueLen, const uint8_t *value, uint8_t status, uint8_t reason) {
+ 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, status, reason);
+}
+
+/**
+ * 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(_theLog,requestId, MSG_TYPE_GET, attrId);
+ if (!_writeCmd->isValid()) {
+ _theLog->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(_theLog,requestId, MSG_TYPE_SET, attrId, valueLen, value);
+ if (!_writeCmd->isValid()) {
+ _theLog->printf("setAttributeComplete invalid command:");
+ _writeCmd->dumpBytes();
+ _writeCmd->dump();
+ delete (_writeCmd);
+ _writeCmd = NULL;
+ return afERROR_INVALID_COMMAND;
+ }
+
+ /**
+ * Recognize when the MCU is trying to reboot the ASR. When this is the case, the ASR will reboot before
+ * the SPI transaction completes and the _outstandingSetGetAttrId will be left set. Instead, just don't
+ * set it for this case.
+ */
+ if (attrId != AFLIB_SYSTEM_COMMAND_ATTR_ID || *value != AFLIB_SYSTEM_COMMAND_REBOOT) {
+ _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, uint16_t valueLen, uint8_t *value, uint8_t status, uint8_t reason) {
+ if (_interrupts_pending > 0 || _writeCmd != NULL) {
+ return afERROR_BUSY;
+ }
+
+ _writeCmd = new Command(_theLog, requestId, MSG_TYPE_UPDATE, attrId, status, reason, valueLen, value);
+ if (!_writeCmd->isValid()) {
+ _theLog->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) {
+ //_theLog->printf("_interrupts_pending: %d\n",_interrupts_pending );
+
+ switch (_state) {
+ case STATE_IDLE:
+ 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 && millis() - lastSync > 1000) {
+ _theLog->printf("Sync Retry\n");
+ updateIntsPending(1);
+ } else if (syncRetries >= MAX_SYNC_RETRIES) {
+ _theLog->printf("No response from ASR - does profile have MCU enabled?\n");
+ 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 = _theTransport->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 = millis();
+ 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 = _theTransport->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, &_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->printf("send bytes: %d\n", _bytesToSend);
+ _theTransport->sendBytesOffset((char *)_writeBuffer, &_bytesToSend, &_writeCmdOffset);
+
+ if (_bytesToSend == 0) {
+ _writeBufferLen = 0;
+ 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) {
+ _theTransport->recvBytesOffset((char **)&_readBuffer, &_readBufferLen, &_bytesToRecv, &_readCmdOffset);
+ if (_bytesToRecv == 0) {
+ _state = STATE_CMD_COMPLETE;
+ printState(_state);
+ _readCmd = new Command(_theLog, _readBufferLen, &_readBuffer[2]);
+ //_readCmd->dumpBytes();
+ 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) {
+ int result;
+
+ _state = STATE_IDLE;
+ printState(_state);
+ if (_readCmd != NULL) {
+ uint8_t *val = new uint8_t[_readCmd->getValueLen()];
+ _readCmd->getValue(val);
+
+ uint8_t state;
+ uint8_t reason;
+
+ switch (_readCmd->getCommand()) {
+ case MSG_TYPE_SET:
+ if (_attrSetHandler(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val)) {
+ state = UPDATE_STATE_UPDATED;
+ reason = UPDATE_REASON_SERVICE_SET;
+ } else {
+ state = UPDATE_STATE_FAILED;
+ reason = UPDATE_REASON_INTERNAL_SET_FAIL;
+ }
+ result = setAttributeComplete(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val, state, reason);
+
+ if (result != afSUCCESS) {
+ _theLog->printf("Can't reply to SET! This is FATAL!\n");
+ }
+
+ break;
+
+ case MSG_TYPE_UPDATE:
+ // If the attr update is a "fake" update, don't send it to the MCU
+ if (_readCmd->getReason() != UPDATE_REASON_FAKE_UPDATE) {
+ if (_readCmd->getAttrId() == _outstandingSetGetAttrId) {
+ _outstandingSetGetAttrId = 0;
+ }
+ static bool inNotifyHandler;
+ if (!inNotifyHandler) {
+ inNotifyHandler = true;
+ _attrNotifyHandler(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val);
+ inNotifyHandler = false;
+ }
+ lastComplete = millis();
+ }
+ break;
+
+ default:
+ break;
+ }
+ 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())) {
+ _attrNotifyHandler(_writeCmd->getReqId(), _writeCmd->getAttrId(), _writeCmd->getValueLen(), _writeCmd->getValueP());
+ lastComplete = millis();
+ }
+ delete (_writeCmd);
+ _writeCmdOffset = 0;
+ _writeCmd = NULL;
+ }
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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() {
+ if (lastComplete != 0 && (millis() - lastComplete) < MIN_TIME_BETWEEN_UPDATES_MILLIS) {
+ return false;
+ }
+ lastComplete = 0;
+ 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 disableInterrupts(){}
+void enableInterrupts(){}
+#endif
+
+void afLib::mcuISR() {
+#if (defined(DEBUG_TRANSPORT) && DEBUG_TRANSPORT > 0)
+ _theLog->printf("mcuISR\n");
+#endif
+ updateIntsPending(1);
+}
+
+/****************************************************************************
+ * Queue Methods *
+ ****************************************************************************/
+
+static uint8_t af_queue_preemption_disable(void) {
+ return 0;
+}
+
+static void af_queue_preemption_enable(uint8_t is_nested) {
+}
+
+/**
+ * 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() {
+ af_queue_init_system(af_queue_preemption_disable, af_queue_preemption_enable, _theLog);
+ AF_QUEUE_INIT(s_request_queue, sizeof(request_t), REQUEST_QUEUE_SIZE);
+}
+
+/**
+ * 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, const uint8_t status, const uint8_t reason) {
+
+ queue_t volatile *p_q = &s_request_queue;
+ request_t *p_event = (request_t *)AF_QUEUE_ELEM_ALLOC_FROM_INTERRUPT(p_q);
+ if (p_event != NULL) {
+ p_event->messageType = messageType;
+ p_event->attrId = attributeId;
+ p_event->requestId = requestId;
+ p_event->valueLen = valueLen;
+ p_event->p_value = new uint8_t[valueLen];
+ memcpy(p_event->p_value, value, valueLen);
+ p_event->status = status;
+ p_event->reason = reason;
+
+ AF_QUEUE_PUT_FROM_INTERRUPT(p_q, p_event);
+ 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, uint8_t *status, uint8_t *reason) {
+
+ if (AF_QUEUE_PEEK_FROM_INTERRUPT(&s_request_queue)) {
+ request_t *p_event = (request_t *)AF_QUEUE_GET_FROM_INTERRUPT(&s_request_queue);
+ *messageType = p_event->messageType;
+ *attributeId = p_event->attrId;
+ *requestId = p_event->requestId;
+ *valueLen = p_event->valueLen;
+ *value = new uint8_t[*valueLen];
+ memcpy(*value, p_event->p_value, *valueLen);
+ delete (p_event->p_value);
+ p_event->p_value = NULL;
+ *status = p_event->status;
+ *reason = p_event->reason;
+
+ AF_QUEUE_ELEM_FREE_FROM_INTERRUPT(&s_request_queue, p_event);
+ 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) {
+ _theLog->printf("%s\n", label);
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ _theLog->printf(", ");
+ }
+ uint8_t b = bytes[i] & 0xff;
+
+ _theLog->printf("0x%02X", b) ;
+#if 0
+ if (b < 0x10) {
+ _theLog->print("0x0");
+ _theLog->print(b, HEX);
+ } else {
+ _theLog->print("0x");
+ _theLog->print(b, HEX);
+ }
+#endif
+ }
+ _theLog->printf("\n");
+}
+
+/**
+ * printState
+ *
+ * Print the current state of the afLib state machine.
+ */
+void afLib::printState(int state) {
+#if (defined(DEBUG_TRANSPORT) && DEBUG_TRANSPORT > 0)
+ switch (state) {
+ case STATE_IDLE:
+ _theLog->printf("STATE_IDLE\n");
+ break;
+ case STATE_STATUS_SYNC:
+ _theLog->printf("STATE_STATUS_SYNC\n");
+ break;
+ case STATE_STATUS_ACK:
+ _theLog->printf("STATE_STATUS_ACK\n");
+ break;
+ case STATE_SEND_BYTES:
+ _theLog->printf("STATE_SEND_BYTES\n");
+ break;
+ case STATE_RECV_BYTES:
+ _theLog->printf("STATE_RECV_BYTES\n");
+ break;
+ case STATE_CMD_COMPLETE:
+ _theLog->printf("STATE_CMD_COMPLETE\n");
+ break;
+ default:
+ _theLog->printf("Unknown State!\n");
+ break;
+ }
+#endif
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/afLib.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,156 @@
+/**
+ * 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.
+ */
+
+#ifndef AFLIB_H__
+#define AFLIB_H__
+
+#include "iafLib.h"
+#include "SPI.h"
+#include "Command.h"
+#include "StatusCommand.h"
+#include "afSPI.h"
+#define Stream Serial
+
+#define STATE_IDLE 0
+#define STATE_STATUS_SYNC 1
+#define STATE_STATUS_ACK 3
+#define STATE_SEND_BYTES 4
+#define STATE_RECV_BYTES 5
+#define STATE_CMD_COMPLETE 6
+
+#define REQUEST_QUEUE_SIZE 10
+
+typedef struct {
+ uint8_t messageType;
+ uint16_t attrId;
+ uint8_t requestId;
+ uint16_t valueLen;
+ uint8_t *p_value;
+ uint8_t status;
+ uint8_t reason;
+} request_t;
+
+class afLib : public iafLib {
+public:
+ afLib(AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *serial, afTransport *theTransport);
+ afLib(PinName mcuInterrupt, isr isrWrapper, AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *serial, afTransport *theTransport);
+
+ virtual int getRequestId(void) ; /* 20-Mar-2018 by Motoo Tanaka */
+
+ virtual void loop(void);
+
+ virtual int getAttribute(const uint16_t attrId);
+
+ virtual int setAttributeBool(const uint16_t attrId, const bool value);
+
+ virtual int setAttribute8(const uint16_t attrId, const int8_t value);
+
+ virtual int setAttribute16(const uint16_t attrId, const int16_t value);
+
+ virtual int setAttribute32(const uint16_t attrId, const int32_t value);
+
+ virtual int setAttribute64(const uint16_t attrId, const int64_t value);
+
+ virtual int setAttributeStr(const uint16_t attrId, const char *value);
+
+ virtual int setAttributeCStr(const uint16_t attrId, const uint16_t valueLen, const char *value);
+
+ virtual int setAttributeBytes(const uint16_t attrId, const uint16_t valueLen, const uint8_t *value);
+
+ virtual bool isIdle();
+
+ virtual void mcuISR();
+
+private:
+ Stream *_theLog;
+ afTransport *_theTransport;
+ InterruptIn *fco ; /* 20-Mar-2018 Motoo Tanaka */
+
+ //SPISettings _spiSettings;
+ volatile int _interrupts_pending;
+ int _state;
+ uint16_t _bytesToSend;
+ uint16_t _bytesToRecv;
+ uint8_t _requestId;
+ uint16_t _outstandingSetGetAttrId;
+
+ // Application Callbacks.
+ AttrSetHandler _attrSetHandler;
+ AttrNotifyHandler _attrNotifyHandler;
+
+ Command *_writeCmd;
+ uint16_t _writeBufferLen;
+ uint8_t *_writeBuffer;
+
+ Command *_readCmd;
+ uint16_t _readBufferLen;
+ uint8_t *_readBuffer;
+
+ uint16_t _writeCmdOffset;
+ uint16_t _readCmdOffset;
+
+ StatusCommand *_txStatus;
+ StatusCommand *_rxStatus;
+
+ request_t _request;
+
+#ifdef ATTRIBUTE_CLI
+ int parseCommand(const char *cmd);
+#endif
+
+ void sendCommand(void);
+
+ void runStateMachine(void);
+
+ void printState(int state);
+
+ bool inSync(StatusCommand *tx, StatusCommand *rx);
+
+ void sendBytesSPI(char *bytes, int len);
+ void sendBytesUART(char *bytes, int len);
+ void sendBytes();
+
+ void recvBytesSPI(char *bytes, int len);
+ void recvBytesUART(char *bytes, int len);
+ void recvBytes();
+
+ void dumpBytes(char *label, int len, uint8_t *bytes);
+
+ void updateIntsPending(int amount);
+
+ void queueInit(void);
+
+ int queuePut(uint8_t messageType, uint8_t requestId, const uint16_t attributeId, uint16_t valueLen, const uint8_t *value, uint8_t status, uint8_t reason);
+
+ int queueGet(uint8_t *messageType, uint8_t *requestId, uint16_t *attributeId, uint16_t *valueLen, uint8_t **value, uint8_t *status, uint8_t *reason);
+
+ int doGetAttribute(uint8_t requestId, uint16_t attrId);
+
+ int doSetAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value);
+
+ int doUpdateAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value, uint8_t status, uint8_t reason);
+
+ int setAttributeComplete(uint8_t requestId, const uint16_t attrId, const uint16_t valueLen, const uint8_t *value, uint8_t status, uint8_t reason);
+
+ void onStateIdle(void);
+ void onStateSync(void);
+ void onStateAck(void);
+ void onStateSendBytes(void);
+ void onStateRecvBytes(void);
+ void onStateCmdComplete(void);
+};
+
+#endif // AFLIB_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/afSPI.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+#ifndef AFLIB_AFSPI_H
+#define AFLIB_AFSPI_H
+
+class afSPI {
+ public:
+ virtual void begin() = 0;
+ virtual void beginSPI() = 0;
+ virtual void endSPI() = 0;
+ virtual void transfer(char *bytes,int len) = 0;
+};
+
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/afTransport.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,91 @@
+/**
+ * Copyright 2016 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.
+ */
+#ifndef AFLIB_AFTRANSPORT_H
+#define AFLIB_AFTRANSPORT_H
+
+#include "StatusCommand.h"
+
+class afTransport {
+public:
+ /*
+ * checkForInterrupt
+ *
+ * For interfaces that don't use the interrupt pin to signal they want the state machine to run (like UART).
+ */
+ virtual void checkForInterrupt(volatile int *interrupts_pending, bool idle) = 0;
+
+ /*
+ * exchangeStatus
+ *
+ * Write a status message to the interface and read one back.
+ */
+ virtual int exchangeStatus(StatusCommand *tx, StatusCommand *rx) = 0;
+
+ /*
+ * writeStatus
+ *
+ * Write the specified status message to the interface.
+ */
+ virtual int writeStatus(StatusCommand *c) = 0;
+
+ /*
+ * sendBytes
+ *
+ * Write the specified bytes to the interface.
+ */
+ virtual void sendBytes(char *bytes, int len) = 0;
+
+ /*
+ * recvBytes
+ *
+ * Read the specified bytes from the interface.
+ */
+ virtual void recvBytes(char *bytes, int len) = 0;
+
+ /*
+ * sendBytesOffset
+ *
+ * Write bytes using an interface specific packet size.
+ * It may take multiple calls to this method to write all of the bytes.
+ *
+ * @param bytes buffer of bytes to be written.
+ * @param bytesToSend Pointer to count of total number of bytes to be written.
+ * This value is decremented after each packet is written and will be 0 when all bytes have been sent.
+ * @param offset Pointer to offset into bytes buffer.
+ * This value is incremented after each packet is written and will equal bytesToSend when all bytes have been sent.
+ */
+ virtual void sendBytesOffset(char *bytes, uint16_t *bytesToSend, uint16_t *offset) = 0;
+
+ /*
+ * recvBytesOffset
+ *
+ * Read bytes using an interface specific packet size.
+ * It may take multiple calls to this method to read all of the bytes.
+ *
+ * @param bytes Pointer to buffer of bytes to read into.
+ * This buffer is allocated for all bytesToRecv before the first packet is read.
+ * NOTE: IT IS THE CALLER'S RESPONSIBILITY TO FREE THIS BUFFER.
+ * @param bytesToRecv Pointer to count of total number of bytes to be read.
+ * This value is decremented after each packet is read and will be 0 when all bytes have been read.
+ * @param offset Pointer to offset into bytes buffer.
+ * This value is incremented after each packet is read and will equal bytesToRecv when all bytes have been read.
+ */
+ virtual void recvBytesOffset(char **bytes, uint16_t *bytesLen, uint16_t *bytesToRecv, uint16_t *offset) = 0;
+};
+
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/afUART.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+#ifndef AFLIB_AFUART_H
+#define AFLIB_AFUART_H
+
+#include <stdint.h>
+
+class afUART {
+ public:
+ virtual int available() = 0;
+ virtual char peek() = 0;
+ virtual void read(uint8_t *buffer, int len) = 0;
+ virtual char read() = 0;
+ virtual void write(uint8_t *buffer, int len) = 0;
+};
+
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/af_queue.cpp Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,266 @@
+/*
+ * af_queue.c
+ *
+ * Created on: Apr 27, 2015
+ * Author: chrisatkiban
+ */
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "af_queue.h"
+
+static Stream *_theLog = NULL;
+static uint8_t (*m_p_preemption_disable)(void);
+static void (*m_p_preemption_enable)(uint8_t is_nested);
+
+static void __af_queue_put(queue_t *p_q, af_queue_elem_desc_t *p_desc)
+{
+ if (p_q->p_head == NULL) {
+ p_q->p_tail = p_q->p_head = p_desc;
+ } else {
+ p_q->p_tail->p_next_alloc = p_desc;
+ p_q->p_tail = p_desc;
+ }
+}
+
+static void _af_queue_put(queue_t *p_q, af_queue_elem_desc_t *p_desc, bool interrupt_context)
+{
+ if (!interrupt_context) {
+ uint8_t is_nested;
+
+ is_nested = m_p_preemption_disable();
+ {
+ __af_queue_put( p_q, p_desc );
+ }
+ m_p_preemption_enable(is_nested);
+ } else {
+ __af_queue_put( p_q, p_desc );
+ }
+}
+
+static af_queue_elem_desc_t *__af_queue_elem_alloc(queue_t *p_q)
+{
+ af_queue_elem_desc_t *p_desc = NULL;
+
+ if (p_q->p_free_head != NULL) {
+ p_desc = p_q->p_free_head;
+ p_q->p_free_head = p_desc->p_next_free;
+ p_desc->p_next_alloc = NULL;
+ }
+
+ return p_desc;
+}
+
+static void *_af_queue_elem_alloc(queue_t *p_q, bool interrupt_context)
+{
+ af_queue_elem_desc_t *p_desc;
+
+ if (!interrupt_context) {
+ uint8_t is_nested;
+
+ is_nested = m_p_preemption_disable();
+ {
+ p_desc = __af_queue_elem_alloc(p_q);
+ }
+ m_p_preemption_enable(is_nested);
+ } else {
+ p_desc = __af_queue_elem_alloc(p_q);
+ }
+
+ return p_desc ? p_desc->data : NULL;
+}
+
+static af_queue_elem_desc_t *__af_queue_get(queue_t *p_q)
+{
+ af_queue_elem_desc_t *p_desc = p_q->p_head;
+
+ if (p_desc != NULL) {
+ p_q->p_head = p_desc->p_next_alloc;
+ p_desc->p_next_alloc = NULL;
+ }
+
+ if (p_q->p_head == NULL) {
+ p_q->p_tail = NULL;
+ }
+
+ return p_desc;
+}
+
+static void *_af_queue_get(queue_t *p_q, bool interrupt_context)
+{
+ af_queue_elem_desc_t *p_desc;
+
+ if (!interrupt_context) {
+ uint8_t is_nested;
+
+ is_nested = m_p_preemption_disable();
+ {
+ p_desc = __af_queue_get(p_q);
+ }
+ m_p_preemption_enable(is_nested);
+ } else {
+ p_desc = __af_queue_get(p_q);
+ }
+
+ return p_desc ? p_desc->data : NULL;
+}
+
+static void __af_queue_elem_free(queue_t *p_q, void *p_data)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+ af_queue_elem_desc_t *p_desc = (af_queue_elem_desc_t *)((uint8_t *)p_data - __builtin_offsetof(struct af_queue_elem_desc_s, data));
+#pragma GCC diagnostic push
+ af_queue_elem_desc_t *p_tmp_desc;
+
+ p_tmp_desc = p_q->p_free_head;
+ p_q->p_free_head = p_desc;
+ p_desc->p_next_free = p_tmp_desc;
+}
+
+static void _af_queue_elem_free(queue_t *p_q, void *p_data, bool interrupt_context)
+{
+ if (!interrupt_context) {
+ uint8_t is_nested;
+
+ is_nested = m_p_preemption_disable();
+ {
+ __af_queue_elem_free(p_q, p_data);
+ }
+ m_p_preemption_enable(is_nested);
+ } else {
+ __af_queue_elem_free(p_q, p_data);
+ }
+}
+
+static void *_af_queue_peek(queue_t *p_q, bool interrupt_context)
+{
+ return p_q->p_head ? p_q->p_head->data : NULL;
+}
+
+static void *_af_queue_peek_tail(queue_t *p_q, bool interrupt_context)
+{
+ return p_q->p_tail ? p_q->p_tail->data : NULL;
+}
+
+void af_queue_put(queue_t *p_q, void *p_data)
+{
+ af_queue_elem_desc_t *p_desc = (af_queue_elem_desc_t *)((uint8_t *)p_data - __builtin_offsetof(struct af_queue_elem_desc_s, data));
+ _af_queue_put(p_q, p_desc, false);
+}
+
+void af_queue_put_from_interrupt(queue_t *p_q, void *p_data)
+{
+ af_queue_elem_desc_t *p_desc = (af_queue_elem_desc_t *)((uint8_t *)p_data - __builtin_offsetof(struct af_queue_elem_desc_s, data));
+ _af_queue_put(p_q, p_desc, true);
+}
+
+void *af_queue_elem_alloc(queue_t *p_q)
+{
+ return _af_queue_elem_alloc(p_q, false);
+}
+
+void *af_queue_elem_alloc_from_interrupt(queue_t *p_q)
+{
+ return _af_queue_elem_alloc(p_q, true);
+}
+
+void *af_queue_get(queue_t *p_q)
+{
+ return _af_queue_get(p_q, false);
+}
+
+void *af_queue_get_from_interrupt(queue_t *p_q)
+{
+ return _af_queue_get(p_q, true);
+}
+
+void *af_queue_peek(queue_t *p_q)
+{
+ return _af_queue_peek(p_q, false);
+}
+
+void *af_queue_peek_from_interrupt(queue_t *p_q)
+{
+ return _af_queue_peek(p_q, true);
+}
+
+void *af_queue_peek_tail(queue_t *p_q)
+{
+ return _af_queue_peek_tail(p_q, false);
+}
+
+void *af_queue_peek_tail_from_interrupt(queue_t *p_q)
+{
+ return _af_queue_peek_tail(p_q, true);
+}
+
+void af_queue_elem_free(queue_t *p_q, void *p_data)
+{
+ _af_queue_elem_free(p_q, p_data, false);
+}
+
+void af_queue_elem_free_from_interrupt(queue_t *p_q, void *p_data)
+{
+ _af_queue_elem_free(p_q, p_data, true);
+}
+
+void af_queue_init(queue_t *p_q, int elem_size, int max_elem, uint8_t *p_mem)
+{
+ af_queue_elem_desc_t *p_desc;
+ af_queue_elem_desc_t *p_desc_next;
+ int offset;
+ int i = 0;
+
+ p_q->p_head = NULL;
+ p_q->p_tail = NULL;
+
+ // string all elements together and onto the null-terminated free list to start
+ p_q->p_free_head = (af_queue_elem_desc_t *)p_mem;
+
+ for (i = 0; i < max_elem - 1; ++i) {
+ offset = i * (ALIGN_SIZE(sizeof(af_queue_elem_desc_t), 4) + ALIGN_SIZE(elem_size, 4));
+ p_desc = (af_queue_elem_desc_t *)(p_mem + offset);
+
+ offset = (i + 1) * (ALIGN_SIZE(sizeof(af_queue_elem_desc_t), 4) + ALIGN_SIZE(elem_size, 4));
+ p_desc_next = (af_queue_elem_desc_t *)(p_mem + offset);
+ p_desc->p_next_free = p_desc_next;
+ }
+
+ offset = (max_elem - 1) * (ALIGN_SIZE(sizeof(af_queue_elem_desc_t), 4) + ALIGN_SIZE(elem_size, 4));
+ p_desc = (af_queue_elem_desc_t *)(p_mem + offset);
+ p_desc->p_next_free = NULL;
+}
+
+void af_queue_init_system(uint8_t (*p_preemption_disable)(void), void (*p_preemption_enable)(uint8_t is_nested), Stream *theLog)
+{
+ m_p_preemption_disable = p_preemption_disable;
+ m_p_preemption_enable = p_preemption_enable;
+ _theLog = theLog;
+}
+
+void af_queue_dump(queue_t *p_q)
+{
+ af_queue_elem_desc_t *p_elem;
+
+ if (_theLog != NULL) {
+ _theLog->printf("Q %X", (int)p_q);
+ _theLog->printf(" free_head %X", (int)p_q->p_free_head);
+ _theLog->printf(" head %X", (int)p_q->p_head);
+ _theLog->printf(" tail %X", (int)p_q->p_tail);
+
+ _theLog->printf("In Queue: \n"); // Not all allocated are in queue (until af_queue_put)
+ p_elem = p_q->p_head;
+ while (p_elem) {
+ _theLog->printf("%X\n", (int) p_elem);
+ p_elem = p_elem->p_next_alloc;
+ }
+
+ _theLog->printf("Free:\n");
+ p_elem = p_q->p_free_head;
+ while (p_elem) {
+ _theLog->printf("%X\n", (int) p_elem);
+ p_elem = p_elem->p_next_free;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/af_queue.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,70 @@
+/*
+ * q.h
+ *
+ * Created on: Apr 27, 2015
+ * Author: chrisatkiban
+ */
+
+#ifndef AF_QUEUE_H
+#define AF_QUEUE_H
+
+#include <stdint.h>
+#include "mbed.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ALIGN_SIZE( sizeToAlign, PowerOfTwo ) \
+ (((sizeToAlign) + (PowerOfTwo) - 1) & ~((PowerOfTwo) - 1))
+
+#define AF_QUEUE_DECLARE(q, elem_size, max_elem) queue_t volatile (q); uint8_t volatile (q##_mem)[(max_elem) * (ALIGN_SIZE(sizeof(af_queue_elem_desc_t), 4) + ALIGN_SIZE((elem_size), 4))]
+#define AF_QUEUE_INIT(q, elem_size, max_elem) af_queue_init((queue_t *)&(q), elem_size, max_elem, (uint8_t *)(q##_mem))
+#define AF_QUEUE_GET(p_q) af_queue_get((queue_t *)(p_q))
+#define AF_QUEUE_GET_FROM_INTERRUPT(p_q) af_queue_get_from_interrupt((queue_t *)(p_q))
+#define AF_QUEUE_ELEM_ALLOC(p_q) af_queue_elem_alloc((queue_t *)(p_q))
+#define AF_QUEUE_ELEM_ALLOC_FROM_INTERRUPT(p_q) af_queue_elem_alloc_from_interrupt((queue_t *)(p_q))
+#define AF_QUEUE_ELEM_FREE(p_q, p_data) af_queue_elem_free((queue_t *)(p_q), p_data)
+#define AF_QUEUE_ELEM_FREE_FROM_INTERRUPT(p_q, p_data) af_queue_elem_free_from_interrupt((queue_t *)(p_q), p_data)
+#define AF_QUEUE_PEEK(p_q) af_queue_peek((queue_t *)(p_q))
+#define AF_QUEUE_PEEK_FROM_INTERRUPT(p_q) af_queue_peek_from_interrupt((queue_t *)(p_q))
+#define AF_QUEUE_PEEK_TAIL(p_q) af_queue_peek_tail((queue_t *)(p_q))
+#define AF_QUEUE_PEEK_TAIL_FROM_INTERRUPT(p_q) af_queue_peek_tail_from_interrupt((queue_t *)(p_q))
+#define AF_QUEUE_PUT(p_q, p_data) af_queue_put((queue_t *)(p_q), p_data)
+#define AF_QUEUE_PUT_FROM_INTERRUPT(p_q, p_data) af_queue_put_from_interrupt((queue_t *)(p_q), p_data)
+
+typedef struct af_queue_elem_desc_s
+{
+ struct af_queue_elem_desc_s *p_next_alloc;
+ struct af_queue_elem_desc_s *p_next_free;
+ uint8_t data[0];
+} af_queue_elem_desc_t;
+
+typedef struct queue_s
+{
+ af_queue_elem_desc_t *p_head;
+ af_queue_elem_desc_t *p_tail;
+ af_queue_elem_desc_t *p_free_head;
+} queue_t;
+
+void af_queue_init_system(uint8_t (*p_preemption_disable)(void), void (*p_preemption_enable)(uint8_t is_nested), Stream *theLog);
+void af_queue_init(queue_t *p_q, int elem_size, int max_elem, uint8_t *p_mem);
+void *af_queue_peek(queue_t *p_q);
+void *af_queue_peek_from_interrupt(queue_t *p_q);
+void *af_queue_peek_tail(queue_t *p_q);
+void *af_queue_peek_tail_from_interrupt(queue_t *p_q);
+void *af_queue_get(queue_t *p_q);
+void *af_queue_get_from_interrupt(queue_t *p_q);
+void *af_queue_elem_alloc(queue_t *p_q);
+void *af_queue_elem_alloc_from_interrupt(queue_t *p_q);
+void af_queue_elem_free(queue_t *p_q, void *p_data);
+void af_queue_elem_free_from_interrupt(queue_t *p_q, void *p_data);
+void af_queue_put(queue_t *p_q, void *p_data);
+void af_queue_put_from_interrupt(queue_t *p_q, void *p_data);
+void af_queue_dump(queue_t *p_q);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* AF_QUEUE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/iafLib.h Tue Mar 20 06:47:25 2018 +0000
@@ -0,0 +1,115 @@
+/**
+ * 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.
+ */
+
+/**
+ * afLib public interface
+ *
+ * This file defines everything your application should need for commuinicating with the Afero ASR-1 radio module.
+ * Is there is anything missing from this file, please post a request on the developer forum and we will see what
+ * we can do.
+ */
+#ifndef AFLIB_IAFLIB_H
+#define AFLIB_IAFLIB_H
+
+#include "mbed.h"
+#define Stream Serial
+#include "afErrors.h"
+#include "afSPI.h"
+#include "afUART.h"
+#include "afTransport.h"
+
+#define afMINIMUM_TIME_BETWEEN_REQUESTS 1000
+
+#define MAX_ATTRIBUTE_SIZE 255
+
+typedef void (*isr)();
+typedef bool (*AttrSetHandler)(const uint8_t requestId, const uint16_t attributeId, const uint16_t valueLen, const uint8_t *value);
+typedef void (*AttrNotifyHandler)(const uint8_t requestId, const uint16_t attributeId, const uint16_t valueLen, const uint8_t *value);
+
+class iafLib {
+public:
+ /**
+ * create
+ *
+ * Create an instance of the afLib object. The afLib is a singleton. Calling this method multiple
+ * times will return the same instance.
+ *
+ * @param attrSet Callback for notification of attribute set requests
+ * @param attrNotify Callback for notification of attribute set request completions
+ * @param theLog An instance of a Stream object that will be used for debug prints
+ * @param theTransport An instance of an afTransport object to be used for communications with the ASR-1
+ * @param attrNotify Callback for notification of attribute set request completions
+ * @return iafLib * Instance of iafLib
+ */
+ static iafLib * create(AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport);
+
+ static iafLib * create(PinName mcuInterrupt, isr isrWrapper, AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport);
+
+ /**
+ * loop
+ *
+ * Called by the loop() method in your sketch to give afLib some CPU time
+ */
+ virtual void loop(void) = 0;
+
+ /**
+ * getAttribute
+ *
+ * Request the value of an attribute be returned from the ASR-1.
+ * Value will be returned in the attrNotify callback.
+ */
+ virtual int getAttribute(const uint16_t attrId) = 0;
+
+ /**
+ * setAttribute
+ *
+ * Request setting an attribute.
+ * For MCU attributes, the attribute value will be updated.
+ * For IO attributes, the attribute value will be updated, and then onAttrSetComplete will be called.
+ */
+ virtual int setAttributeBool(const uint16_t attrId, const bool value) = 0;
+
+ virtual int setAttribute8(const uint16_t attrId, const int8_t value) = 0;
+
+ virtual int setAttribute16(const uint16_t attrId, const int16_t value) = 0;
+
+ virtual int setAttribute32(const uint16_t attrId, const int32_t value) = 0;
+
+ virtual int setAttribute64(const uint16_t attrId, const int64_t value) = 0;
+
+ virtual int setAttributeStr(const uint16_t attrId, const char *value) = 0;
+
+ virtual int setAttributeCStr(const uint16_t attrId, const uint16_t valueLen, const char *value) = 0;
+
+ virtual int setAttributeBytes(const uint16_t attrId, const uint16_t valueLen, const uint8_t *value) = 0;
+
+ /**
+ * isIdle
+ *
+ * Call to find out of the ASR-1 is currently handling a request.
+ *
+ * @return true if an operation is in progress
+ */
+ virtual bool isIdle() = 0;
+
+ /**
+ * mcuISR
+ *
+ * Called by your sketch to pass the interrupt along to afLib.
+ */
+ virtual void mcuISR() = 0;
+};
+#endif //AFLIB_IAFLIB_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/msg_types.h Tue Mar 20 06:47:25 2018 +0000 @@ -0,0 +1,65 @@ +/** + * 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. + */ + +#ifndef MSG_TYPE_H__ +#define MSG_TYPE_H__ + +typedef uint8_t msg_type_t; + +#define SYNC_REQUEST 0x30 +#define SYNC_ACK 0x31 + +#define MSG_TYPE_UNKNOWN 0 +#define MSG_TYPE_ERROR 1 + +// Messaging channel messages +#define MESSAGE_CHANNEL_BASE 10 +#define MSG_TYPE_SET (MESSAGE_CHANNEL_BASE + 1) +#define MSG_TYPE_GET (MESSAGE_CHANNEL_BASE + 2) +#define MSG_TYPE_UPDATE (MESSAGE_CHANNEL_BASE + 3) + +#define NEGOTIATOR_CHANNEL_BASE 20 +#define MSG_TYPE_AUTHENTICATOR_SESSION_INFO (NEGOTIATOR_CHANNEL_BASE + 1) +#define MSG_TYPE_PERIPHERAL_SESSION_INFO (NEGOTIATOR_CHANNEL_BASE + 2) +#define MSG_TYPE_SIGNED_SESSION_PUBLIC_KEYS (NEGOTIATOR_CHANNEL_BASE + 3) +#define MSG_TYPE_MESSAGING_AVAILABLE (NEGOTIATOR_CHANNEL_BASE + 4) +#define MSG_TYPE_PAIRING_COMPLETE (NEGOTIATOR_CHANNEL_BASE + 5) + +// Success states +#define UPDATE_STATE_UPDATED 0 + +// Failure states +#define UPDATE_STATE_INTERRUPTED 1 +#define UPDATE_STATE_UNKNOWN_UUID 2 +#define UPDATE_STATE_LENGTH_EXCEEDED 3 +#define UPDATE_STATE_CONFLICT 4 +#define UPDATE_STATE_FAILED 5 + +#define UPDATE_REASON_UNKNOWN 0x00 +#define UPDATE_REASON_LOCAL_OR_MCU_UPDATE 0x01 // local or unsolicited UPDATE from MCU +#define UPDATE_REASON_SERVICE_SET 0x02 // response to Service SET +#define UPDATE_REASON_MCU_SET 0x03 // response to MCU SET +#define UPDATE_REASON_RELINK 0x04 +#define UPDATE_REASON_BIND_FOLLOW 0x05 // a bound attribute was changed +#define UPDATE_REASON_FAKE_UPDATE 0x06 // fake update launched +#define UPDATE_REASON_NOTIFY_MCU_WE_REBOOTED 0x07 // notify MCU we rebooted. Never goes to Service +#define UPDATE_REASON_LOCAL_SET 0x08 // response to Local SET +#define UPDATE_REASON_INTERNAL_LAST_VALID UPDATE_REASON_LOCAL_SET // always last valid #define +#define UPDATE_REASON_INTERNAL_SET_FAIL 0xfe // Set failed +#define UPDATE_REASON_INTERNAL_NO_CHANGE 0xff // do not change current value (not to be sent to Service) + +#endif // MSG_TYPE_H__ +