Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
afLib.cpp
00001 /** 00002 * Copyright 2015 Afero, Inc. 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "mbed.h" 00018 #define Stream Serial 00019 #include "afLib.h" 00020 #include "af_queue.h" 00021 00022 /** 00023 * Define this to debug your selected transport (ie SPI or UART). 00024 * This will cause a println each time an interrupt or ready byte is received from the ASR. 00025 * You will also get states printed whenever a SYNC transaction is performed by the afLib. 00026 */ 00027 #define DEBUG_TRANSPORT 0 00028 00029 /** 00030 * These are required to be able to recognize the MCU trying to reboot the ASR by setting the command 00031 * attribute. We used local defines with the aflib prefix to make sure they are always defined and don't 00032 * clash with anything the app is using. 00033 */ 00034 #define AFLIB_SYSTEM_COMMAND_ATTR_ID (65012) 00035 #define AFLIB_SYSTEM_COMMAND_REBOOT (1) 00036 00037 /** 00038 * Prevent the MCU from spamming us with too many setAttribute requests. 00039 * We do this by waiting a small amount of time in between transactions. 00040 * This prevents sync retries and allows the module to get it's work done. 00041 */ 00042 #define MIN_TIME_BETWEEN_UPDATES_MILLIS (50) 00043 00044 #define IS_MCU_ATTR(x) (x >= 0 && x < 1024) 00045 00046 static iafLib *_iaflib = NULL; 00047 00048 #define MAX_SYNC_RETRIES 10 00049 static long lastSync = 0; 00050 static int syncRetries = 0; 00051 static long lastComplete = 0; 00052 00053 AF_QUEUE_DECLARE(s_request_queue, sizeof(request_t), REQUEST_QUEUE_SIZE); 00054 00055 /** 00056 * Required for the Linux version of afLib. 00057 */ 00058 #ifndef ARDUINO 00059 #if 0 00060 #include <sys/time.h> 00061 00062 struct timeval start; 00063 00064 long millis() { 00065 gettimeofday(&start, NULL); 00066 return start.tv_sec; 00067 } 00068 #endif /* for 0 */ 00069 #endif /* ARDUINO */ 00070 00071 /** 00072 * These methods are required for the Arduino version of afLib. 00073 * They are no-ops on linux. 00074 */ 00075 void noInterrupts() 00076 { 00077 __disable_irq() ; 00078 } 00079 00080 void interrupts() 00081 { 00082 __enable_irq() ; 00083 } 00084 00085 /* for mbed implementation */ 00086 Timer *aflib_timer = 0 ; 00087 00088 long millis(void) 00089 { 00090 if (aflib_timer == 0) { 00091 aflib_timer = new Timer() ; 00092 aflib_timer->start() ; 00093 } 00094 return(aflib_timer->read_ms()) ; 00095 } 00096 00097 /** 00098 * getRequestId 00099 * by Motoo Tanaka on 20-Mar-2018 00100 */ 00101 int afLib::getRequestId(void) 00102 { 00103 return( _requestId ) ; 00104 } 00105 00106 /** 00107 * create 00108 * 00109 * The public constructor for the afLib. This allows us to create the afLib object once and hold a reference to it. 00110 */ 00111 iafLib *iafLib::create(PinName mcuInterrupt, isr isrWrapper, 00112 AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog , afTransport *theTransport) 00113 { 00114 if (_iaflib == NULL) { 00115 _iaflib = new afLib( mcuInterrupt, isrWrapper, attrSet, attrNotify, theLog, theTransport); 00116 } 00117 00118 return _iaflib; 00119 } 00120 00121 /** 00122 * create 00123 * 00124 * The public constructor for the afLib. This allows us to create the afLib object once and hold a reference to it. 00125 */ 00126 iafLib *iafLib::create(AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport) 00127 { 00128 if (_iaflib == NULL) { 00129 _iaflib = new afLib(PinName(-1), NULL, attrSet, attrNotify, theLog, theTransport); 00130 } 00131 00132 return _iaflib; 00133 } 00134 00135 /** 00136 * afLib 00137 * 00138 * The private constructor for the afLib. This one actually initializes the afLib and prepares it for use. 00139 */ 00140 afLib::afLib(PinName mcuInterrupt, isr isrWrapper, 00141 AttrSetHandler attrSet, AttrNotifyHandler attrNotify, Stream *theLog, afTransport *theTransport) 00142 { 00143 queueInit(); 00144 _theLog= theLog; 00145 _theTransport= theTransport; 00146 _request.p_value = NULL; 00147 00148 //_spiSettings = SPISettings(1000000, LSBFIRST, SPI_MODE0); 00149 _interrupts_pending = 0; 00150 _state = STATE_IDLE; 00151 00152 _writeCmd = NULL; 00153 _writeCmdOffset = 0; 00154 00155 _outstandingSetGetAttrId = 0; 00156 00157 _readCmd = NULL; 00158 _readCmdOffset = 0; 00159 _readBufferLen = 0; 00160 00161 _txStatus = new StatusCommand(_theLog); 00162 _rxStatus = new StatusCommand(_theLog); 00163 00164 _attrSetHandler = attrSet; 00165 _attrNotifyHandler = attrNotify; 00166 00167 00168 #ifdef ARDUINO 00169 if (mcuInterrupt != -1) { 00170 pinMode(mcuInterrupt, INPUT); 00171 attachInterrupt(mcuInterrupt, isrWrapper, FALLING); 00172 } 00173 #endif 00174 /* 20-Mar-2018 by Motoo Tanaka for mbed implementation */ 00175 if (isrWrapper != 0) { 00176 fco = new InterruptIn(mcuInterrupt) ; 00177 fco->fall(isrWrapper) ; 00178 } 00179 00180 _interrupts_pending = 0; 00181 } 00182 00183 /** 00184 * loop 00185 * 00186 * This is how the afLib gets time to run its state machine. This method should be called periodically from the 00187 * loop() function of the Arduino sketch. 00188 * This function pulls pending attribute operations from the queue. It takes approximately 4 calls to loop() to 00189 * complete one attribute operation. 00190 */ 00191 void afLib::loop(void) { 00192 // For UART, we need to look for a magic character on the line as our interrupt. 00193 // We call this method to handle that. For other interfaces, the interrupt pin is used and this method does nothing. 00194 _theTransport->checkForInterrupt(&_interrupts_pending, isIdle()); 00195 00196 if (isIdle() && (queueGet(&_request.messageType, &_request.requestId, &_request.attrId, &_request.valueLen, 00197 &_request.p_value, &_request.status, &_request.reason) == afSUCCESS)) { 00198 switch (_request.messageType) { 00199 case MSG_TYPE_GET: 00200 doGetAttribute(_request.requestId, _request.attrId); 00201 break; 00202 00203 case MSG_TYPE_SET: 00204 doSetAttribute(_request.requestId, _request.attrId, _request.valueLen, _request.p_value); 00205 break; 00206 00207 case MSG_TYPE_UPDATE: 00208 doUpdateAttribute(_request.requestId, _request.attrId, _request.valueLen, _request.p_value, _request.status, _request.reason); 00209 break; 00210 00211 default: 00212 _theLog->printf("loop: request type!\n"); 00213 } 00214 } 00215 00216 if (_request.p_value != NULL) { 00217 delete (_request.p_value); 00218 _request.p_value = NULL; 00219 } 00220 runStateMachine(); 00221 } 00222 00223 /** 00224 * updateIntsPending 00225 * 00226 * Interrupt-safe method for updating the interrupt count. This is called to increment and decrement the interrupt count 00227 * as interrupts are received and handled. 00228 */ 00229 void afLib::updateIntsPending(int amount) { 00230 noInterrupts(); 00231 _interrupts_pending += amount; 00232 interrupts(); 00233 } 00234 00235 /** 00236 * sendCommand 00237 * 00238 * This increments the interrupt count to kick off the state machine in the next call to loop(). 00239 */ 00240 void afLib::sendCommand(void) { 00241 noInterrupts(); 00242 if (_interrupts_pending == 0 && _state == STATE_IDLE) { 00243 updateIntsPending(1); 00244 } 00245 interrupts(); 00246 } 00247 00248 /** 00249 * getAttribute 00250 * 00251 * The public getAttribute method. This method queues the operation and returns immediately. Applications must call 00252 * loop() for the operation to complete. 00253 */ 00254 int afLib::getAttribute(const uint16_t attrId) { 00255 _requestId++; 00256 uint8_t dummy; // This value isn't actually used. 00257 return queuePut(MSG_TYPE_GET, _requestId, attrId, 0, &dummy, 0, 0); 00258 } 00259 00260 /** 00261 * The many moods of setAttribute 00262 * 00263 * These are the public versions of the setAttribute method. 00264 * These methods queue the operation and return immediately. Applications must call loop() for the operation to complete. 00265 */ 00266 int afLib::setAttributeBool(const uint16_t attrId, const bool value) { 00267 _requestId++; 00268 uint8_t val = value ? 1 : 0; 00269 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(val), 00270 (uint8_t *)&val, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE); 00271 } 00272 00273 int afLib::setAttribute8(const uint16_t attrId, const int8_t value) { 00274 _requestId++; 00275 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), 00276 (uint8_t *)&value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE); 00277 } 00278 00279 int afLib::setAttribute16(const uint16_t attrId, const int16_t value) { 00280 _requestId++; 00281 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), 00282 (uint8_t *) &value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE); 00283 } 00284 00285 int afLib::setAttribute32(const uint16_t attrId, const int32_t value) { 00286 _requestId++; 00287 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), 00288 (uint8_t *) &value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE); 00289 } 00290 00291 int afLib::setAttribute64(const uint16_t attrId, const int64_t value) { 00292 _requestId++; 00293 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, sizeof(value), 00294 (uint8_t *) &value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE); 00295 } 00296 00297 int afLib::setAttributeStr(const uint16_t attrId, const char *value) { 00298 _requestId++; 00299 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, strlen(value), 00300 (uint8_t *) value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE); 00301 } 00302 00303 int afLib::setAttributeCStr(const uint16_t attrId, const uint16_t valueLen, const char *value) { 00304 if (valueLen > MAX_ATTRIBUTE_SIZE) { 00305 return afERROR_INVALID_PARAM; 00306 } 00307 00308 if (value == NULL) { 00309 return afERROR_INVALID_PARAM; 00310 } 00311 00312 _requestId++; 00313 return queuePut(IS_MCU_ATTR(attrId) ? MSG_TYPE_UPDATE : MSG_TYPE_SET, _requestId, attrId, valueLen, 00314 (const uint8_t *) value, UPDATE_STATE_UPDATED, UPDATE_REASON_LOCAL_OR_MCU_UPDATE); 00315 } 00316 00317 int afLib::setAttributeBytes(const uint16_t attrId, const uint16_t valueLen, const uint8_t *value) { 00318 if (valueLen > MAX_ATTRIBUTE_SIZE) { 00319 return afERROR_INVALID_PARAM; 00320 } 00321 00322 if (value == NULL) { 00323 return afERROR_INVALID_PARAM; 00324 } 00325 00326 _requestId++; 00327 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); 00328 } 00329 00330 int afLib::setAttributeComplete(uint8_t requestId, const uint16_t attrId, const uint16_t valueLen, const uint8_t *value, uint8_t status, uint8_t reason) { 00331 if (valueLen > MAX_ATTRIBUTE_SIZE) { 00332 return afERROR_INVALID_PARAM; 00333 } 00334 00335 if (value == NULL) { 00336 return afERROR_INVALID_PARAM; 00337 } 00338 00339 return queuePut(MSG_TYPE_UPDATE, requestId, attrId, valueLen, value, status, reason); 00340 } 00341 00342 /** 00343 * doGetAttribute 00344 * 00345 * The private version of getAttribute. This version actually calls sendCommand() to kick off the state machine and 00346 * execute the operation. 00347 */ 00348 int afLib::doGetAttribute(uint8_t requestId, uint16_t attrId) { 00349 if (_interrupts_pending > 0 || _writeCmd != NULL) { 00350 return afERROR_BUSY; 00351 } 00352 00353 _writeCmd = new Command(_theLog,requestId, MSG_TYPE_GET, attrId); 00354 if (!_writeCmd->isValid()) { 00355 _theLog->printf("getAttribute invalid command:"); 00356 _writeCmd->dumpBytes(); 00357 _writeCmd->dump(); 00358 delete (_writeCmd); 00359 _writeCmd = NULL; 00360 return afERROR_INVALID_COMMAND; 00361 } 00362 00363 _outstandingSetGetAttrId = attrId; 00364 00365 // Start the transmission. 00366 sendCommand(); 00367 00368 return afSUCCESS; 00369 } 00370 00371 /** 00372 * doSetAttribute 00373 * 00374 * The private version of setAttribute. This version actually calls sendCommand() to kick off the state machine and 00375 * execute the operation. 00376 */ 00377 int afLib::doSetAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value) { 00378 if (_interrupts_pending > 0 || _writeCmd != NULL) { 00379 return afERROR_BUSY; 00380 } 00381 00382 _writeCmd = new Command(_theLog,requestId, MSG_TYPE_SET, attrId, valueLen, value); 00383 if (!_writeCmd->isValid()) { 00384 _theLog->printf("setAttributeComplete invalid command:"); 00385 _writeCmd->dumpBytes(); 00386 _writeCmd->dump(); 00387 delete (_writeCmd); 00388 _writeCmd = NULL; 00389 return afERROR_INVALID_COMMAND; 00390 } 00391 00392 /** 00393 * Recognize when the MCU is trying to reboot the ASR. When this is the case, the ASR will reboot before 00394 * the SPI transaction completes and the _outstandingSetGetAttrId will be left set. Instead, just don't 00395 * set it for this case. 00396 */ 00397 if (attrId != AFLIB_SYSTEM_COMMAND_ATTR_ID || *value != AFLIB_SYSTEM_COMMAND_REBOOT) { 00398 _outstandingSetGetAttrId = attrId; 00399 } 00400 00401 // Start the transmission. 00402 sendCommand(); 00403 00404 return afSUCCESS; 00405 } 00406 00407 /** 00408 * doUpdateAttribute 00409 * 00410 * setAttribute calls on MCU attributes turn into updateAttribute calls. See documentation on the SPI protocol for 00411 * more information. This method calls sendCommand() to kick off the state machine and execute the operation. 00412 */ 00413 int afLib::doUpdateAttribute(uint8_t requestId, uint16_t attrId, uint16_t valueLen, uint8_t *value, uint8_t status, uint8_t reason) { 00414 if (_interrupts_pending > 0 || _writeCmd != NULL) { 00415 return afERROR_BUSY; 00416 } 00417 00418 _writeCmd = new Command(_theLog, requestId, MSG_TYPE_UPDATE, attrId, status, reason, valueLen, value); 00419 if (!_writeCmd->isValid()) { 00420 _theLog->printf("updateAttribute invalid command:"); 00421 _writeCmd->dumpBytes(); 00422 _writeCmd->dump(); 00423 delete (_writeCmd); 00424 return afERROR_INVALID_COMMAND; 00425 } 00426 00427 // Start the transmission. 00428 sendCommand(); 00429 00430 return afSUCCESS; 00431 } 00432 00433 /** 00434 * parseCommand 00435 * 00436 * A debug method for parsing a string into a command. This is not required for library operation and is only supplied 00437 * as an example of how to execute attribute operations from a command line interface. 00438 */ 00439 #ifdef ATTRIBUTE_CLI 00440 int afLib::parseCommand(const char *cmd) { 00441 if (_interrupts_pending > 0 || _writeCmd != NULL) { 00442 _theLog->print("Busy: "); 00443 _theLog->print(_interrupts_pending); 00444 _theLog->print(", "); 00445 _theLog->println(_writeCmd != NULL); 00446 return afERROR_BUSY; 00447 } 00448 00449 int reqId = _requestId++; 00450 _writeCmd = new Command(_theLog,reqId, cmd); 00451 if (!_writeCmd->isValid()) { 00452 _theLog->print("BAD: "); 00453 _theLog->println(cmd); 00454 _writeCmd->dumpBytes(); 00455 _writeCmd->dump(); 00456 delete (_writeCmd); 00457 _writeCmd = NULL; 00458 return afERROR_INVALID_COMMAND; 00459 } 00460 00461 // Start the transmission. 00462 sendCommand(); 00463 00464 return afSUCCESS; 00465 } 00466 #endif 00467 00468 /** 00469 * runStateMachine 00470 * 00471 * The state machine for afLib. This state machine is responsible for implementing the KSP SPI protocol and executing 00472 * attribute operations. 00473 * This method is run: 00474 * 1. In response to receiving an interrupt from the ASR-1. 00475 * 2. When an attribute operation is pulled out of the queue and executed. 00476 */ 00477 void afLib::runStateMachine(void) { 00478 if (_interrupts_pending > 0) { 00479 // _theLog->printf("_interrupts_pending: %d\n",_interrupts_pending ); 00480 00481 switch (_state) { 00482 case STATE_IDLE: 00483 onStateIdle(); 00484 return; 00485 00486 case STATE_STATUS_SYNC: 00487 onStateSync(); 00488 break; 00489 00490 case STATE_STATUS_ACK: 00491 onStateAck(); 00492 break; 00493 00494 case STATE_SEND_BYTES: 00495 onStateSendBytes(); 00496 break; 00497 00498 case STATE_RECV_BYTES: 00499 onStateRecvBytes(); 00500 break; 00501 00502 case STATE_CMD_COMPLETE: 00503 onStateCmdComplete(); 00504 break; 00505 } 00506 00507 updateIntsPending(-1); 00508 } else { 00509 if (syncRetries > 0 && syncRetries < MAX_SYNC_RETRIES && millis() - lastSync > 1000) { 00510 _theLog->printf("Sync Retry\n"); 00511 updateIntsPending(1); 00512 } else if (syncRetries >= MAX_SYNC_RETRIES) { 00513 _theLog->printf("No response from ASR - does profile have MCU enabled?\n"); 00514 syncRetries = 0; 00515 _state = STATE_IDLE; 00516 } 00517 } 00518 } 00519 00520 /** 00521 * onStateIdle 00522 * 00523 * If there is a command to be written, update the bytes to send. Otherwise we're sending a zero-sync message. 00524 * Either way advance the state to send a sync message. 00525 */ 00526 void afLib::onStateIdle(void) { 00527 if (_writeCmd != NULL) { 00528 // Include 2 bytes for length 00529 _bytesToSend = _writeCmd->getSize() + 2; 00530 } else { 00531 _bytesToSend = 0; 00532 } 00533 _state = STATE_STATUS_SYNC; 00534 printState(_state); 00535 } 00536 00537 /** 00538 * onStateSync 00539 * 00540 * Write a sync message over SPI to let the ASR-1 know that we want to send some data. 00541 * Check for a "collision" which occurs if the ASR-1 is trying to send us data at the same time. 00542 */ 00543 void afLib::onStateSync(void) { 00544 int result; 00545 00546 _txStatus->setAck(false); 00547 _txStatus->setBytesToSend(_bytesToSend); 00548 _txStatus->setBytesToRecv(0); 00549 00550 result = _theTransport->exchangeStatus(_txStatus, _rxStatus); 00551 00552 if (result == afSUCCESS && _rxStatus->isValid() && inSync(_txStatus, _rxStatus)) { 00553 syncRetries = 0; // Flag that sync completed. 00554 _state = STATE_STATUS_ACK; 00555 if (_txStatus->getBytesToSend() == 0 && _rxStatus->getBytesToRecv() > 0) { 00556 _bytesToRecv = _rxStatus->getBytesToRecv(); 00557 } 00558 } else { 00559 // Try resending the preamble 00560 _state = STATE_STATUS_SYNC; 00561 lastSync = millis(); 00562 syncRetries++; 00563 // _txStatus->dumpBytes(); 00564 // _rxStatus->dumpBytes(); 00565 } 00566 printState(_state); 00567 } 00568 00569 /** 00570 * onStateAck 00571 * 00572 * Acknowledge the previous sync message and advance the state. 00573 * If there are bytes to send, advance to send bytes state. 00574 * If there are bytes to receive, advance to receive bytes state. 00575 * Otherwise it was a zero-sync so advance to command complete. 00576 */ 00577 void afLib::onStateAck(void) { 00578 int result; 00579 00580 _txStatus->setAck(true); 00581 _txStatus->setBytesToRecv(_rxStatus->getBytesToRecv()); 00582 _bytesToRecv = _rxStatus->getBytesToRecv(); 00583 result = _theTransport->writeStatus(_txStatus); 00584 if (result != afSUCCESS) { 00585 _state = STATE_STATUS_SYNC; 00586 printState(_state); 00587 return; 00588 } 00589 if (_bytesToSend > 0) { 00590 _writeBufferLen = (uint16_t) _writeCmd->getSize(); 00591 _writeBuffer = new uint8_t[_bytesToSend]; 00592 memcpy(_writeBuffer, &_writeBufferLen, 2); 00593 _writeCmd->getBytes(&_writeBuffer[2]); 00594 _state = STATE_SEND_BYTES; 00595 } else if (_bytesToRecv > 0) { 00596 _state = STATE_RECV_BYTES; 00597 } else { 00598 _state = STATE_CMD_COMPLETE; 00599 } 00600 printState(_state); 00601 } 00602 00603 /** 00604 * onStateSendBytes 00605 * 00606 * Send the required number of bytes to the ASR-1 and then advance to command complete. 00607 */ 00608 void afLib::onStateSendBytes(void) { 00609 //_theLog->printf("send bytes: %d\n", _bytesToSend); 00610 _theTransport->sendBytesOffset((char *)_writeBuffer, &_bytesToSend, &_writeCmdOffset); 00611 00612 if (_bytesToSend == 0) { 00613 _writeBufferLen = 0; 00614 delete (_writeBuffer); 00615 _writeBuffer = NULL; 00616 _state = STATE_CMD_COMPLETE; 00617 printState(_state); 00618 } 00619 } 00620 00621 /** 00622 * onStateRecvBytes 00623 * 00624 * Receive the required number of bytes from the ASR-1 and then advance to command complete. 00625 */ 00626 void afLib::onStateRecvBytes(void) { 00627 _theTransport->recvBytesOffset((char **)&_readBuffer, &_readBufferLen, &_bytesToRecv, &_readCmdOffset); 00628 if (_bytesToRecv == 0) { 00629 _state = STATE_CMD_COMPLETE; 00630 printState(_state); 00631 _readCmd = new Command(_theLog, _readBufferLen, &_readBuffer[2]); 00632 //_readCmd->dumpBytes(); 00633 delete (_readBuffer); 00634 _readBuffer = NULL; 00635 } 00636 } 00637 00638 /** 00639 * onStateCmdComplete 00640 * 00641 * Call the appropriate sketch callback to report the result of the command. 00642 * Clear the command object and go back to waiting for the next interrupt or command. 00643 */ 00644 void afLib::onStateCmdComplete(void) { 00645 int result; 00646 00647 _state = STATE_IDLE; 00648 printState(_state); 00649 if (_readCmd != NULL) { 00650 uint8_t *val = new uint8_t[_readCmd->getValueLen()]; 00651 _readCmd->getValue(val); 00652 00653 uint8_t state; 00654 uint8_t reason; 00655 00656 switch (_readCmd->getCommand()) { 00657 case MSG_TYPE_SET: 00658 if (_attrSetHandler(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val)) { 00659 state = UPDATE_STATE_UPDATED; 00660 reason = UPDATE_REASON_SERVICE_SET; 00661 } else { 00662 state = UPDATE_STATE_FAILED; 00663 reason = UPDATE_REASON_INTERNAL_SET_FAIL; 00664 } 00665 result = setAttributeComplete(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val, state, reason); 00666 00667 if (result != afSUCCESS) { 00668 _theLog->printf("Can't reply to SET! This is FATAL!\n"); 00669 } 00670 00671 break; 00672 00673 case MSG_TYPE_UPDATE: 00674 // If the attr update is a "fake" update, don't send it to the MCU 00675 if (_readCmd->getReason() != UPDATE_REASON_FAKE_UPDATE) { 00676 if (_readCmd->getAttrId() == _outstandingSetGetAttrId) { 00677 _outstandingSetGetAttrId = 0; 00678 } 00679 static bool inNotifyHandler; 00680 if (!inNotifyHandler) { 00681 inNotifyHandler = true; 00682 _attrNotifyHandler(_readCmd->getReqId(), _readCmd->getAttrId(), _readCmd->getValueLen(), val); 00683 inNotifyHandler = false; 00684 } 00685 lastComplete = millis(); 00686 } 00687 break; 00688 00689 default: 00690 break; 00691 } 00692 delete (val); 00693 delete (_readCmd); 00694 _readCmdOffset = 0; 00695 _readCmd = NULL; 00696 } 00697 00698 if (_writeCmd != NULL) { 00699 // Fake a callback here for MCU attributes as we don't get one from the module. 00700 if (_writeCmd->getCommand() == MSG_TYPE_UPDATE && IS_MCU_ATTR(_writeCmd->getAttrId())) { 00701 _attrNotifyHandler(_writeCmd->getReqId(), _writeCmd->getAttrId(), _writeCmd->getValueLen(), _writeCmd->getValueP()); 00702 lastComplete = millis(); 00703 } 00704 delete (_writeCmd); 00705 _writeCmdOffset = 0; 00706 _writeCmd = NULL; 00707 } 00708 } 00709 00710 /** 00711 * inSync 00712 * 00713 * Check to make sure the Arduino and the ASR-1 aren't trying to send data at the same time. 00714 * Return true only if there is no collision. 00715 */ 00716 bool afLib::inSync(StatusCommand *tx, StatusCommand *rx) { 00717 return (tx->getBytesToSend() == 0 && rx->getBytesToRecv() == 0) || 00718 (tx->getBytesToSend() > 0 && rx->getBytesToRecv() == 0) || 00719 (tx->getBytesToSend() == 0 && rx->getBytesToRecv() > 0); 00720 } 00721 00722 /** 00723 * isIdle 00724 * 00725 * Provide a way for the sketch to know if we're idle. Returns true if there are no attribute operations in progress. 00726 */ 00727 bool afLib::isIdle() { 00728 if (lastComplete != 0 && (millis() - lastComplete) < MIN_TIME_BETWEEN_UPDATES_MILLIS) { 00729 return false; 00730 } 00731 lastComplete = 0; 00732 return _interrupts_pending == 0 && _state == STATE_IDLE && _outstandingSetGetAttrId == 0; 00733 } 00734 00735 /** 00736 * These methods are required to disable/enable interrupts for the Linux version of afLib. 00737 * They are no-ops on Arduino. 00738 */ 00739 #ifndef ARDUINO 00740 void disableInterrupts(){} 00741 void enableInterrupts(){} 00742 #endif 00743 00744 void afLib::mcuISR() { 00745 #if (defined(DEBUG_TRANSPORT) && DEBUG_TRANSPORT > 0) 00746 _theLog->printf("mcuISR\n"); 00747 #endif 00748 updateIntsPending(1); 00749 } 00750 00751 /**************************************************************************** 00752 * Queue Methods * 00753 ****************************************************************************/ 00754 00755 static uint8_t af_queue_preemption_disable(void) { 00756 return 0; 00757 } 00758 00759 static void af_queue_preemption_enable(uint8_t is_nested) { 00760 } 00761 00762 /** 00763 * queueInit 00764 * 00765 * Create a small queue to prevent flooding the ASR-1 with attribute operations. 00766 * The initial size is small to allow running on small boards like UNO. 00767 * Size can be increased on larger boards. 00768 */ 00769 void afLib::queueInit() { 00770 af_queue_init_system(af_queue_preemption_disable, af_queue_preemption_enable, _theLog); 00771 AF_QUEUE_INIT(s_request_queue, sizeof(request_t), REQUEST_QUEUE_SIZE); 00772 } 00773 00774 /** 00775 * queuePut 00776 * 00777 * Add an item to the end of the queue. Return an error if we're out of space in the queue. 00778 */ 00779 int afLib::queuePut(uint8_t messageType, uint8_t requestId, const uint16_t attributeId, uint16_t valueLen, 00780 const uint8_t *value, const uint8_t status, const uint8_t reason) { 00781 00782 queue_t volatile *p_q = &s_request_queue; 00783 request_t *p_event = (request_t *)AF_QUEUE_ELEM_ALLOC_FROM_INTERRUPT(p_q); 00784 if (p_event != NULL) { 00785 p_event->messageType = messageType; 00786 p_event->attrId = attributeId; 00787 p_event->requestId = requestId; 00788 p_event->valueLen = valueLen; 00789 p_event->p_value = new uint8_t[valueLen]; 00790 memcpy(p_event->p_value, value, valueLen); 00791 p_event->status = status; 00792 p_event->reason = reason; 00793 00794 AF_QUEUE_PUT_FROM_INTERRUPT(p_q, p_event); 00795 return afSUCCESS; 00796 } 00797 00798 return afERROR_QUEUE_OVERFLOW; 00799 } 00800 00801 /** 00802 * queueGet 00803 * 00804 * Pull and return the oldest item from the queue. Return an error if the queue is empty. 00805 */ 00806 int afLib::queueGet(uint8_t *messageType, uint8_t *requestId, uint16_t *attributeId, uint16_t *valueLen, 00807 uint8_t **value, uint8_t *status, uint8_t *reason) { 00808 00809 if (AF_QUEUE_PEEK_FROM_INTERRUPT(&s_request_queue)) { 00810 request_t *p_event = (request_t *)AF_QUEUE_GET_FROM_INTERRUPT(&s_request_queue); 00811 *messageType = p_event->messageType; 00812 *attributeId = p_event->attrId; 00813 *requestId = p_event->requestId; 00814 *valueLen = p_event->valueLen; 00815 *value = new uint8_t[*valueLen]; 00816 memcpy(*value, p_event->p_value, *valueLen); 00817 delete (p_event->p_value); 00818 p_event->p_value = NULL; 00819 *status = p_event->status; 00820 *reason = p_event->reason; 00821 00822 AF_QUEUE_ELEM_FREE_FROM_INTERRUPT(&s_request_queue, p_event); 00823 return afSUCCESS; 00824 } 00825 00826 return afERROR_QUEUE_UNDERFLOW; 00827 } 00828 00829 /**************************************************************************** 00830 * Debug Methods * 00831 ****************************************************************************/ 00832 /** 00833 * dumpBytes 00834 * 00835 * Dump a byte buffer to the debug log. 00836 */ 00837 void afLib::dumpBytes(char *label, int len, uint8_t *bytes) { 00838 _theLog->printf("%s\n", label); 00839 for (int i = 0; i < len; i++) { 00840 if (i > 0) { 00841 _theLog->printf(", "); 00842 } 00843 uint8_t b = bytes[i] & 0xff; 00844 00845 _theLog->printf("0x%02X", b) ; 00846 #if 0 00847 if (b < 0x10) { 00848 _theLog->print("0x0"); 00849 _theLog->print(b, HEX); 00850 } else { 00851 _theLog->print("0x"); 00852 _theLog->print(b, HEX); 00853 } 00854 #endif 00855 } 00856 _theLog->printf("\n"); 00857 } 00858 00859 /** 00860 * printState 00861 * 00862 * Print the current state of the afLib state machine. 00863 */ 00864 void afLib::printState(int state) { 00865 #if (defined(DEBUG_TRANSPORT) && DEBUG_TRANSPORT > 0) 00866 switch (state) { 00867 case STATE_IDLE: 00868 _theLog->printf("STATE_IDLE\n"); 00869 break; 00870 case STATE_STATUS_SYNC: 00871 _theLog->printf("STATE_STATUS_SYNC\n"); 00872 break; 00873 case STATE_STATUS_ACK: 00874 _theLog->printf("STATE_STATUS_ACK\n"); 00875 break; 00876 case STATE_SEND_BYTES: 00877 _theLog->printf("STATE_SEND_BYTES\n"); 00878 break; 00879 case STATE_RECV_BYTES: 00880 _theLog->printf("STATE_RECV_BYTES\n"); 00881 break; 00882 case STATE_CMD_COMPLETE: 00883 _theLog->printf("STATE_CMD_COMPLETE\n"); 00884 break; 00885 default: 00886 _theLog->printf("Unknown State!\n"); 00887 break; 00888 } 00889 #endif 00890 }
Generated on Wed Jul 13 2022 19:00:06 by
1.7.2