From 47cda832102068236f9d9d0fd22d16bc245ca99b Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 12 Feb 2023 10:36:26 +1000 Subject: [PATCH 1/2] Disabled servo animations --- IO_EXIOExpander.h | 93 +++++++++++++++++++++++++++++++---------------- version.h | 3 +- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index ad48a3a..289f282 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -72,10 +72,10 @@ private: _i2cAddress = i2cAddress; // To save RAM, space for servo configuration is not allocated unless a pin is used. // Initialise the pointers to NULL. - _servoData = (ServoData**) calloc(_nPins, sizeof(ServoData*)); - for (int i=0; i<_nPins; i++) { - _servoData[i] = NULL; - } + // _servoData = (ServoData**) calloc(_nPins, sizeof(ServoData*)); + // for (int i=0; i<_nPins; i++) { + // _servoData[i] = NULL; + // } addDevice(this); } @@ -166,14 +166,14 @@ private: I2CManager.read(_i2cAddress, _digitalInputStates, _digitalPinBytes, _command1Buffer, 1); _command1Buffer[0] = EXIORDAN; I2CManager.read(_i2cAddress, _analogueInputStates, _analoguePinBytes, _command1Buffer, 1); - if ((currentMicros - _lastRefresh) / 1000UL > refreshInterval) { - _lastRefresh = currentMicros; - for (int pin=0; pin<_nPins; pin++) { - if (_servoData[pin] != NULL) { - updatePosition(pin); - } - } - } + // if ((currentMicros - _lastRefresh) / 1000UL > refreshInterval) { + // _lastRefresh = currentMicros; + // for (int pin=0; pin<_nPins; pin++) { + // if (_servoData[pin] != NULL) { + // updatePosition(pin); + // } + // } + // } } // Obtain the correct analogue input value @@ -194,24 +194,24 @@ private: int _read(VPIN vpin) override { if (_deviceState == DEVSTATE_FAILED) return 0; int pin = vpin - _firstVpin; - if (_servoData[pin] == NULL) { + // if (_servoData[pin] == NULL) { uint8_t pinByte = pin / 8; bool value = bitRead(_digitalInputStates[pinByte], pin - pinByte * 8); return value; - } else { - struct ServoData *s = _servoData[pin]; - if (s == NULL) { - return false; // No structure means no animation! - } else { - return (s->stepNumber < s->numSteps); - } - } + // } else { + // struct ServoData *s = _servoData[pin]; + // if (s == NULL) { + // return false; // No structure means no animation! + // } else { + // return (s->stepNumber < s->numSteps); + // } + // } } void _write(VPIN vpin, int value) override { if (_deviceState == DEVSTATE_FAILED) return; int pin = vpin - _firstVpin; - if (_servoData[pin] == NULL) { + // if (_servoData[pin] == NULL) { _digitalOutBuffer[0] = EXIOWRD; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = value; @@ -219,19 +219,40 @@ private: if (_command1Buffer[0] != EXIORDY) { DIAG(F("Vpin %d cannot be used as a digital output pin"), (int)vpin); } - } else { - if (value) value = 1; - struct ServoData *s = _servoData[pin]; - if (s != NULL) { - // Use configured parameters - this->_writeAnalogue(vpin, value ? s->activePosition : s->inactivePosition, s->profile, s->duration); - } else { - /* simulate digital pin on PWM */ - this->_writeAnalogue(vpin, value ? 4095 : 0, Instant | NoPowerOff, 0); - } + // } else { + // if (value) value = 1; + // struct ServoData *s = _servoData[pin]; + // if (s != NULL) { + // // Use configured parameters + // this->_writeAnalogue(vpin, value ? s->activePosition : s->inactivePosition, s->profile, s->duration); + // } else { + // /* simulate digital pin on PWM */ + // this->_writeAnalogue(vpin, value ? 4095 : 0, Instant | NoPowerOff, 0); + // } + // } + } + + void _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) override { + if (_deviceState == DEVSTATE_FAILED) return; + int pin = vpin - _firstVpin; +#ifdef DIAG_IO + DIAG(F("Servo: WriteAnalogue Vpin:%d Value:%d Profile:%d Duration:%d %S"), + vpin, value, profile, duration, _deviceState == DEVSTATE_FAILED?F("DEVSTATE_FAILED"):F("")); +#endif + _servoBuffer[0] = EXIOWRAN; + _servoBuffer[1] = pin; + _servoBuffer[2] = value & 0xFF; + _servoBuffer[3] = value >> 8; + _servoBuffer[4] = profile; + _servoBuffer[5] = duration & 0xFF; + _servoBuffer[6] = duration >> 8; + I2CManager.read(_i2cAddress, _command1Buffer, 1, _servoBuffer, 7); + if (_command1Buffer[0] != EXIORDY) { + DIAG(F("Vpin %d cannot be used as a servo/PWM pin"), (int)vpin); } } +/* void _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) override { if (_deviceState == DEVSTATE_FAILED) return; int pin = vpin - _firstVpin; @@ -266,7 +287,9 @@ private: s->toPosition = value; s->fromPosition = s->currentPosition; } +*/ +/* void updatePosition(uint8_t pin) { struct ServoData *s = _servoData[pin]; if (s == NULL) return; // No pin configuration/state data @@ -299,7 +322,9 @@ private: s->numSteps = 0; // Done now. } } +*/ +/* void writePWM(int pin, uint16_t value) { _command4Buffer[0] = EXIOWRAN; _command4Buffer[1] = pin; @@ -307,6 +332,7 @@ private: _command4Buffer[3] = value >> 8; I2CManager.write(_i2cAddress, _command4Buffer, 4); } +*/ void _display() override { DIAG(F("EX-IOExpander I2C:x%x v%d.%d.%d Vpins %d-%d %S"), @@ -331,8 +357,10 @@ private: byte _command2Buffer[2]; byte _command4Buffer[4]; byte _receive3Buffer[3]; + byte _servoBuffer[7]; uint8_t* _analoguePinMap; +/* // Servo specific struct ServoData { uint16_t activePosition : 12; // Config parameter @@ -360,6 +388,7 @@ private: // i.e. the bounce is the same on the down action as on the up action. First entry isn't used. const byte FLASH _bounceProfile[30] = {0,2,3,7,13,33,50,83,100,83,75,70,65,60,60,65,74,84,100,83,75,70,70,72,75,80,87,92,97,100}; +*/ // EX-IOExpander protocol flags enum { diff --git a/version.h b/version.h index abfa9df..3a0fa9e 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,8 @@ #include "StringFormatter.h" -#define VERSION "4.2.15" +#define VERSION "4.2.16" +// 4.2.16 Move EX-IOExpander servo support to the EX-IOExpander software // 4.2.15 Add basic experimental PWM support to EX-IOExpander // EX-IOExpander 0.0.14 minimum required // 4.2.14 STM32F4xx fast ADC read implementation From 9c95eb69054718e04b34ba38facd6a4e560dc8a0 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 12 Feb 2023 19:06:46 +1000 Subject: [PATCH 2/2] Servo animation moved to EX-IO --- IO_EXIOExpander.h | 167 +++------------------------------------------- 1 file changed, 10 insertions(+), 157 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 289f282..a782942 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -70,12 +70,6 @@ private: _firstVpin = firstVpin; _nPins = nPins; _i2cAddress = i2cAddress; - // To save RAM, space for servo configuration is not allocated unless a pin is used. - // Initialise the pointers to NULL. - // _servoData = (ServoData**) calloc(_nPins, sizeof(ServoData*)); - // for (int i=0; i<_nPins; i++) { - // _servoData[i] = NULL; - // } addDevice(this); } @@ -166,14 +160,6 @@ private: I2CManager.read(_i2cAddress, _digitalInputStates, _digitalPinBytes, _command1Buffer, 1); _command1Buffer[0] = EXIORDAN; I2CManager.read(_i2cAddress, _analogueInputStates, _analoguePinBytes, _command1Buffer, 1); - // if ((currentMicros - _lastRefresh) / 1000UL > refreshInterval) { - // _lastRefresh = currentMicros; - // for (int pin=0; pin<_nPins; pin++) { - // if (_servoData[pin] != NULL) { - // updatePosition(pin); - // } - // } - // } } // Obtain the correct analogue input value @@ -194,42 +180,21 @@ private: int _read(VPIN vpin) override { if (_deviceState == DEVSTATE_FAILED) return 0; int pin = vpin - _firstVpin; - // if (_servoData[pin] == NULL) { - uint8_t pinByte = pin / 8; - bool value = bitRead(_digitalInputStates[pinByte], pin - pinByte * 8); - return value; - // } else { - // struct ServoData *s = _servoData[pin]; - // if (s == NULL) { - // return false; // No structure means no animation! - // } else { - // return (s->stepNumber < s->numSteps); - // } - // } + uint8_t pinByte = pin / 8; + bool value = bitRead(_digitalInputStates[pinByte], pin - pinByte * 8); + return value; } void _write(VPIN vpin, int value) override { if (_deviceState == DEVSTATE_FAILED) return; int pin = vpin - _firstVpin; - // if (_servoData[pin] == NULL) { - _digitalOutBuffer[0] = EXIOWRD; - _digitalOutBuffer[1] = pin; - _digitalOutBuffer[2] = value; - I2CManager.read(_i2cAddress, _command1Buffer, 1, _digitalOutBuffer, 3); - if (_command1Buffer[0] != EXIORDY) { - DIAG(F("Vpin %d cannot be used as a digital output pin"), (int)vpin); - } - // } else { - // if (value) value = 1; - // struct ServoData *s = _servoData[pin]; - // if (s != NULL) { - // // Use configured parameters - // this->_writeAnalogue(vpin, value ? s->activePosition : s->inactivePosition, s->profile, s->duration); - // } else { - // /* simulate digital pin on PWM */ - // this->_writeAnalogue(vpin, value ? 4095 : 0, Instant | NoPowerOff, 0); - // } - // } + _digitalOutBuffer[0] = EXIOWRD; + _digitalOutBuffer[1] = pin; + _digitalOutBuffer[2] = value; + I2CManager.read(_i2cAddress, _command1Buffer, 1, _digitalOutBuffer, 3); + if (_command1Buffer[0] != EXIORDY) { + DIAG(F("Vpin %d cannot be used as a digital output pin"), (int)vpin); + } } void _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) override { @@ -252,88 +217,6 @@ private: } } -/* - void _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) override { - if (_deviceState == DEVSTATE_FAILED) return; - int pin = vpin - _firstVpin; -#ifdef DIAG_IO - DIAG(F("Servo: WriteAnalogue Vpin:%d Value:%d Profile:%d Duration:%d %S"), - vpin, value, profile, duration, _deviceState == DEVSTATE_FAILED?F("DEVSTATE_FAILED"):F("")); -#endif - if (_deviceState == DEVSTATE_FAILED) return; - if (value > 4095) value = 4095; - else if (value < 0) value = 0; - - struct ServoData *s = _servoData[pin]; - if (s == NULL) { - // Servo pin not configured, so configure now using defaults - s = _servoData[pin] = (struct ServoData *) calloc(sizeof(struct ServoData), 1); - if (s == NULL) return; // Check for memory allocation failure - s->activePosition = 4095; - s->inactivePosition = 0; - s->currentPosition = value; - s->profile = Instant | NoPowerOff; // Use instant profile (but not this time) - } - - // Animated profile. Initiate the appropriate action. - s->currentProfile = profile; - uint8_t profileValue = profile & ~NoPowerOff; // Mask off 'don't-power-off' bit. - s->numSteps = profileValue==Fast ? 10 : // 0.5 seconds - profileValue==Medium ? 20 : // 1.0 seconds - profileValue==Slow ? 40 : // 2.0 seconds - profileValue==Bounce ? sizeof(_bounceProfile)-1 : // ~ 1.5 seconds - duration * 2 + 1; // Convert from deciseconds (100ms) to refresh cycles (50ms) - s->stepNumber = 0; - s->toPosition = value; - s->fromPosition = s->currentPosition; - } -*/ - -/* - void updatePosition(uint8_t pin) { - struct ServoData *s = _servoData[pin]; - if (s == NULL) return; // No pin configuration/state data - - if (s->numSteps == 0) return; // No animation in progress - - if (s->stepNumber == 0 && s->fromPosition == s->toPosition) { - // Go straight to end of sequence, output final position. - s->stepNumber = s->numSteps-1; - } - - if (s->stepNumber < s->numSteps) { - // Animation in progress, reposition servo - s->stepNumber++; - if ((s->currentProfile & ~NoPowerOff) == Bounce) { - // Retrieve step positions from array in flash - uint8_t profileValue = GETFLASH(&_bounceProfile[s->stepNumber]); - s->currentPosition = map(profileValue, 0, 100, s->fromPosition, s->toPosition); - } else { - // All other profiles - calculate step by linear interpolation between from and to positions. - s->currentPosition = map(s->stepNumber, 0, s->numSteps, s->fromPosition, s->toPosition); - } - // Send servo command - this->writePWM(pin, s->currentPosition); - } else if (s->stepNumber < s->numSteps + _catchupSteps) { - // We've finished animation, wait a little to allow servo to catch up - s->stepNumber++; - } else if (s->stepNumber == s->numSteps + _catchupSteps - && s->currentPosition != 0) { - s->numSteps = 0; // Done now. - } - } -*/ - -/* - void writePWM(int pin, uint16_t value) { - _command4Buffer[0] = EXIOWRAN; - _command4Buffer[1] = pin; - _command4Buffer[2] = value & 0xFF; - _command4Buffer[3] = value >> 8; - I2CManager.write(_i2cAddress, _command4Buffer, 4); - } -*/ - void _display() override { DIAG(F("EX-IOExpander I2C:x%x v%d.%d.%d Vpins %d-%d %S"), _i2cAddress, _majorVer, _minorVer, _patchVer, @@ -360,36 +243,6 @@ private: byte _servoBuffer[7]; uint8_t* _analoguePinMap; -/* - // Servo specific - struct ServoData { - uint16_t activePosition : 12; // Config parameter - uint16_t inactivePosition : 12; // Config parameter - uint16_t currentPosition : 12; - uint16_t fromPosition : 12; - uint16_t toPosition : 12; - uint8_t profile; // Config parameter - uint16_t stepNumber; // Index of current step (starting from 0) - uint16_t numSteps; // Number of steps in animation, or 0 if none in progress. - uint8_t currentProfile; // profile being used for current animation. - uint16_t duration; // time (tenths of a second) for animation to complete. - }; // 14 bytes per element, i.e. per pin in use - - ServoData** _servoData; - - static const uint8_t _catchupSteps = 5; // number of steps to wait before switching servo off - - const unsigned int refreshInterval = 50; // refresh every 50ms - unsigned long _lastRefresh = 0; - - // Profile for a bouncing signal or turnout - // The profile below is in the range 0-100% and should be combined with the desired limits - // of the servo set by _activePosition and _inactivePosition. The profile is symmetrical here, - // i.e. the bounce is the same on the down action as on the up action. First entry isn't used. - const byte FLASH _bounceProfile[30] = - {0,2,3,7,13,33,50,83,100,83,75,70,65,60,60,65,74,84,100,83,75,70,70,72,75,80,87,92,97,100}; -*/ - // EX-IOExpander protocol flags enum { EXIOINIT = 0xE0, // Flag to initialise setup procedure