1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-25 09:06:13 +01:00

Compare commits

..

No commits in common. "995c6f8ede39284d1a78ebf2b6e965a486c0672a" and "988011475c84e7f02a7adb2a17a637cc8075a4b0" have entirely different histories.

2 changed files with 28 additions and 92 deletions

View File

@ -1,5 +1,4 @@
/* /*
* © 2023, Peter Cole. All rights reserved.
* © 2022, Peter Cole. All rights reserved. * © 2022, Peter Cole. All rights reserved.
* *
* This file is part of EX-CommandStation * This file is part of EX-CommandStation
@ -29,23 +28,9 @@
* ONCHANGE(vpin) - flag when the rotary encoder position has changed from the previous position * ONCHANGE(vpin) - flag when the rotary encoder position has changed from the previous position
* IFRE(vpin, position) - test to see if specified rotary encoder position has been received * IFRE(vpin, position) - test to see if specified rotary encoder position has been received
* *
* Feedback can also be sent to the rotary encoder by using 2 Vpins, and sending a SET()/RESET() to the second Vpin. * Further to this, feedback can be sent to the rotary encoder by using 2 Vpins, and sending a SET()/RESET() to the second Vpin.
* A SET(vpin) will flag that a turntable (or anything else) is in motion, and a RESET(vpin) that the motion has finished. * A SET(vpin) will flag that a turntable (or anything else) is in motion, and a RESET(vpin) that the motion has finished.
* *
* In addition, defining a third Vpin will allow a position number to be sent so that when an EXRAIL automation or some other
* activity has moved a turntable, the position can be reflected in the rotary encoder software. This can be accomplished
* using the EXRAIL SERVO(vpin, position, profile) command, where:
* - vpin = the third defined Vpin (any other is ignored)
* - position = the defined position in the DCC-EX Rotary Encoder software, 0 (Home) to 255
* - profile = Must be defined as per the SERVO() command, but is ignored as it has no relevance
*
* Defining in myAutomation.h requires the device driver to be included in addition to the HAL() statement. Examples:
*
* #include "IO_RotaryEncoder.h"
* HAL(RotaryEncoder, 700, 1, 0x70) // Define single Vpin, no feedback or position sent to rotary encoder software
* HAL(RotaryEncoder, 700, 2, 0x70) // Define two Vpins, feedback only sent to rotary encoder software
* HAL(RotaryEncoder, 700, 3, 0x70) // Define three Vpins, can send feedback and position update to rotary encoder software
*
* Refer to the documentation for further information including the valid activities and examples. * Refer to the documentation for further information including the valid activities and examples.
*/ */
@ -59,79 +44,50 @@
class RotaryEncoder : public IODevice { class RotaryEncoder : public IODevice {
public: public:
// Constructor
RotaryEncoder(VPIN firstVpin, int nPins, I2CAddress i2cAddress){
_firstVpin = firstVpin;
_nPins = nPins;
_I2CAddress = i2cAddress;
addDevice(this);
}
static void create(VPIN firstVpin, int nPins, I2CAddress i2cAddress) { static void create(VPIN firstVpin, int nPins, I2CAddress i2cAddress) {
if (checkNoOverlap(firstVpin, nPins, i2cAddress)) new RotaryEncoder(firstVpin, nPins, i2cAddress); if (checkNoOverlap(firstVpin, nPins, i2cAddress)) new RotaryEncoder(firstVpin, nPins, i2cAddress);
} }
private: private:
// Constructor
RotaryEncoder(VPIN firstVpin, int nPins, I2CAddress i2cAddress){
_firstVpin = firstVpin;
_nPins = nPins;
if (_nPins > 3) {
_nPins = 3;
DIAG(F("RotaryEncoder WARNING:%d vpins defined, only 3 supported"), _nPins);
}
_I2CAddress = i2cAddress;
addDevice(this);
}
// Initiate the device // Initiate the device
void _begin() { void _begin() {
uint8_t _status;
// Attempt to initilalise device
I2CManager.begin(); I2CManager.begin();
if (I2CManager.exists(_I2CAddress)) { if (I2CManager.exists(_I2CAddress)) {
// Send RE_RDY, must receive RE_RDY to be online byte _getVersion[1] = {RE_VER};
_sendBuffer[0] = RE_RDY; I2CManager.read(_I2CAddress, _versionBuffer, 3, _getVersion, 1);
_status = I2CManager.read(_I2CAddress, _rcvBuffer, 1, _sendBuffer, 1); _majorVer = _versionBuffer[0];
if (_status == I2C_STATUS_OK) { _minorVer = _versionBuffer[1];
if (_rcvBuffer[0] == RE_RDY) { _patchVer = _versionBuffer[2];
_sendBuffer[0] = RE_VER; _buffer[0] = RE_OP;
if (I2CManager.read(_I2CAddress, _versionBuffer, 3, _sendBuffer, 1) == I2C_STATUS_OK) { I2CManager.write(_I2CAddress, _buffer, 1);
_majorVer = _versionBuffer[0];
_minorVer = _versionBuffer[1];
_patchVer = _versionBuffer[2];
}
} else {
DIAG(F("RotaryEncoder I2C:%s garbage received: %d"), _I2CAddress.toString(), _rcvBuffer[0]);
_deviceState = DEVSTATE_FAILED;
return;
}
} else {
DIAG(F("RotaryEncoder I2C:%s ERROR connecting"), _I2CAddress.toString());
_deviceState = DEVSTATE_FAILED;
return;
}
#ifdef DIAG_IO #ifdef DIAG_IO
_display(); _display();
#endif #endif
} else { } else {
DIAG(F("RotaryEncoder I2C:%s device not found"), _I2CAddress.toString()); _deviceState = DEVSTATE_FAILED;
_deviceState = DEVSTATE_FAILED;
} }
} }
void _loop(unsigned long currentMicros) override { void _loop(unsigned long currentMicros) override {
if (_deviceState == DEVSTATE_FAILED) return; // Return if device has failed I2CManager.read(_I2CAddress, _buffer, 1);
if (_i2crb.isBusy()) return; // Return if I2C operation still in progress _position = _buffer[0];
// This here needs to have a change check, ie. position is a different value.
if (currentMicros - _lastPositionRead > _positionRefresh) { #if defined(EXRAIL_ACTIVE)
_lastPositionRead = currentMicros;
_sendBuffer[0] = RE_READ;
I2CManager.read(_I2CAddress, _rcvBuffer, 1, _sendBuffer, 1, &_i2crb); // Read position from encoder
_position = _rcvBuffer[0];
// If EXRAIL is active, we need to trigger the ONCHANGE() event handler if it's in use
#if defined(EXRAIL_ACTIVE)
if (_position != _previousPosition) { if (_position != _previousPosition) {
_previousPosition = _position; _previousPosition = _position;
RMFT2::changeEvent(_firstVpin, 1); RMFT2::changeEvent(_firstVpin,1);
} else { } else {
RMFT2::changeEvent(_firstVpin, 0); RMFT2::changeEvent(_firstVpin,0);
} }
#endif #endif
} delayUntil(currentMicros + 100000);
} }
// Device specific read function // Device specific read function
@ -147,16 +103,6 @@ private:
I2CManager.write(_I2CAddress, _feedbackBuffer, 2); I2CManager.write(_I2CAddress, _feedbackBuffer, 2);
} }
} }
void _writeAnalogue(VPIN vpin, int position, uint8_t profile, uint16_t duration) override {
if (vpin == _firstVpin + 2) {
if (position >= 0 && position <= 255) {
byte newPosition = position & 0xFF;
byte _positionBuffer[2] = {RE_MOVE, newPosition};
I2CManager.write(_I2CAddress, _positionBuffer, 2);
}
}
}
void _display() override { void _display() override {
DIAG(F("Rotary Encoder I2C:%s v%d.%d.%d Configured on VPIN:%u-%d %S"), _I2CAddress.toString(), _majorVer, _minorVer, _patchVer, DIAG(F("Rotary Encoder I2C:%s v%d.%d.%d Configured on VPIN:%u-%d %S"), _I2CAddress.toString(), _majorVer, _minorVer, _patchVer,
@ -166,21 +112,14 @@ private:
int8_t _position; int8_t _position;
int8_t _previousPosition = 0; int8_t _previousPosition = 0;
uint8_t _versionBuffer[3]; uint8_t _versionBuffer[3];
uint8_t _sendBuffer[1]; uint8_t _buffer[1];
uint8_t _rcvBuffer[1];
uint8_t _majorVer = 0; uint8_t _majorVer = 0;
uint8_t _minorVer = 0; uint8_t _minorVer = 0;
uint8_t _patchVer = 0; uint8_t _patchVer = 0;
I2CRB _i2crb;
unsigned long _lastPositionRead = 0;
const unsigned long _positionRefresh = 100000UL; // Delay refreshing position for 100ms
enum { enum {
RE_RDY = 0xA0, // Flag to check if encoder is ready for operation RE_VER = 0xA0, // Flag to retrieve rotary encoder version from the device
RE_VER = 0xA1, // Flag to retrieve rotary encoder software version RE_OP = 0xA1, // Flag for normal operation
RE_READ = 0xA2, // Flag to read the current position of the encoder
RE_OP = 0xA3, // Flag for operation start/end, sent to when sending feedback on move start/end
RE_MOVE = 0xA4, // Flag for sending a position update from the device driver to the encoder
}; };
}; };

View File

@ -4,10 +4,7 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "4.2.56" #define VERSION "4.2.55"
// 4.2.56 - Update IO_RotaryEncoder.h:
// - Improved I2C communication, non-blocking reads
// - Enable sending positions to the encoder from EXRAIL via SERVO()
// 4.2.55 - Optimize analog read for AVR // 4.2.55 - Optimize analog read for AVR
// 4.2.54 - EX8874 shield in config.example.h // 4.2.54 - EX8874 shield in config.example.h
// - Fix: Better warnings for pin number errors // - Fix: Better warnings for pin number errors