an old afLib which supports both SPI and UART

Files at this revision

API Documentation at this revision

Comitter:
Rhyme
Date:
Tue Mar 20 06:47:25 2018 +0000
Child:
1:112741fe45d1
Commit message:
SPI mode started working

Changed in this revision

Command.cpp Show annotated file Show diff for this revision Revisions of this file
Command.h Show annotated file Show diff for this revision Revisions of this file
ModuleCommands.h Show annotated file Show diff for this revision Revisions of this file
ModuleStates.h Show annotated file Show diff for this revision Revisions of this file
StatusCommand.cpp Show annotated file Show diff for this revision Revisions of this file
StatusCommand.h Show annotated file Show diff for this revision Revisions of this file
afErrors.h Show annotated file Show diff for this revision Revisions of this file
afLib.cpp Show annotated file Show diff for this revision Revisions of this file
afLib.h Show annotated file Show diff for this revision Revisions of this file
afSPI.h Show annotated file Show diff for this revision Revisions of this file
afTransport.h Show annotated file Show diff for this revision Revisions of this file
afUART.h Show annotated file Show diff for this revision Revisions of this file
af_queue.cpp Show annotated file Show diff for this revision Revisions of this file
af_queue.h Show annotated file Show diff for this revision Revisions of this file
iafLib.h Show annotated file Show diff for this revision Revisions of this file
msg_types.h Show annotated file Show diff for this revision Revisions of this file
--- /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__
+