Orefatoi / afLib_1_3
Committer:
Rhyme
Date:
Mon Apr 23 06:15:05 2018 +0000
Revision:
1:112741fe45d1
Parent:
0:6f371c791202
afLib1.3 first mbed version with working UART

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Rhyme 0:6f371c791202 1 /**
Rhyme 0:6f371c791202 2 * Copyright 2015 Afero, Inc.
Rhyme 0:6f371c791202 3 *
Rhyme 0:6f371c791202 4 * Licensed under the Apache License, Version 2.0 (the "License");
Rhyme 0:6f371c791202 5 * you may not use this file except in compliance with the License.
Rhyme 0:6f371c791202 6 * You may obtain a copy of the License at
Rhyme 0:6f371c791202 7 *
Rhyme 0:6f371c791202 8 * http://www.apache.org/licenses/LICENSE-2.0
Rhyme 0:6f371c791202 9 *
Rhyme 0:6f371c791202 10 * Unless required by applicable law or agreed to in writing, software
Rhyme 0:6f371c791202 11 * distributed under the License is distributed on an "AS IS" BASIS,
Rhyme 0:6f371c791202 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Rhyme 0:6f371c791202 13 * See the License for the specific language governing permissions and
Rhyme 0:6f371c791202 14 * limitations under the License.
Rhyme 0:6f371c791202 15 */
Rhyme 0:6f371c791202 16
Rhyme 0:6f371c791202 17 #include "mbed.h"
Rhyme 0:6f371c791202 18 #define Stream Serial
Rhyme 0:6f371c791202 19 #include "afLib.h"
Rhyme 0:6f371c791202 20 #include "af_queue.h"
Rhyme 0:6f371c791202 21
Rhyme 0:6f371c791202 22 /**
Rhyme 0:6f371c791202 23 * Define this to debug your selected transport (ie SPI or UART).
Rhyme 0:6f371c791202 24 * This will cause a println each time an interrupt or ready byte is received from the ASR.
Rhyme 0:6f371c791202 25 * You will also get states printed whenever a SYNC transaction is performed by the afLib.
Rhyme 0:6f371c791202 26 */
Rhyme 0:6f371c791202 27 #define DEBUG_TRANSPORT 0
Rhyme 0:6f371c791202 28
Rhyme 0:6f371c791202 29 /**
Rhyme 0:6f371c791202 30 * These are required to be able to recognize the MCU trying to reboot the ASR by setting the command
Rhyme 0:6f371c791202 31 * attribute. We used local defines with the aflib prefix to make sure they are always defined and don't
Rhyme 0:6f371c791202 32 * clash with anything the app is using.
Rhyme 0:6f371c791202 33 */
Rhyme 0:6f371c791202 34 #define AFLIB_SYSTEM_COMMAND_ATTR_ID (65012)
Rhyme 0:6f371c791202 35 #define AFLIB_SYSTEM_COMMAND_REBOOT (1)
Rhyme 0:6f371c791202 36
Rhyme 0:6f371c791202 37 /**
Rhyme 0:6f371c791202 38 * Prevent the MCU from spamming us with too many setAttribute requests.
Rhyme 0:6f371c791202 39 * We do this by waiting a small amount of time in between transactions.
Rhyme 0:6f371c791202 40 * This prevents sync retries and allows the module to get it's work done.
Rhyme 0:6f371c791202 41 */
Rhyme 0:6f371c791202 42 #define MIN_TIME_BETWEEN_UPDATES_MILLIS (50)
Rhyme 0:6f371c791202 43
Rhyme 0:6f371c791202 44 #define IS_MCU_ATTR(x) (x >= 0 && x < 1024)
Rhyme 0:6f371c791202 45
Rhyme 0:6f371c791202 46 static iafLib *_iaflib = NULL;
Rhyme 0:6f371c791202 47
Rhyme 0:6f371c791202 48 #define MAX_SYNC_RETRIES 10
Rhyme 0:6f371c791202 49 static long lastSync = 0;
Rhyme 0:6f371c791202 50 static int syncRetries = 0;
Rhyme 0:6f371c791202 51 static long lastComplete = 0;
Rhyme 0:6f371c791202 52
Rhyme 0:6f371c791202 53 AF_QUEUE_DECLARE(s_request_queue, sizeof(request_t), REQUEST_QUEUE_SIZE);
Rhyme 0:6f371c791202 54
Rhyme 0:6f371c791202 55 /**
Rhyme 0:6f371c791202 56 * Required for the Linux version of afLib.
Rhyme 0:6f371c791202 57 */
Rhyme 0:6f371c791202 58 #ifndef ARDUINO
Rhyme 0:6f371c791202 59 #if 0
Rhyme 0:6f371c791202 60 #include <sys/time.h>
Rhyme 0:6f371c791202 61
Rhyme 0:6f371c791202 62 struct timeval start;
Rhyme 0:6f371c791202 63
Rhyme 0:6f371c791202 64 long millis() {
Rhyme 0:6f371c791202 65 gettimeofday(&start, NULL);
Rhyme 0:6f371c791202 66 return start.tv_sec;
Rhyme 0:6f371c791202 67 }
Rhyme 0:6f371c791202 68 #endif /* for 0 */
Rhyme 0:6f371c791202 69 #endif /* ARDUINO */
Rhyme 0:6f371c791202 70
Rhyme 0:6f371c791202 71 /**
Rhyme 0:6f371c791202 72 * These methods are required for the Arduino version of afLib.
Rhyme 0:6f371c791202 73 * They are no-ops on linux.
Rhyme 0:6f371c791202 74 */
Rhyme 0:6f371c791202 75 void noInterrupts()
Rhyme 0:6f371c791202 76 {
Rhyme 0:6f371c791202 77 __disable_irq() ;
Rhyme 0:6f371c791202 78 }
Rhyme 0:6f371c791202 79
Rhyme 0:6f371c791202 80 void interrupts()
Rhyme 0:6f371c791202 81 {
Rhyme 0:6f371c791202 82 __enable_irq() ;
Rhyme 0:6f371c791202 83 }
Rhyme 0:6f371c791202 84
Rhyme 0:6f371c791202 85 /* for mbed implementation */
Rhyme 0:6f371c791202 86 Timer *aflib_timer = 0 ;
Rhyme 0:6f371c791202 87
Rhyme 0:6f371c791202 88 long millis(void)
Rhyme 0:6f371c791202 89 {
Rhyme 0:6f371c791202 90 if (aflib_timer == 0) {
Rhyme 0:6f371c791202 91 aflib_timer = new Timer() ;
Rhyme 0:6f371c791202 92 aflib_timer->start() ;
Rhyme 0:6f371c791202 93 }
Rhyme 0:6f371c791202 94 return(aflib_timer->read_ms()) ;
Rhyme 0:6f371c791202 95 }
Rhyme 0:6f371c791202 96
Rhyme 0:6f371c791202 97 /**
Rhyme 0:6f371c791202 98 * getRequestId
Rhyme 0:6f371c791202 99 * by Motoo Tanaka on 20-Mar-2018
Rhyme 0:6f371c791202 100 */
Rhyme 0:6f371c791202 101 int afLib::getRequestId(void)
Rhyme 0:6f371c791202 102 {
Rhyme 0:6f371c791202 103 return( _requestId ) ;
Rhyme 0:6f371c791202 104 }
Rhyme 0:6f371c791202 105
Rhyme 0:6f371c791202 106 /**
Rhyme 0:6f371c791202 107 * create
Rhyme 0:6f371c791202 108 *
Rhyme 0:6f371c791202 109 * The public constructor for the afLib. This allows us to create the afLib object once and hold a reference to it.
Rhyme 0:6f371c791202 110 */
Rhyme 0:6f371c791202 111 iafLib *iafLib::create(PinName mcuInterrupt, isr isrWrapper,
Rhyme 0:6f371c791202 112 AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog , afTransport *theTransport)
Rhyme 0:6f371c791202 113 {
Rhyme 0:6f371c791202 114 if (_iaflib == NULL) {
Rhyme 0:6f371c791202 115 _iaflib = new afLib( mcuInterrupt, isrWrapper, attrSet, attrNotify, theLog, theTransport);
Rhyme 0:6f371c791202 116 }
Rhyme 0:6f371c791202 117
Rhyme 0:6f371c791202 118 return _iaflib;
Rhyme 0:6f371c791202 119 }
Rhyme 0:6f371c791202 120
Rhyme 0:6f371c791202 121 /**
Rhyme 0:6f371c791202 122 * create
Rhyme 0:6f371c791202 123 *
Rhyme 0:6f371c791202 124 * The public constructor for the afLib. This allows us to create the afLib object once and hold a reference to it.
Rhyme 0:6f371c791202 125 */
Rhyme 0:6f371c791202 126 iafLib *iafLib::create(AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport)
Rhyme 0:6f371c791202 127 {
Rhyme 0:6f371c791202 128 if (_iaflib == NULL) {
Rhyme 0:6f371c791202 129 _iaflib = new afLib(PinName(-1), NULL, attrSet, attrNotify, theLog, theTransport);
Rhyme 0:6f371c791202 130 }
Rhyme 0:6f371c791202 131
Rhyme 0:6f371c791202 132 return _iaflib;
Rhyme 0:6f371c791202 133 }
Rhyme 0:6f371c791202 134
Rhyme 0:6f371c791202 135 /**
Rhyme 0:6f371c791202 136 * afLib
Rhyme 0:6f371c791202 137 *
Rhyme 0:6f371c791202 138 * The private constructor for the afLib. This one actually initializes the afLib and prepares it for use.
Rhyme 0:6f371c791202 139 */
Rhyme 0:6f371c791202 140 afLib::afLib(PinName mcuInterrupt, isr isrWrapper,
Rhyme 0:6f371c791202 141 AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport)
Rhyme 0:6f371c791202 142 {
Rhyme 0:6f371c791202 143 queueInit();
Rhyme 0:6f371c791202 144 _theLog= theLog;
Rhyme 0:6f371c791202 145 _theTransport= theTransport;
Rhyme 0:6f371c791202 146 _request.p_value = NULL;
Rhyme 0:6f371c791202 147
Rhyme 0:6f371c791202 148 //_spiSettings = SPISettings(1000000, LSBFIRST, SPI_MODE0);
Rhyme 0:6f371c791202 149 _interrupts_pending = 0;
Rhyme 0:6f371c791202 150 _state = STATE_IDLE;
Rhyme 0:6f371c791202 151
Rhyme 0:6f371c791202 152 _writeCmd = NULL;
Rhyme 0:6f371c791202 153 _writeCmdOffset = 0;
Rhyme 0:6f371c791202 154
Rhyme 0:6f371c791202 155 _outstandingSetGetAttrId = 0;
Rhyme 0:6f371c791202 156
Rhyme 0:6f371c791202 157 _readCmd = NULL;
Rhyme 0:6f371c791202 158 _readCmdOffset = 0;
Rhyme 0:6f371c791202 159 _readBufferLen = 0;
Rhyme 0:6f371c791202 160
Rhyme 0:6f371c791202 161 _txStatus = new StatusCommand(_theLog);
Rhyme 0:6f371c791202 162 _rxStatus = new StatusCommand(_theLog);
Rhyme 0:6f371c791202 163
Rhyme 0:6f371c791202 164 _attrSetHandler = attrSet;
Rhyme 0:6f371c791202 165 _attrNotifyHandler = attrNotify;
Rhyme 0:6f371c791202 166
Rhyme 0:6f371c791202 167
Rhyme 0:6f371c791202 168 #ifdef ARDUINO
Rhyme 0:6f371c791202 169 if (mcuInterrupt != -1) {
Rhyme 0:6f371c791202 170 pinMode(mcuInterrupt, INPUT);
Rhyme 0:6f371c791202 171 attachInterrupt(mcuInterrupt, isrWrapper, FALLING);
Rhyme 0:6f371c791202 172 }
Rhyme 0:6f371c791202 173 #endif
Rhyme 0:6f371c791202 174 /* 20-Mar-2018 by Motoo Tanaka for mbed implementation */
Rhyme 0:6f371c791202 175 if (isrWrapper != 0) {
Rhyme 0:6f371c791202 176 fco = new InterruptIn(mcuInterrupt) ;
Rhyme 0:6f371c791202 177 fco->fall(isrWrapper) ;
Rhyme 0:6f371c791202 178 }
Rhyme 0:6f371c791202 179
Rhyme 0:6f371c791202 180 _interrupts_pending = 0;
Rhyme 0:6f371c791202 181 }
Rhyme 0:6f371c791202 182
Rhyme 0:6f371c791202 183 /**
Rhyme 0:6f371c791202 184 * loop
Rhyme 0:6f371c791202 185 *
Rhyme 0:6f371c791202 186 * This is how the afLib gets time to run its state machine. This method should be called periodically from the
Rhyme 0:6f371c791202 187 * loop() function of the Arduino sketch.
Rhyme 0:6f371c791202 188 * This function pulls pending attribute operations from the queue. It takes approximately 4 calls to loop() to
Rhyme 0:6f371c791202 189 * complete one attribute operation.
Rhyme 0:6f371c791202 190 */
Rhyme 0:6f371c791202 191 void afLib::loop(void) {
Rhyme 0:6f371c791202 192 // For UART, we need to look for a magic character on the line as our interrupt.
Rhyme 0:6f371c791202 193 // We call this method to handle that. For other interfaces, the interrupt pin is used and this method does nothing.
Rhyme 0:6f371c791202 194 _theTransport->checkForInterrupt(&_interrupts_pending, isIdle());
Rhyme 0:6f371c791202 195
Rhyme 0:6f371c791202 196 if (isIdle() && (queueGet(&_request.messageType, &_request.requestId, &_request.attrId, &_request.valueLen,
Rhyme 0:6f371c791202 197 &_request.p_value, &_request.status, &_request.reason) == afSUCCESS)) {
Rhyme 0:6f371c791202 198 switch (_request.messageType) {
Rhyme 0:6f371c791202 199 case MSG_TYPE_GET:
Rhyme 0:6f371c791202 200 doGetAttribute(_request.requestId, _request.attrId);
Rhyme 0:6f371c791202 201 break;
Rhyme 0:6f371c791202 202
Rhyme 0:6f371c791202 203 case MSG_TYPE_SET:
Rhyme 0:6f371c791202 204 doSetAttribute(_request.requestId, _request.attrId, _request.valueLen, _request.p_value);
Rhyme 0:6f371c791202 205 break;
Rhyme 0:6f371c791202 206
Rhyme 0:6f371c791202 207 case MSG_TYPE_UPDATE:
Rhyme 0:6f371c791202 208 doUpdateAttribute(_request.requestId, _request.attrId, _request.valueLen, _request.p_value, _request.status, _request.reason);
Rhyme 0:6f371c791202 209 break;
Rhyme 0:6f371c791202 210
Rhyme 0:6f371c791202 211 default:
Rhyme 0:6f371c791202 212 _theLog->printf("loop: request type!\n");
Rhyme 0:6f371c791202 213 }
Rhyme 0:6f371c791202 214 }
Rhyme 0:6f371c791202 215
Rhyme 0:6f371c791202 216 if (_request.p_value != NULL) {
Rhyme 0:6f371c791202 217 delete (_request.p_value);
Rhyme 0:6f371c791202 218 _request.p_value = NULL;
Rhyme 0:6f371c791202 219 }
Rhyme 0:6f371c791202 220 runStateMachine();
Rhyme 0:6f371c791202 221 }
Rhyme 0:6f371c791202 222
Rhyme 0:6f371c791202 223 /**
Rhyme 0:6f371c791202 224 * updateIntsPending
Rhyme 0:6f371c791202 225 *
Rhyme 0:6f371c791202 226 * Interrupt-safe method for updating the interrupt count. This is called to increment and decrement the interrupt count
Rhyme 0:6f371c791202 227 * as interrupts are received and handled.
Rhyme 0:6f371c791202 228 */
Rhyme 0:6f371c791202 229 void afLib::updateIntsPending(int amount) {
Rhyme 0:6f371c791202 230 noInterrupts();
Rhyme 0:6f371c791202 231 _interrupts_pending += amount;
Rhyme 0:6f371c791202 232 interrupts();
Rhyme 0:6f371c791202 233 }
Rhyme 0:6f371c791202 234
Rhyme 0:6f371c791202 235 /**
Rhyme 0:6f371c791202 236 * sendCommand
Rhyme 0:6f371c791202 237 *
Rhyme 0:6f371c791202 238 * This increments the interrupt count to kick off the state machine in the next call to loop().
Rhyme 0:6f371c791202 239 */
Rhyme 0:6f371c791202 240 void afLib::sendCommand(void) {
Rhyme 0:6f371c791202 241 noInterrupts();
Rhyme 0:6f371c791202 242 if (_interrupts_pending == 0 && _state == STATE_IDLE) {
Rhyme 0:6f371c791202 243 updateIntsPending(1);
Rhyme 0:6f371c791202 244 }
Rhyme 0:6f371c791202 245 interrupts();
Rhyme 0:6f371c791202 246 }
Rhyme 0:6f371c791202 247
Rhyme 0:6f371c791202 248 /**
Rhyme 0:6f371c791202 249 * getAttribute
Rhyme 0:6f371c791202 250 *
Rhyme 0:6f371c791202 251 * The public getAttribute method. This method queues the operation and returns immediately. Applications must call
Rhyme 0:6f371c791202 252 * loop() for the operation to complete.
Rhyme 0:6f371c791202 253 */
Rhyme 0:6f371c791202 254 int afLib::getAttribute(const uint16_t attrId) {
Rhyme 0:6f371c791202 255 _requestId++;
Rhyme 0:6f371c791202 256 uint8_t dummy; // This value isn't actually used.
Rhyme 0:6f371c791202 257 return queuePut(MSG_TYPE_GET, _requestId, attrId, 0, &dummy, 0, 0);
Rhyme 0:6f371c791202 258 }
Rhyme 0:6f371c791202 259
Rhyme 0:6f371c791202 260 /**
Rhyme 0:6f371c791202 261 * The many moods of setAttribute
Rhyme 0:6f371c791202 262 *
Rhyme 0:6f371c791202 263 * These are the public versions of the setAttribute method.
Rhyme 0:6f371c791202 264 * These methods queue the operation and return immediately. Applications must call loop() for the operation to complete.
Rhyme 0:6f371c791202 265 */
Rhyme 0:6f371c791202 266 int afLib::setAttributeBool(const uint16_t attrId, const bool value) {
Rhyme 0:6f371c791202 267 _requestId++;
Rhyme 0:6f371c791202 268 uint8_t val = value ? 1 : 0;
Rhyme 0:6f371c791202 269 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(val),
Rhyme 0:6f371c791202 270 (uint8_t *)&val, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
Rhyme 0:6f371c791202 271 }
Rhyme 0:6f371c791202 272
Rhyme 0:6f371c791202 273 int afLib::setAttribute8(const uint16_t attrId, const int8_t value) {
Rhyme 0:6f371c791202 274 _requestId++;
Rhyme 0:6f371c791202 275 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
Rhyme 0:6f371c791202 276 (uint8_t *)&value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
Rhyme 0:6f371c791202 277 }
Rhyme 0:6f371c791202 278
Rhyme 0:6f371c791202 279 int afLib::setAttribute16(const uint16_t attrId, const int16_t value) {
Rhyme 0:6f371c791202 280 _requestId++;
Rhyme 0:6f371c791202 281 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
Rhyme 0:6f371c791202 282 (uint8_t *) &value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
Rhyme 0:6f371c791202 283 }
Rhyme 0:6f371c791202 284
Rhyme 0:6f371c791202 285 int afLib::setAttribute32(const uint16_t attrId, const int32_t value) {
Rhyme 0:6f371c791202 286 _requestId++;
Rhyme 0:6f371c791202 287 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
Rhyme 0:6f371c791202 288 (uint8_t *) &value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
Rhyme 0:6f371c791202 289 }
Rhyme 0:6f371c791202 290
Rhyme 0:6f371c791202 291 int afLib::setAttribute64(const uint16_t attrId, const int64_t value) {
Rhyme 0:6f371c791202 292 _requestId++;
Rhyme 0:6f371c791202 293 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value),
Rhyme 0:6f371c791202 294 (uint8_t *) &value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
Rhyme 0:6f371c791202 295 }
Rhyme 0:6f371c791202 296
Rhyme 0:6f371c791202 297 int afLib::setAttributeStr(const uint16_t attrId, const char *value) {
Rhyme 0:6f371c791202 298 _requestId++;
Rhyme 0:6f371c791202 299 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, strlen(value),
Rhyme 0:6f371c791202 300 (uint8_t *) value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
Rhyme 0:6f371c791202 301 }
Rhyme 0:6f371c791202 302
Rhyme 0:6f371c791202 303 int afLib::setAttributeCStr(const uint16_t attrId, const uint16_t valueLen, const char *value) {
Rhyme 0:6f371c791202 304 if (valueLen > MAX_ATTRIBUTE_SIZE) {
Rhyme 0:6f371c791202 305 return afERROR_INVALID_PARAM;
Rhyme 0:6f371c791202 306 }
Rhyme 0:6f371c791202 307
Rhyme 0:6f371c791202 308 if (value == NULL) {
Rhyme 0:6f371c791202 309 return afERROR_INVALID_PARAM;
Rhyme 0:6f371c791202 310 }
Rhyme 0:6f371c791202 311
Rhyme 0:6f371c791202 312 _requestId++;
Rhyme 0:6f371c791202 313 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, valueLen,
Rhyme 0:6f371c791202 314 (const uint8_t *) value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE);
Rhyme 0:6f371c791202 315 }
Rhyme 0:6f371c791202 316
Rhyme 0:6f371c791202 317 int afLib::setAttributeBytes(const uint16_t attrId, const uint16_t valueLen, const uint8_t *value) {
Rhyme 0:6f371c791202 318 if (valueLen > MAX_ATTRIBUTE_SIZE) {
Rhyme 0:6f371c791202 319 return afERROR_INVALID_PARAM;
Rhyme 0:6f371c791202 320 }
Rhyme 0:6f371c791202 321
Rhyme 0:6f371c791202 322 if (value == NULL) {
Rhyme 0:6f371c791202 323 return afERROR_INVALID_PARAM;
Rhyme 0:6f371c791202 324 }
Rhyme 0:6f371c791202 325
Rhyme 0:6f371c791202 326 _requestId++;
Rhyme 0:6f371c791202 327 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);
Rhyme 0:6f371c791202 328 }
Rhyme 0:6f371c791202 329
Rhyme 0:6f371c791202 330 int afLib::setAttributeComplete(uint8_t requestId, const uint16_t attrId, const uint16_t valueLen, const uint8_t *value, uint8_t status, uint8_t reason) {
Rhyme 0:6f371c791202 331 if (valueLen > MAX_ATTRIBUTE_SIZE) {
Rhyme 0:6f371c791202 332 return afERROR_INVALID_PARAM;
Rhyme 0:6f371c791202 333 }
Rhyme 0:6f371c791202 334
Rhyme 0:6f371c791202 335 if (value == NULL) {
Rhyme 0:6f371c791202 336 return afERROR_INVALID_PARAM;
Rhyme 0:6f371c791202 337 }
Rhyme 0:6f371c791202 338
Rhyme 0:6f371c791202 339 return queuePut(MSG_TYPE_UPDATE, requestId, attrId, valueLen, value, status, reason);
Rhyme 0:6f371c791202 340 }
Rhyme 0:6f371c791202 341
Rhyme 0:6f371c791202 342 /**
Rhyme 0:6f371c791202 343 * doGetAttribute
Rhyme 0:6f371c791202 344 *
Rhyme 0:6f371c791202 345 * The private version of getAttribute. This version actually calls sendCommand() to kick off the state machine and
Rhyme 0:6f371c791202 346 * execute the operation.
Rhyme 0:6f371c791202 347 */
Rhyme 0:6f371c791202 348 int afLib::doGetAttribute(uint8_t requestId, uint16_t attrId) {
Rhyme 0:6f371c791202 349 if (_interrupts_pending > 0 || _writeCmd != NULL) {
Rhyme 0:6f371c791202 350 return afERROR_BUSY;
Rhyme 0:6f371c791202 351 }
Rhyme 0:6f371c791202 352
Rhyme 0:6f371c791202 353 _writeCmd = new Command(_theLog,requestId, MSG_TYPE_GET, attrId);
Rhyme 0:6f371c791202 354 if (!_writeCmd->isValid()) {
Rhyme 0:6f371c791202 355 _theLog->printf("getAttribute invalid command:");
Rhyme 0:6f371c791202 356 _writeCmd->dumpBytes();
Rhyme 0:6f371c791202 357 _writeCmd->dump();
Rhyme 0:6f371c791202 358 delete (_writeCmd);
Rhyme 0:6f371c791202 359 _writeCmd = NULL;
Rhyme 0:6f371c791202 360 return afERROR_INVALID_COMMAND;
Rhyme 0:6f371c791202 361 }
Rhyme 0:6f371c791202 362
Rhyme 0:6f371c791202 363 _outstandingSetGetAttrId = attrId;
Rhyme 0:6f371c791202 364
Rhyme 0:6f371c791202 365 // Start the transmission.
Rhyme 0:6f371c791202 366 sendCommand();
Rhyme 0:6f371c791202 367
Rhyme 0:6f371c791202 368 return afSUCCESS;
Rhyme 0:6f371c791202 369 }
Rhyme 0:6f371c791202 370
Rhyme 0:6f371c791202 371 /**
Rhyme 0:6f371c791202 372 * doSetAttribute
Rhyme 0:6f371c791202 373 *
Rhyme 0:6f371c791202 374 * The private version of setAttribute. This version actually calls sendCommand() to kick off the state machine and
Rhyme 0:6f371c791202 375 * execute the operation.
Rhyme 0:6f371c791202 376 */
Rhyme 0:6f371c791202 377 int afLib::doSetAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value) {
Rhyme 0:6f371c791202 378 if (_interrupts_pending > 0 || _writeCmd != NULL) {
Rhyme 0:6f371c791202 379 return afERROR_BUSY;
Rhyme 0:6f371c791202 380 }
Rhyme 0:6f371c791202 381
Rhyme 0:6f371c791202 382 _writeCmd = new Command(_theLog,requestId, MSG_TYPE_SET, attrId, valueLen, value);
Rhyme 0:6f371c791202 383 if (!_writeCmd->isValid()) {
Rhyme 0:6f371c791202 384 _theLog->printf("setAttributeComplete invalid command:");
Rhyme 0:6f371c791202 385 _writeCmd->dumpBytes();
Rhyme 0:6f371c791202 386 _writeCmd->dump();
Rhyme 0:6f371c791202 387 delete (_writeCmd);
Rhyme 0:6f371c791202 388 _writeCmd = NULL;
Rhyme 0:6f371c791202 389 return afERROR_INVALID_COMMAND;
Rhyme 0:6f371c791202 390 }
Rhyme 0:6f371c791202 391
Rhyme 0:6f371c791202 392 /**
Rhyme 0:6f371c791202 393 * Recognize when the MCU is trying to reboot the ASR. When this is the case, the ASR will reboot before
Rhyme 0:6f371c791202 394 * the SPI transaction completes and the _outstandingSetGetAttrId will be left set. Instead, just don't
Rhyme 0:6f371c791202 395 * set it for this case.
Rhyme 0:6f371c791202 396 */
Rhyme 0:6f371c791202 397 if (attrId != AFLIB_SYSTEM_COMMAND_ATTR_ID || *value != AFLIB_SYSTEM_COMMAND_REBOOT) {
Rhyme 0:6f371c791202 398 _outstandingSetGetAttrId = attrId;
Rhyme 0:6f371c791202 399 }
Rhyme 0:6f371c791202 400
Rhyme 0:6f371c791202 401 // Start the transmission.
Rhyme 0:6f371c791202 402 sendCommand();
Rhyme 0:6f371c791202 403
Rhyme 0:6f371c791202 404 return afSUCCESS;
Rhyme 0:6f371c791202 405 }
Rhyme 0:6f371c791202 406
Rhyme 0:6f371c791202 407 /**
Rhyme 0:6f371c791202 408 * doUpdateAttribute
Rhyme 0:6f371c791202 409 *
Rhyme 0:6f371c791202 410 * setAttribute calls on MCU attributes turn into updateAttribute calls. See documentation on the SPI protocol for
Rhyme 0:6f371c791202 411 * more information. This method calls sendCommand() to kick off the state machine and execute the operation.
Rhyme 0:6f371c791202 412 */
Rhyme 0:6f371c791202 413 int afLib::doUpdateAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value, uint8_t status, uint8_t reason) {
Rhyme 0:6f371c791202 414 if (_interrupts_pending > 0 || _writeCmd != NULL) {
Rhyme 0:6f371c791202 415 return afERROR_BUSY;
Rhyme 0:6f371c791202 416 }
Rhyme 0:6f371c791202 417
Rhyme 0:6f371c791202 418 _writeCmd = new Command(_theLog, requestId, MSG_TYPE_UPDATE, attrId, status, reason, valueLen, value);
Rhyme 0:6f371c791202 419 if (!_writeCmd->isValid()) {
Rhyme 0:6f371c791202 420 _theLog->printf("updateAttribute invalid command:");
Rhyme 0:6f371c791202 421 _writeCmd->dumpBytes();
Rhyme 0:6f371c791202 422 _writeCmd->dump();
Rhyme 0:6f371c791202 423 delete (_writeCmd);
Rhyme 0:6f371c791202 424 return afERROR_INVALID_COMMAND;
Rhyme 0:6f371c791202 425 }
Rhyme 0:6f371c791202 426
Rhyme 0:6f371c791202 427 // Start the transmission.
Rhyme 0:6f371c791202 428 sendCommand();
Rhyme 0:6f371c791202 429
Rhyme 0:6f371c791202 430 return afSUCCESS;
Rhyme 0:6f371c791202 431 }
Rhyme 0:6f371c791202 432
Rhyme 0:6f371c791202 433 /**
Rhyme 0:6f371c791202 434 * parseCommand
Rhyme 0:6f371c791202 435 *
Rhyme 0:6f371c791202 436 * A debug method for parsing a string into a command. This is not required for library operation and is only supplied
Rhyme 0:6f371c791202 437 * as an example of how to execute attribute operations from a command line interface.
Rhyme 0:6f371c791202 438 */
Rhyme 0:6f371c791202 439 #ifdef ATTRIBUTE_CLI
Rhyme 0:6f371c791202 440 int afLib::parseCommand(const char *cmd) {
Rhyme 0:6f371c791202 441 if (_interrupts_pending > 0 || _writeCmd != NULL) {
Rhyme 0:6f371c791202 442 _theLog->print("Busy: ");
Rhyme 0:6f371c791202 443 _theLog->print(_interrupts_pending);
Rhyme 0:6f371c791202 444 _theLog->print(", ");
Rhyme 0:6f371c791202 445 _theLog->println(_writeCmd != NULL);
Rhyme 0:6f371c791202 446 return afERROR_BUSY;
Rhyme 0:6f371c791202 447 }
Rhyme 0:6f371c791202 448
Rhyme 0:6f371c791202 449 int reqId = _requestId++;
Rhyme 0:6f371c791202 450 _writeCmd = new Command(_theLog,reqId, cmd);
Rhyme 0:6f371c791202 451 if (!_writeCmd->isValid()) {
Rhyme 0:6f371c791202 452 _theLog->print("BAD: ");
Rhyme 0:6f371c791202 453 _theLog->println(cmd);
Rhyme 0:6f371c791202 454 _writeCmd->dumpBytes();
Rhyme 0:6f371c791202 455 _writeCmd->dump();
Rhyme 0:6f371c791202 456 delete (_writeCmd);
Rhyme 0:6f371c791202 457 _writeCmd = NULL;
Rhyme 0:6f371c791202 458 return afERROR_INVALID_COMMAND;
Rhyme 0:6f371c791202 459 }
Rhyme 0:6f371c791202 460
Rhyme 0:6f371c791202 461 // Start the transmission.
Rhyme 0:6f371c791202 462 sendCommand();
Rhyme 0:6f371c791202 463
Rhyme 0:6f371c791202 464 return afSUCCESS;
Rhyme 0:6f371c791202 465 }
Rhyme 0:6f371c791202 466 #endif
Rhyme 0:6f371c791202 467
Rhyme 0:6f371c791202 468 /**
Rhyme 0:6f371c791202 469 * runStateMachine
Rhyme 0:6f371c791202 470 *
Rhyme 0:6f371c791202 471 * The state machine for afLib. This state machine is responsible for implementing the KSP SPI protocol and executing
Rhyme 0:6f371c791202 472 * attribute operations.
Rhyme 0:6f371c791202 473 * This method is run:
Rhyme 0:6f371c791202 474 * 1. In response to receiving an interrupt from the ASR-1.
Rhyme 0:6f371c791202 475 * 2. When an attribute operation is pulled out of the queue and executed.
Rhyme 0:6f371c791202 476 */
Rhyme 0:6f371c791202 477 void afLib::runStateMachine(void) {
Rhyme 0:6f371c791202 478 if (_interrupts_pending > 0) {
Rhyme 1:112741fe45d1 479 // _theLog->printf("_interrupts_pending: %d\n",_interrupts_pending );
Rhyme 0:6f371c791202 480
Rhyme 0:6f371c791202 481 switch (_state) {
Rhyme 0:6f371c791202 482 case STATE_IDLE:
Rhyme 0:6f371c791202 483 onStateIdle();
Rhyme 0:6f371c791202 484 return;
Rhyme 0:6f371c791202 485
Rhyme 0:6f371c791202 486 case STATE_STATUS_SYNC:
Rhyme 0:6f371c791202 487 onStateSync();
Rhyme 0:6f371c791202 488 break;
Rhyme 0:6f371c791202 489
Rhyme 0:6f371c791202 490 case STATE_STATUS_ACK:
Rhyme 0:6f371c791202 491 onStateAck();
Rhyme 0:6f371c791202 492 break;
Rhyme 0:6f371c791202 493
Rhyme 0:6f371c791202 494 case STATE_SEND_BYTES:
Rhyme 0:6f371c791202 495 onStateSendBytes();
Rhyme 0:6f371c791202 496 break;
Rhyme 0:6f371c791202 497
Rhyme 0:6f371c791202 498 case STATE_RECV_BYTES:
Rhyme 0:6f371c791202 499 onStateRecvBytes();
Rhyme 0:6f371c791202 500 break;
Rhyme 0:6f371c791202 501
Rhyme 0:6f371c791202 502 case STATE_CMD_COMPLETE:
Rhyme 0:6f371c791202 503 onStateCmdComplete();
Rhyme 0:6f371c791202 504 break;
Rhyme 0:6f371c791202 505 }
Rhyme 0:6f371c791202 506
Rhyme 0:6f371c791202 507 updateIntsPending(-1);
Rhyme 0:6f371c791202 508 } else {
Rhyme 0:6f371c791202 509 if (syncRetries > 0 && syncRetries < MAX_SYNC_RETRIES && millis() - lastSync > 1000) {
Rhyme 0:6f371c791202 510 _theLog->printf("Sync Retry\n");
Rhyme 0:6f371c791202 511 updateIntsPending(1);
Rhyme 0:6f371c791202 512 } else if (syncRetries >= MAX_SYNC_RETRIES) {
Rhyme 0:6f371c791202 513 _theLog->printf("No response from ASR - does profile have MCU enabled?\n");
Rhyme 0:6f371c791202 514 syncRetries = 0;
Rhyme 0:6f371c791202 515 _state = STATE_IDLE;
Rhyme 0:6f371c791202 516 }
Rhyme 0:6f371c791202 517 }
Rhyme 0:6f371c791202 518 }
Rhyme 0:6f371c791202 519
Rhyme 0:6f371c791202 520 /**
Rhyme 0:6f371c791202 521 * onStateIdle
Rhyme 0:6f371c791202 522 *
Rhyme 0:6f371c791202 523 * If there is a command to be written, update the bytes to send. Otherwise we're sending a zero-sync message.
Rhyme 0:6f371c791202 524 * Either way advance the state to send a sync message.
Rhyme 0:6f371c791202 525 */
Rhyme 0:6f371c791202 526 void afLib::onStateIdle(void) {
Rhyme 0:6f371c791202 527 if (_writeCmd != NULL) {
Rhyme 0:6f371c791202 528 // Include 2 bytes for length
Rhyme 0:6f371c791202 529 _bytesToSend = _writeCmd->getSize() + 2;
Rhyme 0:6f371c791202 530 } else {
Rhyme 0:6f371c791202 531 _bytesToSend = 0;
Rhyme 0:6f371c791202 532 }
Rhyme 0:6f371c791202 533 _state = STATE_STATUS_SYNC;
Rhyme 0:6f371c791202 534 printState(_state);
Rhyme 0:6f371c791202 535 }
Rhyme 0:6f371c791202 536
Rhyme 0:6f371c791202 537 /**
Rhyme 0:6f371c791202 538 * onStateSync
Rhyme 0:6f371c791202 539 *
Rhyme 0:6f371c791202 540 * Write a sync message over SPI to let the ASR-1 know that we want to send some data.
Rhyme 0:6f371c791202 541 * Check for a "collision" which occurs if the ASR-1 is trying to send us data at the same time.
Rhyme 0:6f371c791202 542 */
Rhyme 0:6f371c791202 543 void afLib::onStateSync(void) {
Rhyme 0:6f371c791202 544 int result;
Rhyme 0:6f371c791202 545
Rhyme 0:6f371c791202 546 _txStatus->setAck(false);
Rhyme 0:6f371c791202 547 _txStatus->setBytesToSend(_bytesToSend);
Rhyme 0:6f371c791202 548 _txStatus->setBytesToRecv(0);
Rhyme 0:6f371c791202 549
Rhyme 0:6f371c791202 550 result = _theTransport->exchangeStatus(_txStatus, _rxStatus);
Rhyme 1:112741fe45d1 551
Rhyme 0:6f371c791202 552 if (result == afSUCCESS && _rxStatus->isValid() && inSync(_txStatus, _rxStatus)) {
Rhyme 0:6f371c791202 553 syncRetries = 0; // Flag that sync completed.
Rhyme 0:6f371c791202 554 _state = STATE_STATUS_ACK;
Rhyme 0:6f371c791202 555 if (_txStatus->getBytesToSend() == 0 && _rxStatus->getBytesToRecv() > 0) {
Rhyme 0:6f371c791202 556 _bytesToRecv = _rxStatus->getBytesToRecv();
Rhyme 0:6f371c791202 557 }
Rhyme 0:6f371c791202 558 } else {
Rhyme 0:6f371c791202 559 // Try resending the preamble
Rhyme 0:6f371c791202 560 _state = STATE_STATUS_SYNC;
Rhyme 0:6f371c791202 561 lastSync = millis();
Rhyme 0:6f371c791202 562 syncRetries++;
Rhyme 1:112741fe45d1 563 // _txStatus->dumpBytes();
Rhyme 1:112741fe45d1 564 // _rxStatus->dumpBytes();
Rhyme 0:6f371c791202 565 }
Rhyme 0:6f371c791202 566 printState(_state);
Rhyme 0:6f371c791202 567 }
Rhyme 0:6f371c791202 568
Rhyme 0:6f371c791202 569 /**
Rhyme 0:6f371c791202 570 * onStateAck
Rhyme 0:6f371c791202 571 *
Rhyme 0:6f371c791202 572 * Acknowledge the previous sync message and advance the state.
Rhyme 0:6f371c791202 573 * If there are bytes to send, advance to send bytes state.
Rhyme 0:6f371c791202 574 * If there are bytes to receive, advance to receive bytes state.
Rhyme 0:6f371c791202 575 * Otherwise it was a zero-sync so advance to command complete.
Rhyme 0:6f371c791202 576 */
Rhyme 0:6f371c791202 577 void afLib::onStateAck(void) {
Rhyme 0:6f371c791202 578 int result;
Rhyme 0:6f371c791202 579
Rhyme 0:6f371c791202 580 _txStatus->setAck(true);
Rhyme 0:6f371c791202 581 _txStatus->setBytesToRecv(_rxStatus->getBytesToRecv());
Rhyme 0:6f371c791202 582 _bytesToRecv = _rxStatus->getBytesToRecv();
Rhyme 0:6f371c791202 583 result = _theTransport->writeStatus(_txStatus);
Rhyme 0:6f371c791202 584 if (result != afSUCCESS) {
Rhyme 0:6f371c791202 585 _state = STATE_STATUS_SYNC;
Rhyme 0:6f371c791202 586 printState(_state);
Rhyme 0:6f371c791202 587 return;
Rhyme 0:6f371c791202 588 }
Rhyme 0:6f371c791202 589 if (_bytesToSend > 0) {
Rhyme 0:6f371c791202 590 _writeBufferLen = (uint16_t) _writeCmd->getSize();
Rhyme 0:6f371c791202 591 _writeBuffer = new uint8_t[_bytesToSend];
Rhyme 0:6f371c791202 592 memcpy(_writeBuffer, &_writeBufferLen, 2);
Rhyme 0:6f371c791202 593 _writeCmd->getBytes(&_writeBuffer[2]);
Rhyme 0:6f371c791202 594 _state = STATE_SEND_BYTES;
Rhyme 0:6f371c791202 595 } else if (_bytesToRecv > 0) {
Rhyme 0:6f371c791202 596 _state = STATE_RECV_BYTES;
Rhyme 0:6f371c791202 597 } else {
Rhyme 0:6f371c791202 598 _state = STATE_CMD_COMPLETE;
Rhyme 0:6f371c791202 599 }
Rhyme 0:6f371c791202 600 printState(_state);
Rhyme 0:6f371c791202 601 }
Rhyme 0:6f371c791202 602
Rhyme 0:6f371c791202 603 /**
Rhyme 0:6f371c791202 604 * onStateSendBytes
Rhyme 0:6f371c791202 605 *
Rhyme 0:6f371c791202 606 * Send the required number of bytes to the ASR-1 and then advance to command complete.
Rhyme 0:6f371c791202 607 */
Rhyme 0:6f371c791202 608 void afLib::onStateSendBytes(void) {
Rhyme 0:6f371c791202 609 //_theLog->printf("send bytes: %d\n", _bytesToSend);
Rhyme 0:6f371c791202 610 _theTransport->sendBytesOffset((char *)_writeBuffer, &_bytesToSend, &_writeCmdOffset);
Rhyme 0:6f371c791202 611
Rhyme 0:6f371c791202 612 if (_bytesToSend == 0) {
Rhyme 0:6f371c791202 613 _writeBufferLen = 0;
Rhyme 0:6f371c791202 614 delete (_writeBuffer);
Rhyme 0:6f371c791202 615 _writeBuffer = NULL;
Rhyme 0:6f371c791202 616 _state = STATE_CMD_COMPLETE;
Rhyme 0:6f371c791202 617 printState(_state);
Rhyme 0:6f371c791202 618 }
Rhyme 0:6f371c791202 619 }
Rhyme 0:6f371c791202 620
Rhyme 0:6f371c791202 621 /**
Rhyme 0:6f371c791202 622 * onStateRecvBytes
Rhyme 0:6f371c791202 623 *
Rhyme 0:6f371c791202 624 * Receive the required number of bytes from the ASR-1 and then advance to command complete.
Rhyme 0:6f371c791202 625 */
Rhyme 0:6f371c791202 626 void afLib::onStateRecvBytes(void) {
Rhyme 0:6f371c791202 627 _theTransport->recvBytesOffset((char **)&_readBuffer, &_readBufferLen, &_bytesToRecv, &_readCmdOffset);
Rhyme 0:6f371c791202 628 if (_bytesToRecv == 0) {
Rhyme 0:6f371c791202 629 _state = STATE_CMD_COMPLETE;
Rhyme 0:6f371c791202 630 printState(_state);
Rhyme 0:6f371c791202 631 _readCmd = new Command(_theLog, _readBufferLen, &_readBuffer[2]);
Rhyme 0:6f371c791202 632 //_readCmd->dumpBytes();
Rhyme 0:6f371c791202 633 delete (_readBuffer);
Rhyme 0:6f371c791202 634 _readBuffer = NULL;
Rhyme 0:6f371c791202 635 }
Rhyme 0:6f371c791202 636 }
Rhyme 0:6f371c791202 637
Rhyme 0:6f371c791202 638 /**
Rhyme 0:6f371c791202 639 * onStateCmdComplete
Rhyme 0:6f371c791202 640 *
Rhyme 0:6f371c791202 641 * Call the appropriate sketch callback to report the result of the command.
Rhyme 0:6f371c791202 642 * Clear the command object and go back to waiting for the next interrupt or command.
Rhyme 0:6f371c791202 643 */
Rhyme 0:6f371c791202 644 void afLib::onStateCmdComplete(void) {
Rhyme 0:6f371c791202 645 int result;
Rhyme 0:6f371c791202 646
Rhyme 0:6f371c791202 647 _state = STATE_IDLE;
Rhyme 0:6f371c791202 648 printState(_state);
Rhyme 0:6f371c791202 649 if (_readCmd != NULL) {
Rhyme 0:6f371c791202 650 uint8_t *val = new uint8_t[_readCmd->getValueLen()];
Rhyme 0:6f371c791202 651 _readCmd->getValue(val);
Rhyme 0:6f371c791202 652
Rhyme 0:6f371c791202 653 uint8_t state;
Rhyme 0:6f371c791202 654 uint8_t reason;
Rhyme 0:6f371c791202 655
Rhyme 0:6f371c791202 656 switch (_readCmd->getCommand()) {
Rhyme 0:6f371c791202 657 case MSG_TYPE_SET:
Rhyme 0:6f371c791202 658 if (_attrSetHandler(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val)) {
Rhyme 0:6f371c791202 659 state = UPDATE_STATE_UPDATED;
Rhyme 0:6f371c791202 660 reason = UPDATE_REASON_SERVICE_SET;
Rhyme 0:6f371c791202 661 } else {
Rhyme 0:6f371c791202 662 state = UPDATE_STATE_FAILED;
Rhyme 0:6f371c791202 663 reason = UPDATE_REASON_INTERNAL_SET_FAIL;
Rhyme 0:6f371c791202 664 }
Rhyme 0:6f371c791202 665 result = setAttributeComplete(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val, state, reason);
Rhyme 0:6f371c791202 666
Rhyme 0:6f371c791202 667 if (result != afSUCCESS) {
Rhyme 0:6f371c791202 668 _theLog->printf("Can't reply to SET! This is FATAL!\n");
Rhyme 0:6f371c791202 669 }
Rhyme 0:6f371c791202 670
Rhyme 0:6f371c791202 671 break;
Rhyme 0:6f371c791202 672
Rhyme 0:6f371c791202 673 case MSG_TYPE_UPDATE:
Rhyme 0:6f371c791202 674 // If the attr update is a "fake" update, don't send it to the MCU
Rhyme 0:6f371c791202 675 if (_readCmd->getReason() != UPDATE_REASON_FAKE_UPDATE) {
Rhyme 0:6f371c791202 676 if (_readCmd->getAttrId() == _outstandingSetGetAttrId) {
Rhyme 0:6f371c791202 677 _outstandingSetGetAttrId = 0;
Rhyme 0:6f371c791202 678 }
Rhyme 0:6f371c791202 679 static bool inNotifyHandler;
Rhyme 0:6f371c791202 680 if (!inNotifyHandler) {
Rhyme 0:6f371c791202 681 inNotifyHandler = true;
Rhyme 0:6f371c791202 682 _attrNotifyHandler(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val);
Rhyme 0:6f371c791202 683 inNotifyHandler = false;
Rhyme 0:6f371c791202 684 }
Rhyme 0:6f371c791202 685 lastComplete = millis();
Rhyme 0:6f371c791202 686 }
Rhyme 0:6f371c791202 687 break;
Rhyme 0:6f371c791202 688
Rhyme 0:6f371c791202 689 default:
Rhyme 0:6f371c791202 690 break;
Rhyme 0:6f371c791202 691 }
Rhyme 0:6f371c791202 692 delete (val);
Rhyme 0:6f371c791202 693 delete (_readCmd);
Rhyme 0:6f371c791202 694 _readCmdOffset = 0;
Rhyme 0:6f371c791202 695 _readCmd = NULL;
Rhyme 0:6f371c791202 696 }
Rhyme 0:6f371c791202 697
Rhyme 0:6f371c791202 698 if (_writeCmd != NULL) {
Rhyme 0:6f371c791202 699 // Fake a callback here for MCU attributes as we don't get one from the module.
Rhyme 0:6f371c791202 700 if (_writeCmd->getCommand() == MSG_TYPE_UPDATE && IS_MCU_ATTR(_writeCmd->getAttrId())) {
Rhyme 0:6f371c791202 701 _attrNotifyHandler(_writeCmd->getReqId(), _writeCmd->getAttrId(), _writeCmd->getValueLen(), _writeCmd->getValueP());
Rhyme 0:6f371c791202 702 lastComplete = millis();
Rhyme 0:6f371c791202 703 }
Rhyme 0:6f371c791202 704 delete (_writeCmd);
Rhyme 0:6f371c791202 705 _writeCmdOffset = 0;
Rhyme 0:6f371c791202 706 _writeCmd = NULL;
Rhyme 0:6f371c791202 707 }
Rhyme 0:6f371c791202 708 }
Rhyme 0:6f371c791202 709
Rhyme 0:6f371c791202 710 /**
Rhyme 0:6f371c791202 711 * inSync
Rhyme 0:6f371c791202 712 *
Rhyme 0:6f371c791202 713 * Check to make sure the Arduino and the ASR-1 aren't trying to send data at the same time.
Rhyme 0:6f371c791202 714 * Return true only if there is no collision.
Rhyme 0:6f371c791202 715 */
Rhyme 0:6f371c791202 716 bool afLib::inSync(StatusCommand *tx, StatusCommand *rx) {
Rhyme 0:6f371c791202 717 return (tx->getBytesToSend() == 0 && rx->getBytesToRecv() == 0) ||
Rhyme 0:6f371c791202 718 (tx->getBytesToSend() > 0 && rx->getBytesToRecv() == 0) ||
Rhyme 0:6f371c791202 719 (tx->getBytesToSend() == 0 && rx->getBytesToRecv() > 0);
Rhyme 0:6f371c791202 720 }
Rhyme 0:6f371c791202 721
Rhyme 0:6f371c791202 722 /**
Rhyme 0:6f371c791202 723 * isIdle
Rhyme 0:6f371c791202 724 *
Rhyme 0:6f371c791202 725 * Provide a way for the sketch to know if we're idle. Returns true if there are no attribute operations in progress.
Rhyme 0:6f371c791202 726 */
Rhyme 0:6f371c791202 727 bool afLib::isIdle() {
Rhyme 0:6f371c791202 728 if (lastComplete != 0 && (millis() - lastComplete) < MIN_TIME_BETWEEN_UPDATES_MILLIS) {
Rhyme 0:6f371c791202 729 return false;
Rhyme 0:6f371c791202 730 }
Rhyme 0:6f371c791202 731 lastComplete = 0;
Rhyme 0:6f371c791202 732 return _interrupts_pending == 0 && _state == STATE_IDLE && _outstandingSetGetAttrId == 0;
Rhyme 0:6f371c791202 733 }
Rhyme 0:6f371c791202 734
Rhyme 0:6f371c791202 735 /**
Rhyme 0:6f371c791202 736 * These methods are required to disable/enable interrupts for the Linux version of afLib.
Rhyme 0:6f371c791202 737 * They are no-ops on Arduino.
Rhyme 0:6f371c791202 738 */
Rhyme 0:6f371c791202 739 #ifndef ARDUINO
Rhyme 0:6f371c791202 740 void disableInterrupts(){}
Rhyme 0:6f371c791202 741 void enableInterrupts(){}
Rhyme 0:6f371c791202 742 #endif
Rhyme 0:6f371c791202 743
Rhyme 0:6f371c791202 744 void afLib::mcuISR() {
Rhyme 0:6f371c791202 745 #if (defined(DEBUG_TRANSPORT) && DEBUG_TRANSPORT > 0)
Rhyme 0:6f371c791202 746 _theLog->printf("mcuISR\n");
Rhyme 0:6f371c791202 747 #endif
Rhyme 0:6f371c791202 748 updateIntsPending(1);
Rhyme 0:6f371c791202 749 }
Rhyme 0:6f371c791202 750
Rhyme 0:6f371c791202 751 /****************************************************************************
Rhyme 0:6f371c791202 752 * Queue Methods *
Rhyme 0:6f371c791202 753 ****************************************************************************/
Rhyme 0:6f371c791202 754
Rhyme 0:6f371c791202 755 static uint8_t af_queue_preemption_disable(void) {
Rhyme 0:6f371c791202 756 return 0;
Rhyme 0:6f371c791202 757 }
Rhyme 0:6f371c791202 758
Rhyme 0:6f371c791202 759 static void af_queue_preemption_enable(uint8_t is_nested) {
Rhyme 0:6f371c791202 760 }
Rhyme 0:6f371c791202 761
Rhyme 0:6f371c791202 762 /**
Rhyme 0:6f371c791202 763 * queueInit
Rhyme 0:6f371c791202 764 *
Rhyme 0:6f371c791202 765 * Create a small queue to prevent flooding the ASR-1 with attribute operations.
Rhyme 0:6f371c791202 766 * The initial size is small to allow running on small boards like UNO.
Rhyme 0:6f371c791202 767 * Size can be increased on larger boards.
Rhyme 0:6f371c791202 768 */
Rhyme 0:6f371c791202 769 void afLib::queueInit() {
Rhyme 0:6f371c791202 770 af_queue_init_system(af_queue_preemption_disable, af_queue_preemption_enable, _theLog);
Rhyme 0:6f371c791202 771 AF_QUEUE_INIT(s_request_queue, sizeof(request_t), REQUEST_QUEUE_SIZE);
Rhyme 0:6f371c791202 772 }
Rhyme 0:6f371c791202 773
Rhyme 0:6f371c791202 774 /**
Rhyme 0:6f371c791202 775 * queuePut
Rhyme 0:6f371c791202 776 *
Rhyme 0:6f371c791202 777 * Add an item to the end of the queue. Return an error if we're out of space in the queue.
Rhyme 0:6f371c791202 778 */
Rhyme 0:6f371c791202 779 int afLib::queuePut(uint8_t messageType, uint8_t requestId, const uint16_t attributeId, uint16_t valueLen,
Rhyme 0:6f371c791202 780 const uint8_t *value, const uint8_t status, const uint8_t reason) {
Rhyme 0:6f371c791202 781
Rhyme 0:6f371c791202 782 queue_t volatile *p_q = &s_request_queue;
Rhyme 0:6f371c791202 783 request_t *p_event = (request_t *)AF_QUEUE_ELEM_ALLOC_FROM_INTERRUPT(p_q);
Rhyme 0:6f371c791202 784 if (p_event != NULL) {
Rhyme 0:6f371c791202 785 p_event->messageType = messageType;
Rhyme 0:6f371c791202 786 p_event->attrId = attributeId;
Rhyme 0:6f371c791202 787 p_event->requestId = requestId;
Rhyme 0:6f371c791202 788 p_event->valueLen = valueLen;
Rhyme 0:6f371c791202 789 p_event->p_value = new uint8_t[valueLen];
Rhyme 0:6f371c791202 790 memcpy(p_event->p_value, value, valueLen);
Rhyme 0:6f371c791202 791 p_event->status = status;
Rhyme 0:6f371c791202 792 p_event->reason = reason;
Rhyme 0:6f371c791202 793
Rhyme 0:6f371c791202 794 AF_QUEUE_PUT_FROM_INTERRUPT(p_q, p_event);
Rhyme 0:6f371c791202 795 return afSUCCESS;
Rhyme 0:6f371c791202 796 }
Rhyme 0:6f371c791202 797
Rhyme 0:6f371c791202 798 return afERROR_QUEUE_OVERFLOW;
Rhyme 0:6f371c791202 799 }
Rhyme 0:6f371c791202 800
Rhyme 0:6f371c791202 801 /**
Rhyme 0:6f371c791202 802 * queueGet
Rhyme 0:6f371c791202 803 *
Rhyme 0:6f371c791202 804 * Pull and return the oldest item from the queue. Return an error if the queue is empty.
Rhyme 0:6f371c791202 805 */
Rhyme 0:6f371c791202 806 int afLib::queueGet(uint8_t *messageType, uint8_t *requestId, uint16_t *attributeId, uint16_t *valueLen,
Rhyme 0:6f371c791202 807 uint8_t **value, uint8_t *status, uint8_t *reason) {
Rhyme 0:6f371c791202 808
Rhyme 0:6f371c791202 809 if (AF_QUEUE_PEEK_FROM_INTERRUPT(&s_request_queue)) {
Rhyme 0:6f371c791202 810 request_t *p_event = (request_t *)AF_QUEUE_GET_FROM_INTERRUPT(&s_request_queue);
Rhyme 0:6f371c791202 811 *messageType = p_event->messageType;
Rhyme 0:6f371c791202 812 *attributeId = p_event->attrId;
Rhyme 0:6f371c791202 813 *requestId = p_event->requestId;
Rhyme 0:6f371c791202 814 *valueLen = p_event->valueLen;
Rhyme 0:6f371c791202 815 *value = new uint8_t[*valueLen];
Rhyme 0:6f371c791202 816 memcpy(*value, p_event->p_value, *valueLen);
Rhyme 0:6f371c791202 817 delete (p_event->p_value);
Rhyme 0:6f371c791202 818 p_event->p_value = NULL;
Rhyme 0:6f371c791202 819 *status = p_event->status;
Rhyme 0:6f371c791202 820 *reason = p_event->reason;
Rhyme 0:6f371c791202 821
Rhyme 0:6f371c791202 822 AF_QUEUE_ELEM_FREE_FROM_INTERRUPT(&s_request_queue, p_event);
Rhyme 0:6f371c791202 823 return afSUCCESS;
Rhyme 0:6f371c791202 824 }
Rhyme 0:6f371c791202 825
Rhyme 0:6f371c791202 826 return afERROR_QUEUE_UNDERFLOW;
Rhyme 0:6f371c791202 827 }
Rhyme 0:6f371c791202 828
Rhyme 0:6f371c791202 829 /****************************************************************************
Rhyme 0:6f371c791202 830 * Debug Methods *
Rhyme 0:6f371c791202 831 ****************************************************************************/
Rhyme 0:6f371c791202 832 /**
Rhyme 0:6f371c791202 833 * dumpBytes
Rhyme 0:6f371c791202 834 *
Rhyme 0:6f371c791202 835 * Dump a byte buffer to the debug log.
Rhyme 0:6f371c791202 836 */
Rhyme 0:6f371c791202 837 void afLib::dumpBytes(char *label, int len, uint8_t *bytes) {
Rhyme 0:6f371c791202 838 _theLog->printf("%s\n", label);
Rhyme 0:6f371c791202 839 for (int i = 0; i < len; i++) {
Rhyme 0:6f371c791202 840 if (i > 0) {
Rhyme 0:6f371c791202 841 _theLog->printf(", ");
Rhyme 0:6f371c791202 842 }
Rhyme 0:6f371c791202 843 uint8_t b = bytes[i] & 0xff;
Rhyme 0:6f371c791202 844
Rhyme 0:6f371c791202 845 _theLog->printf("0x%02X", b) ;
Rhyme 0:6f371c791202 846 #if 0
Rhyme 0:6f371c791202 847 if (b < 0x10) {
Rhyme 0:6f371c791202 848 _theLog->print("0x0");
Rhyme 0:6f371c791202 849 _theLog->print(b, HEX);
Rhyme 0:6f371c791202 850 } else {
Rhyme 0:6f371c791202 851 _theLog->print("0x");
Rhyme 0:6f371c791202 852 _theLog->print(b, HEX);
Rhyme 0:6f371c791202 853 }
Rhyme 0:6f371c791202 854 #endif
Rhyme 0:6f371c791202 855 }
Rhyme 0:6f371c791202 856 _theLog->printf("\n");
Rhyme 0:6f371c791202 857 }
Rhyme 0:6f371c791202 858
Rhyme 0:6f371c791202 859 /**
Rhyme 0:6f371c791202 860 * printState
Rhyme 0:6f371c791202 861 *
Rhyme 0:6f371c791202 862 * Print the current state of the afLib state machine.
Rhyme 0:6f371c791202 863 */
Rhyme 0:6f371c791202 864 void afLib::printState(int state) {
Rhyme 0:6f371c791202 865 #if (defined(DEBUG_TRANSPORT) && DEBUG_TRANSPORT > 0)
Rhyme 0:6f371c791202 866 switch (state) {
Rhyme 0:6f371c791202 867 case STATE_IDLE:
Rhyme 0:6f371c791202 868 _theLog->printf("STATE_IDLE\n");
Rhyme 0:6f371c791202 869 break;
Rhyme 0:6f371c791202 870 case STATE_STATUS_SYNC:
Rhyme 0:6f371c791202 871 _theLog->printf("STATE_STATUS_SYNC\n");
Rhyme 0:6f371c791202 872 break;
Rhyme 0:6f371c791202 873 case STATE_STATUS_ACK:
Rhyme 0:6f371c791202 874 _theLog->printf("STATE_STATUS_ACK\n");
Rhyme 0:6f371c791202 875 break;
Rhyme 0:6f371c791202 876 case STATE_SEND_BYTES:
Rhyme 0:6f371c791202 877 _theLog->printf("STATE_SEND_BYTES\n");
Rhyme 0:6f371c791202 878 break;
Rhyme 0:6f371c791202 879 case STATE_RECV_BYTES:
Rhyme 0:6f371c791202 880 _theLog->printf("STATE_RECV_BYTES\n");
Rhyme 0:6f371c791202 881 break;
Rhyme 0:6f371c791202 882 case STATE_CMD_COMPLETE:
Rhyme 0:6f371c791202 883 _theLog->printf("STATE_CMD_COMPLETE\n");
Rhyme 0:6f371c791202 884 break;
Rhyme 0:6f371c791202 885 default:
Rhyme 0:6f371c791202 886 _theLog->printf("Unknown State!\n");
Rhyme 0:6f371c791202 887 break;
Rhyme 0:6f371c791202 888 }
Rhyme 0:6f371c791202 889 #endif
Rhyme 0:6f371c791202 890 }