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

Compare commits

...

14 Commits

Author SHA1 Message Date
FranziHH
e236c150f2
Merge 3da4cb0961 into 3b162996ad 2024-02-01 05:58:50 +01:00
peteGSX
3b162996ad EX-IO fixes in version 2024-01-21 07:13:53 +10:00
Harald Barth
fb414a7a50 Bugfix: allocate enough bytes for digital pins. Add more sanity checks when allocating memory 2024-01-20 21:45:09 +01:00
Harald Barth
818e05b425 version 5.0.8 2024-01-10 08:37:54 +01:00
Harald Barth
c5168f030f Do not crash on turnouts without description 2024-01-10 08:25:34 +01:00
FranziHH
3da4cb0961 update read.me 2023-10-23 19:21:03 +02:00
FranziHH
0bfc228d3c
Merge branch 'DCC-EX:master' into FranziHH_FastClock 2023-10-14 15:14:28 +02:00
FranziHH
9b17aaf53e
Merge branch 'DCC-EX:master' into FranziHH_FastClock 2023-10-02 13:07:29 +02:00
FranziHH
579931a885
Merge branch 'DCC-EX:master' into FranziHH_FastClock 2023-09-17 19:58:58 +02:00
FranziHH
7b5e2b41da new config options
For Display

Shows IP and Port in same Line: PRINT_IP_PORT_SINGLE_LINE

Shows FastClock readable: FASTCLOCK_READABLE
2023-09-03 16:09:26 +02:00
FranziHH
4bdc4b7079 Update IODevice.cpp
Debug Output adjusted
2023-09-01 13:56:02 +02:00
FranziHH
5fde819fa2
Merge branch 'DCC-EX:master' into master_FranziHH 2023-08-31 10:13:31 +02:00
FranziHH
b8d1c682ea FastClock is working for Me
Fast Clock can be easily activated without complicated adjustments in config.h:

Serial:
simply comment out the required port: e.g. #define SERIAL1_COMMANDS

OR

for I2C
//#define FAST_CLOCK_I2C 0x55
and define the address
2023-08-31 10:08:23 +02:00
FranziHH
fb8cca8d35 FastClock BUG
serial is working
I2C is wrong
First, the initialization was incorrect. The FastClock was initialized before the I2C Manager was initialized
Second: FastClock Functions are missing
2023-08-30 21:02:37 +02:00
11 changed files with 126 additions and 47 deletions

View File

@ -181,7 +181,20 @@ void CommandDistributor::setClockTime(int16_t clocktime, int8_t clockrate, byte
case 1: case 1:
if (clocktime != lastclocktime){ if (clocktime != lastclocktime){
// CAH. DIAG removed because LCD does it anyway. // CAH. DIAG removed because LCD does it anyway.
LCD(6,F("Clk Time:%d Sp %d"), clocktime, clockrate);
#ifndef FASTCLOCK_READABLE
LCD(6,F("Clk Time: %d Sp %d"), clocktime, clockrate);
#else
// Make Time readable
int hours = clocktime / 60;
int minutes = clocktime - (hours * 60);
int hoursH = hours / 10;
int hoursL = hours - (hoursH * 10);
int minutesH = minutes / 10;
int minutesL = minutes - (minutesH * 10);
LCD(6,F("Clk Time: %d%d:%d%d Sp %d"), hoursH, hoursL, minutesH, minutesL, clockrate);
#endif
// look for an event for this time // look for an event for this time
RMFT2::clockEvent(clocktime,1); RMFT2::clockEvent(clocktime,1);
// Now tell everyone else what the time is. // Now tell everyone else what the time is.

View File

@ -260,7 +260,8 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
void RMFT2::setTurnoutHiddenState(Turnout * t) { void RMFT2::setTurnoutHiddenState(Turnout * t) {
// turnout descriptions are in low flash F strings // turnout descriptions are in low flash F strings
t->setHidden(GETFLASH(getTurnoutDescription(t->getId()))==0x01); const FSH *desc = getTurnoutDescription(t->getId());
if (desc) t->setHidden(GETFLASH(desc)==0x01);
} }
char RMFT2::getRouteType(int16_t id) { char RMFT2::getRouteType(int16_t id) {

View File

@ -48,6 +48,10 @@
static const FSH * guessI2CDeviceType(uint8_t address) { static const FSH * guessI2CDeviceType(uint8_t address) {
if (address >= 0x20 && address <= 0x26) if (address >= 0x20 && address <= 0x26)
return F("GPIO Expander"); return F("GPIO Expander");
#ifdef FAST_CLOCK_I2C
else if (address == FAST_CLOCK_I2C)
return F("Fast Clock");
#endif
else if (address == 0x27) else if (address == 0x27)
return F("GPIO Expander or LCD Display"); return F("GPIO Expander or LCD Display");
else if (address == 0x29) else if (address == 0x29)

View File

@ -27,6 +27,12 @@
#include "IO_MCP23017.h" #include "IO_MCP23017.h"
#include "DCCTimer.h" #include "DCCTimer.h"
#if !defined(IO_NO_HAL)
#ifdef FAST_CLOCK_I2C
#include "IO_EXFastClock.h" // FastClock driver
#endif
#endif
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
#define USE_FAST_IO #define USE_FAST_IO
#endif #endif
@ -76,6 +82,11 @@ void IODevice::begin() {
DIAG(F("Default PCA9685 at I2C 0x41 disabled due to configured user device")); DIAG(F("Default PCA9685 at I2C 0x41 disabled due to configured user device"));
} }
#ifdef FAST_CLOCK_I2C
DIAG(F("EXFastClock::create"));
EXFastClock::create(FAST_CLOCK_I2C);
#endif
// Predefine two MCP23017 module 0x20/0x21 if no conflicts // Predefine two MCP23017 module 0x20/0x21 if no conflicts
// Allocates 32 pins 164-195 // Allocates 32 pins 164-195
if (checkNoOverlap(164, 16, 0x20)) { if (checkNoOverlap(164, 16, 0x20)) {
@ -582,4 +593,3 @@ bool ArduinoPins::fastReadDigital(uint8_t pin) {
#endif #endif
return result; return result;
} }

View File

@ -56,12 +56,12 @@ static void create(I2CAddress i2cAddress) {
// XXXX change thistosave2 bytes // XXXX change thistosave2 bytes
if (_checkforclock == 0) { if (_checkforclock == 0) {
FAST_CLOCK_EXISTS = true; FAST_CLOCK_EXISTS = true;
//DIAG(F("I2C Fast Clock found at %s"), i2cAddress.toString()); DIAG(F("I2C Fast Clock found at %s"), i2cAddress.toString());
new EXFastClock(i2cAddress); new EXFastClock(i2cAddress);
} }
else { else {
FAST_CLOCK_EXISTS = false; FAST_CLOCK_EXISTS = false;
//DIAG(F("No Fast Clock found")); DIAG(F("No Fast Clock found"));
LCD(6,F("CLOCK NOT FOUND")); LCD(6,F("CLOCK NOT FOUND"));
} }
@ -95,7 +95,8 @@ void _loop(unsigned long currentMicros) override{
if (FAST_CLOCK_EXISTS==true) { if (FAST_CLOCK_EXISTS==true) {
uint8_t readBuffer[3]; uint8_t readBuffer[3];
byte a,b; byte a,b;
#ifdef EXRAIL_ACTIVE // I would like to use the FastClock without EXRAIL
// #ifdef EXRAIL_ACTIVE
I2CManager.read(_I2CAddress, readBuffer, 3); I2CManager.read(_I2CAddress, readBuffer, 3);
// XXXX change this to save a few bytes // XXXX change this to save a few bytes
a = readBuffer[0]; a = readBuffer[0];
@ -110,7 +111,7 @@ void _loop(unsigned long currentMicros) override{
// Clock interval is 60/ clockspeed i.e 60/b seconds // Clock interval is 60/ clockspeed i.e 60/b seconds
delayUntil(currentMicros + ((60/b) * 1000000)); delayUntil(currentMicros + ((60/b) * 1000000));
#endif // #endif
} }
} }

View File

@ -1,5 +1,6 @@
/* /*
* © 2022, Peter Cole. All rights reserved. * © 2022, Peter Cole. All rights reserved.
* © 2024, Harald Barth. All rights reserved.
* *
* This file is part of EX-CommandStation * This file is part of EX-CommandStation
* *
@ -98,13 +99,22 @@ private:
_numAnaloguePins = receiveBuffer[2]; _numAnaloguePins = receiveBuffer[2];
// See if we already have suitable buffers assigned // See if we already have suitable buffers assigned
if (_numDigitalPins>0) {
size_t digitalBytesNeeded = (_numDigitalPins + 7) / 8; size_t digitalBytesNeeded = (_numDigitalPins + 7) / 8;
if (_digitalPinBytes < digitalBytesNeeded) { if (_digitalPinBytes < digitalBytesNeeded) {
// Not enough space, free any existing buffer and allocate a new one // Not enough space, free any existing buffer and allocate a new one
if (_digitalPinBytes > 0) free(_digitalInputStates); if (_digitalPinBytes > 0) free(_digitalInputStates);
_digitalInputStates = (byte*) calloc(_digitalPinBytes, 1); if ((_digitalInputStates = (byte*) calloc(digitalBytesNeeded, 1)) != NULL) {
_digitalPinBytes = digitalBytesNeeded; _digitalPinBytes = digitalBytesNeeded;
} else {
DIAG(F("EX-IOExpander I2C:%s ERROR alloc %d bytes"), _I2CAddress.toString(), digitalBytesNeeded);
_deviceState = DEVSTATE_FAILED;
_digitalPinBytes = 0;
return;
} }
}
}
if (_numAnaloguePins>0) {
size_t analogueBytesNeeded = _numAnaloguePins * 2; size_t analogueBytesNeeded = _numAnaloguePins * 2;
if (_analoguePinBytes < analogueBytesNeeded) { if (_analoguePinBytes < analogueBytesNeeded) {
// Free any existing buffers and allocate new ones. // Free any existing buffers and allocate new ones.
@ -116,7 +126,17 @@ private:
_analogueInputStates = (uint8_t*) calloc(analogueBytesNeeded, 1); _analogueInputStates = (uint8_t*) calloc(analogueBytesNeeded, 1);
_analogueInputBuffer = (uint8_t*) calloc(analogueBytesNeeded, 1); _analogueInputBuffer = (uint8_t*) calloc(analogueBytesNeeded, 1);
_analoguePinMap = (uint8_t*) calloc(_numAnaloguePins, 1); _analoguePinMap = (uint8_t*) calloc(_numAnaloguePins, 1);
if (_analogueInputStates != NULL &&
_analogueInputBuffer != NULL &&
_analoguePinMap != NULL) {
_analoguePinBytes = analogueBytesNeeded; _analoguePinBytes = analogueBytesNeeded;
} else {
DIAG(F("EX-IOExpander I2C:%s ERROR alloc analog pin bytes"), _I2CAddress.toString());
_deviceState = DEVSTATE_FAILED;
_analoguePinBytes = 0;
return;
}
}
} }
} else { } else {
DIAG(F("EX-IOExpander I2C:%s ERROR configuring device"), _I2CAddress.toString()); DIAG(F("EX-IOExpander I2C:%s ERROR configuring device"), _I2CAddress.toString());
@ -124,8 +144,8 @@ private:
return; return;
} }
} }
// We now need to retrieve the analogue pin map // We now need to retrieve the analogue pin map if there are analogue pins
if (status == I2C_STATUS_OK) { if (status == I2C_STATUS_OK && _numAnaloguePins>0) {
commandBuffer[0] = EXIOINITA; commandBuffer[0] = EXIOINITA;
status = I2CManager.read(_I2CAddress, _analoguePinMap, _numAnaloguePins, commandBuffer, 1); status = I2CManager.read(_I2CAddress, _analoguePinMap, _numAnaloguePins, commandBuffer, 1);
} }
@ -239,7 +259,7 @@ private:
// If we're not doing anything now, check to see if a new input transfer is due. // If we're not doing anything now, check to see if a new input transfer is due.
if (_readState == RDS_IDLE) { if (_readState == RDS_IDLE) {
if (currentMicros - _lastDigitalRead > _digitalRefresh) { // Delay for digital read refresh if (_numDigitalPins>0 && currentMicros - _lastDigitalRead > _digitalRefresh) { // Delay for digital read refresh
// Issue new read request for digital states. As the request is non-blocking, the buffer has to // Issue new read request for digital states. As the request is non-blocking, the buffer has to
// be allocated from heap (object state). // be allocated from heap (object state).
_readCommandBuffer[0] = EXIORDD; _readCommandBuffer[0] = EXIORDD;
@ -247,7 +267,7 @@ private:
// non-blocking read // non-blocking read
_lastDigitalRead = currentMicros; _lastDigitalRead = currentMicros;
_readState = RDS_DIGITAL; _readState = RDS_DIGITAL;
} else if (currentMicros - _lastAnalogueRead > _analogueRefresh) { // Delay for analogue read refresh } else if (_numAnaloguePins>0 && currentMicros - _lastAnalogueRead > _analogueRefresh) { // Delay for analogue read refresh
// Issue new read for analogue input states // Issue new read for analogue input states
_readCommandBuffer[0] = EXIORDAN; _readCommandBuffer[0] = EXIORDAN;
I2CManager.read(_I2CAddress, _analogueInputBuffer, I2CManager.read(_I2CAddress, _analogueInputBuffer,
@ -362,14 +382,14 @@ private:
uint8_t _minorVer = 0; uint8_t _minorVer = 0;
uint8_t _patchVer = 0; uint8_t _patchVer = 0;
uint8_t* _digitalInputStates; uint8_t* _digitalInputStates = NULL;
uint8_t* _analogueInputStates; uint8_t* _analogueInputStates = NULL;
uint8_t* _analogueInputBuffer; // buffer for I2C input transfers uint8_t* _analogueInputBuffer = NULL; // buffer for I2C input transfers
uint8_t _readCommandBuffer[1]; uint8_t _readCommandBuffer[1];
uint8_t _digitalPinBytes = 0; // Size of allocated memory buffer (may be longer than needed) uint8_t _digitalPinBytes = 0; // Size of allocated memory buffer (may be longer than needed)
uint8_t _analoguePinBytes = 0; // Size of allocated memory buffers (may be longer than needed) uint8_t _analoguePinBytes = 0; // Size of allocated memory buffer (may be longer than needed)
uint8_t* _analoguePinMap; uint8_t* _analoguePinMap = NULL;
I2CRB _i2crb; I2CRB _i2crb;
enum {RDS_IDLE, RDS_DIGITAL, RDS_ANALOGUE}; // Read operation states enum {RDS_IDLE, RDS_DIGITAL, RDS_ANALOGUE}; // Read operation states

View File

@ -1,3 +1,7 @@
# My (FranziHH) DCC++ Ex Hardware
<img src="/images/IMG_5870_1.jpg" height="400px" title="DCC++ Ex Hardware">
# What is DCC++ EX? # What is DCC++ EX?
DCC++ EX is the organization maintaining several codebases that together represent a fully open source DCC system. Currently, this includes the following: DCC++ EX is the organization maintaining several codebases that together represent a fully open source DCC system. Currently, this includes the following:

View File

@ -363,11 +363,17 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password,
} }
ipString[ipLen]=ipChar; ipString[ipLen]=ipChar;
} }
#ifndef PRINT_IP_PORT_SINGLE_LINE
LCD(4,F("%s"),ipString); // There is not enough room on some LCDs to put a title to this LCD(4,F("%s"),ipString); // There is not enough room on some LCDs to put a title to this
#else
LCD(4,F("%s:%d"),ipString,port); // *** Single IP:Port
#endif
} }
// suck up anything after the IP. // suck up anything after the IP.
if (!checkForOK(1000, true, false)) return WIFI_DISCONNECTED; if (!checkForOK(1000, true, false)) return WIFI_DISCONNECTED;
#ifndef PRINT_IP_PORT_SINGLE_LINE
LCD(5,F("PORT=%d"),port); LCD(5,F("PORT=%d"),port);
#endif
return WIFI_CONNECTED; return WIFI_CONNECTED;
} }

View File

@ -167,6 +167,9 @@ The configuration file for DCC-EX Command Station
// * #define SCROLLMODE 2 is by row (move up 1 row at a time). // * #define SCROLLMODE 2 is by row (move up 1 row at a time).
#define SCROLLMODE 1 #define SCROLLMODE 1
// Shows IP and Port on Display in a single line
// #define PRINT_IP_PORT_SINGLE_LINE
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
// DISABLE EEPROM // DISABLE EEPROM
// //
@ -239,7 +242,10 @@ The configuration file for DCC-EX Command Station
// SAMD/SAMC and STM32 have up to 6.) // SAMD/SAMC and STM32 have up to 6.)
// To monitor a throttle on one or more serial ports, uncomment the defines below. // To monitor a throttle on one or more serial ports, uncomment the defines below.
// NOTE: do not define here the WiFi shield serial port or your wifi will not work. // NOTE: do not define here the WiFi shield serial port or your wifi will not work.
// // -------------------------------------
// For Use with FastClock serial: uncomment the needed serial Port and
// FastClock will work, no further actions are needed
// -------------------------------------
//#define SERIAL1_COMMANDS //#define SERIAL1_COMMANDS
//#define SERIAL2_COMMANDS //#define SERIAL2_COMMANDS
//#define SERIAL3_COMMANDS //#define SERIAL3_COMMANDS
@ -247,6 +253,17 @@ The configuration file for DCC-EX Command Station
//#define SERIAL5_COMMANDS //#define SERIAL5_COMMANDS
//#define SERIAL6_COMMANDS //#define SERIAL6_COMMANDS
// //
// -------------------------------------
// FastClock with I2C
// uncomment the following Line and Set the used I2C Address
//#define FAST_CLOCK_I2C 0x55 // default is 0x55
// -------------------------------------
//
// -------------------------------------
// FastClock in HH:MM on Display
//#define FASTCLOCK_READABLE
// -------------------------------------
//
// BLUETOOTH SERIAL ON ESP32 // BLUETOOTH SERIAL ON ESP32
// On ESP32 you have the possibility to use the builtin BT serial to connect to // On ESP32 you have the possibility to use the builtin BT serial to connect to
// the CS. // the CS.

BIN
images/IMG_5870_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 KiB

View File

@ -3,7 +3,10 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "5.0.7" #define VERSION "5.0.9"
// 5.0.9 - EX-IOExpander bug fix for memory allocation
// - EX-IOExpander bug fix to allow for devices with no analogue or no digital pins
// 5.0.8 - Bugfix: Do not crash on turnouts without description
// 5.0.7 - Only flag 2.2.0.0-dev as broken, not 2.2.0.0 // 5.0.7 - Only flag 2.2.0.0-dev as broken, not 2.2.0.0
// 5.0.6 - Bugfix lost TURNOUTL description // 5.0.6 - Bugfix lost TURNOUTL description
// 5.0.5 - Bugfix version detection logic and better message // 5.0.5 - Bugfix version detection logic and better message