an old afLib which supports both SPI and UART
Embed:
(wiki syntax)
Show/hide line numbers
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