1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-24 13:21:23 +01:00

Add option to suppress I2C retries.

I2CRB method suppressRetries() added to allow retries to be suppressed.
This commit is contained in:
Neil McKechnie 2023-01-14 18:58:06 +00:00
parent 6e69df2da8
commit 538519dd9d
4 changed files with 29 additions and 7 deletions

View File

@ -81,8 +81,13 @@ void I2CManagerClass::forceClock(uint32_t speed) {
// Check if specified I2C address is responding (blocking operation) // Check if specified I2C address is responding (blocking operation)
// Returns I2C_STATUS_OK (0) if OK, or error code. // Returns I2C_STATUS_OK (0) if OK, or error code.
// Suppress retries. If it doesn't respond first time it's out of the running.
uint8_t I2CManagerClass::checkAddress(uint8_t address) { uint8_t I2CManagerClass::checkAddress(uint8_t address) {
return write(address, NULL, 0); I2CRB rb;
rb.setWriteParams(address, NULL, 0);
rb.suppressRetries(true);
queueRequest(&rb);
return rb.wait();
} }
@ -244,3 +249,9 @@ void I2CRB::setWriteParams(uint8_t i2cAddress, const uint8_t *writeBuffer, uint8
this->status = I2C_STATUS_OK; this->status = I2C_STATUS_OK;
} }
void I2CRB::suppressRetries(bool suppress) {
if (suppress)
this->operation |= OPERATION_NORETRY;
else
this->operation &= ~OPERATION_NORETRY;
}

View File

@ -157,6 +157,8 @@ typedef enum : uint8_t
OPERATION_REQUEST = 2, OPERATION_REQUEST = 2,
OPERATION_SEND = 3, OPERATION_SEND = 3,
OPERATION_SEND_P = 4, OPERATION_SEND_P = 4,
OPERATION_NORETRY = 0x80, // OR with operation to suppress retries.
OPERATION_MASK = 0x7f, // mask for extracting the operation code
} OperationEnum; } OperationEnum;
@ -178,6 +180,7 @@ public:
void setReadParams(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t readLen); void setReadParams(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t readLen);
void setRequestParams(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t readLen, const uint8_t *writeBuffer, uint8_t writeLen); void setRequestParams(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t readLen, const uint8_t *writeBuffer, uint8_t writeLen);
void setWriteParams(uint8_t i2cAddress, const uint8_t *writeBuffer, uint8_t writeLen); void setWriteParams(uint8_t i2cAddress, const uint8_t *writeBuffer, uint8_t writeLen);
void suppressRetries(bool suppress);
uint8_t writeLen; uint8_t writeLen;
uint8_t readLen; uint8_t readLen;

View File

@ -105,7 +105,7 @@ void I2CManagerClass::startTransaction() {
currentRequest = queueHead; currentRequest = queueHead;
rxCount = txCount = 0; rxCount = txCount = 0;
// Copy key fields to static data for speed. // Copy key fields to static data for speed.
operation = currentRequest->operation; operation = currentRequest->operation & OPERATION_MASK;
// Start the I2C process going. // Start the I2C process going.
I2C_sendStart(); I2C_sendStart();
startTime = micros(); startTime = micros();
@ -227,8 +227,10 @@ void I2CManagerClass::handleInterrupt() {
// and state isn't active then state contains the completion status of the request. // and state isn't active then state contains the completion status of the request.
if (state != I2C_STATE_ACTIVE && currentRequest != NULL) { if (state != I2C_STATE_ACTIVE && currentRequest != NULL) {
// Operation has completed. // Operation has completed.
if (state == I2C_STATUS_OK || ++retryCounter > MAX_I2C_RETRIES) { if (state == I2C_STATUS_OK || ++retryCounter > MAX_I2C_RETRIES
// Status is OK, or has failed and retry count exceeded. || currentRequest->operation & OPERATION_NORETRY)
{
// Status is OK, or has failed and retry count exceeded, or retries disabled.
// Remove completed request from head of queue // Remove completed request from head of queue
I2CRB * t = queueHead; I2CRB * t = queueHead;
if (t == currentRequest) { if (t == currentRequest) {

View File

@ -51,11 +51,14 @@ void I2CManagerClass::_setClock(unsigned long i2cClockSpeed) {
uint8_t I2CManagerClass::write(uint8_t address, const uint8_t buffer[], uint8_t size, I2CRB *rb) { uint8_t I2CManagerClass::write(uint8_t address, const uint8_t buffer[], uint8_t size, I2CRB *rb) {
uint8_t status = I2C_STATUS_OK; uint8_t status = I2C_STATUS_OK;
uint8_t retryCount = 0; uint8_t retryCount = 0;
// If request fails, retry up to the defined limit, unless the NORETRY flag is set
// in the request block.
do { do {
Wire.beginTransmission(address); Wire.beginTransmission(address);
if (size > 0) Wire.write(buffer, size); if (size > 0) Wire.write(buffer, size);
status = Wire.endTransmission(); status = Wire.endTransmission();
} while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES)); } while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES
|| rb->operation & OPERATION_NORETRY));
rb->status = status; rb->status = status;
return I2C_STATUS_OK; return I2C_STATUS_OK;
} }
@ -81,6 +84,8 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea
uint8_t status = I2C_STATUS_OK; uint8_t status = I2C_STATUS_OK;
uint8_t nBytes = 0; uint8_t nBytes = 0;
uint8_t retryCount = 0; uint8_t retryCount = 0;
// If request fails, retry up to the defined limit, unless the NORETRY flag is set
// in the request block.
do { do {
if (writeSize > 0) { if (writeSize > 0) {
Wire.beginTransmission(address); Wire.beginTransmission(address);
@ -93,7 +98,8 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea
readBuffer[nBytes++] = Wire.read(); readBuffer[nBytes++] = Wire.read();
if (nBytes < readSize) status = I2C_STATUS_TRUNCATED; if (nBytes < readSize) status = I2C_STATUS_TRUNCATED;
} }
} while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES)); } while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES
|| rb->operation & OPERATION_NORETRY));
rb->nBytes = nBytes; rb->nBytes = nBytes;
rb->status = status; rb->status = status;
@ -109,7 +115,7 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea
* the non-blocking version. * the non-blocking version.
***************************************************************************/ ***************************************************************************/
void I2CManagerClass::queueRequest(I2CRB *req) { void I2CManagerClass::queueRequest(I2CRB *req) {
switch (req->operation) { switch (req->operation & OPERATION_MASK) {
case OPERATION_READ: case OPERATION_READ:
read(req->i2cAddress, req->readBuffer, req->readLen, NULL, 0, req); read(req->i2cAddress, req->readBuffer, req->readLen, NULL, 0, req);
break; break;