diff --git a/.gitignore b/.gitignore index 8f01818..6237359 100644 --- a/.gitignore +++ b/.gitignore @@ -7,16 +7,9 @@ Release/* .pio/ .vscode/ config.h -.vscode/* -# mySetup.h mySetup.cpp myHal.cpp -# myAutomation.h myFilter.cpp -# myAutomation.h -# myLayout.h my*.h !my*.example.h -.vscode/extensions.json -.vscode/extensions.json compile_commands.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 080e70d..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ], - "unwantedRecommendations": [ - "ms-vscode.cpptools-extension-pack" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ffa498a..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "files.associations": { - "array": "cpp", - "deque": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "string_view": "cpp", - "initializer_list": "cpp", - "cstdint": "cpp" - } -} diff --git a/Display.cpp b/Display.cpp index 2c44778..a1a1ec1 100644 --- a/Display.cpp +++ b/Display.cpp @@ -1,5 +1,6 @@ /* * © 2021, Chris Harlow, Neil McKechnie. All rights reserved. + * © 2023, Harald Barth. * * This file is part of CommandStation-EX * @@ -52,7 +53,7 @@ Display::Display(DisplayDevice *deviceDriver) { _deviceDriver = deviceDriver; // Get device dimensions in characters (e.g. 16x2). numCharacterColumns = _deviceDriver->getNumCols(); - numCharacterRows = _deviceDriver->getNumRows();; + numCharacterRows = _deviceDriver->getNumRows(); for (uint8_t row = 0; row < MAX_CHARACTER_ROWS; row++) rowBuffer[row][0] = '\0'; topRow = ROW_INITIAL; // loop2 will fill from row 0 @@ -173,16 +174,18 @@ bool Display::findNextNonBlankRow() { rowNext = 0; else rowNext = rowNext + 1; - if (rowNext >= MAX_CHARACTER_ROWS) rowNext = ROW_INITIAL; #if SCROLLMODE == 1 - // Finished if we've looped back to start - if (rowNext == ROW_INITIAL) { + if (rowNext >= MAX_CHARACTER_ROWS) { + // Finished if we've looped back to start + rowNext = ROW_INITIAL; noMoreRowsToDisplay = true; return false; } #else - // Finished if we're back to the first one shown + if (rowNext >= MAX_CHARACTER_ROWS) + rowNext = 0; if (rowNext == rowFirst) { + // Finished if we're back to the first one shown noMoreRowsToDisplay = true; return false; } @@ -193,4 +196,4 @@ bool Display::findNextNonBlankRow() { } } return false; -} \ No newline at end of file +} diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 3bd8da7..8541cd2 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -105,12 +105,9 @@ uint16_t RMFT2::getOperand(byte n) { // getOperand static version, must be provided prog counter from loop etc. uint16_t RMFT2::getOperand(int progCounter,byte n) { int offset=progCounter+1+(n*3); - if (offset&1) { - byte lsb=GETHIGHFLASH(RouteCode,offset); - byte msb=GETHIGHFLASH(RouteCode,offset+1); - return msb<<8|lsb; - } - return GETHIGHFLASHW(RouteCode,offset); + byte lsb=GETHIGHFLASH(RouteCode,offset); + byte msb=GETHIGHFLASH(RouteCode,offset+1); + return msb<<8|lsb; } LookList::LookList(int16_t size) { diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index db56eac..be808f8 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202303101548Z" +#define GITHUB_SHA "devel-202303141949Z" diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 0296c93..84433b7 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -154,12 +154,30 @@ private: // Main loop, collect both digital and analogue pin states continuously (faster sensor/input reads) void _loop(unsigned long currentMicros) override { - (void)currentMicros; // remove warning - if (_deviceState == DEVSTATE_FAILED) return; - _command1Buffer[0] = EXIORDD; - I2CManager.read(_i2cAddress, _digitalInputStates, _digitalPinBytes, _command1Buffer, 1, &_i2crb); - _command1Buffer[0] = EXIORDAN; - I2CManager.read(_i2cAddress, _analogueInputStates, _analoguePinBytes, _command1Buffer, 1, &_i2crb); + if (_deviceState == DEVSTATE_FAILED) return; // If device failed, return + uint8_t status = _i2crb.status; + if (status == I2C_STATUS_PENDING) return; // If device busy, return + if (status == I2C_STATUS_OK) { // If device ok, read input data + if (_commandFlag) { + if (currentMicros - _lastDigitalRead > _digitalRefresh) { // Delay for digital read refresh + _lastDigitalRead = currentMicros; + _command1Buffer[0] = EXIORDD; + I2CManager.read(_i2cAddress, _digitalInputStates, _digitalPinBytes, _command1Buffer, 1, &_i2crb); + } + } else { + if (currentMicros - _lastAnalogueRead > _analogueRefresh) { // Delay for analogue read refresh + _lastAnalogueRead = currentMicros; + _command1Buffer[0] = EXIORDAN; + byte _tempAnalogue[_analoguePinBytes]; // Setup temp buffer so reads come from known state + I2CManager.read(_i2cAddress, _tempAnalogue, _analoguePinBytes, _command1Buffer, 1, &_i2crb); + memcpy(_analogueInputStates, _tempAnalogue, _analoguePinBytes); // Copy temp buffer to states + } + } + _commandFlag = !_commandFlag; + } else { + DIAG(F("EX-IOExpander I2C:%s Error:%d %S"), _I2CAddress.toString(), status, I2CManager.getErrorMessage(status)); + _deviceState = DEVSTATE_FAILED; + } } // Obtain the correct analogue input value @@ -191,9 +209,14 @@ private: _digitalOutBuffer[0] = EXIOWRD; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = value; - I2CManager.read(_i2cAddress, _command1Buffer, 1, _digitalOutBuffer, 3, &_i2crb); - if (_command1Buffer[0] != EXIORDY) { - DIAG(F("Vpin %d cannot be used as a digital output pin"), (int)vpin); + uint8_t status = I2CManager.read(_i2cAddress, _command1Buffer, 1, _digitalOutBuffer, 3); + if (status != I2C_STATUS_OK) { + DIAG(F("EX-IOExpander I2C:%s Error:%d %S"), _I2CAddress.toString(), status, I2CManager.getErrorMessage(status)); + _deviceState = DEVSTATE_FAILED; + } else { + if (_command1Buffer[0] != EXIORDY) { + DIAG(F("Vpin %d cannot be used as a digital output pin"), (int)vpin); + } } } @@ -211,9 +234,14 @@ private: _servoBuffer[4] = profile; _servoBuffer[5] = duration & 0xFF; _servoBuffer[6] = duration >> 8; - I2CManager.read(_i2cAddress, _command1Buffer, 1, _servoBuffer, 7, &_i2crb); - if (_command1Buffer[0] != EXIORDY) { - DIAG(F("Vpin %d cannot be used as a servo/PWM pin"), (int)vpin); + uint8_t status = I2CManager.read(_i2cAddress, _command1Buffer, 1, _servoBuffer, 7); + if (status != I2C_STATUS_OK) { + DIAG(F("EX-IOExpander I2C:%s Error:%d %S"), _I2CAddress.toString(), status, I2CManager.getErrorMessage(status)); + _deviceState = DEVSTATE_FAILED; + } else { + if (_command1Buffer[0] != EXIORDY) { + DIAG(F("Vpin %d cannot be used as a servo/PWM pin"), (int)vpin); + } } } @@ -243,6 +271,11 @@ private: byte _servoBuffer[7]; uint8_t* _analoguePinMap; I2CRB _i2crb; + bool _commandFlag = 1; + unsigned long _lastDigitalRead = 0; + unsigned long _lastAnalogueRead = 0; + const unsigned long _digitalRefresh = 10000UL; // Delay refreshing digital inputs for 10ms + const unsigned long _analogueRefresh = 50000UL; // Delay refreshing analogue inputs for 50ms // EX-IOExpander protocol flags enum { diff --git a/Release_Notes/CommandRef.md b/Release_Notes/CommandRef.md index 6420471..c06e388 100644 --- a/Release_Notes/CommandRef.md +++ b/Release_Notes/CommandRef.md @@ -4,24 +4,37 @@ General points: - Commands below have a single character opcode and parameters. Even is actually read as - Keyword parameters are shown in upper case but may be entered in mixed case. - - value parameters are numeric. + - value parameters are decimal numeric (unless otherwise noted) - [something] indicates its optional. - - Not all commands have a response, and not all responses come from the last commands that you have issued. + - Not all commands have a response, and broadcasts mean that not all responses come from the last commands that you have issued. Startup status - + Return status like + + also returns defined turnout list: + 1=thrown -Track power management -<1> -<1 MAIN|PROG|JOIN> -<0> -<0 MAIN|PROG> +Track power management. After power commands a power state is broadcast to all throttles. + +<1> Power on all +<1 MAIN|PROG|JOIN> Power on MAIN or PROG track +<1 JOIN> Power on MAIN and PROG track but send main track data on both. +<0> Power off all tracks +<0 MAIN|PROG> Power off main or prog track + +Basic manual loco control + Throttle loco. + speed in JMRI-form (-1=ESTOP, 0=STOP, 1..126 = DCC speeds 2..127) + direction 1=forward, 0=reverse + For response see broadcast + + Set loco function 1=ON, 0-OFF + For response see broadcast + + emergency stop all locos + Control turnout id, 0=C=Closed, 1=T=Thrown + response broadcast -Basic manual control - - - - DCC accessory control @@ -35,25 +48,30 @@ Note: Turnouts are best defined in myAutomation.h where a turnout description ca + Valid commands respond with + +Outputs (Used by JMRI, not required by EXRAIL) + Define an output pin that JMRI can set by id + Activate an output pin by id -Outputs - - +Sensors (Used by JMRI, not required by EXRAIL) + define a sensor to be monitored. + Responses and as sensor changes -Sensors - +Decoder programming - main track + POM write value to cv on loco + POM write bit to cv on loco -Decoder programming - - - - - - - - - +Decoder Programming - prog track + Clear consist and write new cab id (includes long/short settings) + Responds or for error + Write value to cv + + Read cv value, much faster if prediction is correct. + Read CV bit + + Read drive-away loco id. (May be a consist id) @@ -152,6 +170,8 @@ Obsolete commands/formats + V command is much faster if prediction is correct. + V command is much faster if prediction is correct. Broadcast responses Note: broadcasts are sent to all throttles when appropriate (usually because something has changed) diff --git a/version.h b/version.h index 6e2d0ba..b8f547f 100644 --- a/version.h +++ b/version.h @@ -4,8 +4,14 @@ #include "StringFormatter.h" -#define VERSION "4.2.24" -// 4.3.24 - Bugfix Ethernet shield: Static IP now possible +#define VERSION "4.2.27" +// 4.2.27 - Bugfix LCD showed random characters in SCROLLMODE 2 +// 4.2.26 - EX-IOExpander device driver enhancements +// - Enhance I2C error checking +// - Introduce delays to _loop to allow room for other I2C device comms +// - Improve analogue read reliability +// 4.2.25 - Bugfix SAMD21 Exrail odd byte boundary +// 4.2.24 - Bugfix Ethernet shield: Static IP now possible // 4.2.23 - Bugfix signalpin2 was not set up in shadow port // 4.2.22 - Implement broadcast of Track Manager changes // 4.2.21 - Implement non-blocking I2C for EX-IOExpander device driver