mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-24 00:26:13 +01:00
Compare commits
7 Commits
4e48b24d77
...
81460952c9
Author | SHA1 | Date | |
---|---|---|---|
|
81460952c9 | ||
|
657c08c653 | ||
|
bc37a2d2cf | ||
|
3c0704dbd1 | ||
|
95bf5aae38 | ||
|
8216579f62 | ||
|
a54a262f68 |
|
@ -1113,11 +1113,11 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[])
|
||||||
|
|
||||||
case "ANOUT"_hk: // <D ANOUT vpin position [profile]>
|
case "ANOUT"_hk: // <D ANOUT vpin position [profile]>
|
||||||
IODevice::writeAnalogue(p[1], p[2], params>3 ? p[3] : 0);
|
IODevice::writeAnalogue(p[1], p[2], params>3 ? p[3] : 0);
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
case "ANIN"_hk: // <D ANIN vpin> Display analogue input value
|
case "ANIN"_hk: // <D ANIN vpin> Display analogue input value
|
||||||
DIAG(F("VPIN=%u value=%d"), p[1], IODevice::readAnalogue(p[1]));
|
DIAG(F("VPIN=%u value=%d"), p[1], IODevice::readAnalogue(p[1]));
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
#if !defined(IO_NO_HAL)
|
#if !defined(IO_NO_HAL)
|
||||||
case "HAL"_hk:
|
case "HAL"_hk:
|
||||||
|
@ -1130,7 +1130,7 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[])
|
||||||
|
|
||||||
case "TT"_hk: // <D TT vpin steps activity>
|
case "TT"_hk: // <D TT vpin steps activity>
|
||||||
IODevice::writeAnalogue(p[1], p[2], params>3 ? p[3] : 0);
|
IODevice::writeAnalogue(p[1], p[2], params>3 ? p[3] : 0);
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
default: // invalid/unknown
|
default: // invalid/unknown
|
||||||
return parseC(stream, params, p);
|
return parseC(stream, params, p);
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#undef FWD
|
#undef FWD
|
||||||
#undef GREEN
|
#undef GREEN
|
||||||
#undef HAL
|
#undef HAL
|
||||||
|
#undef HAL_IGNORE_DEFAULTS
|
||||||
#undef IF
|
#undef IF
|
||||||
#undef IFAMBER
|
#undef IFAMBER
|
||||||
#undef IFCLOSED
|
#undef IFCLOSED
|
||||||
|
@ -218,6 +219,7 @@
|
||||||
#define FWD(speed)
|
#define FWD(speed)
|
||||||
#define GREEN(signal_id)
|
#define GREEN(signal_id)
|
||||||
#define HAL(haltype,params...)
|
#define HAL(haltype,params...)
|
||||||
|
#define HAL_IGNORE_DEFAULTS
|
||||||
#define IF(sensor_id)
|
#define IF(sensor_id)
|
||||||
#define IFAMBER(signal_id)
|
#define IFAMBER(signal_id)
|
||||||
#define IFCLOSED(turnout_id)
|
#define IFCLOSED(turnout_id)
|
||||||
|
|
|
@ -74,13 +74,81 @@
|
||||||
#define ALIAS(name,value...) const int name= 1##value##0 ==10 ? -__COUNTER__ : value##0/10;
|
#define ALIAS(name,value...) const int name= 1##value##0 ==10 ? -__COUNTER__ : value##0/10;
|
||||||
#include "myAutomation.h"
|
#include "myAutomation.h"
|
||||||
|
|
||||||
|
// Pass 1d Detect sequence duplicates.
|
||||||
|
// This pass generates no runtime data or code
|
||||||
|
#include "EXRAIL2MacroReset.h"
|
||||||
|
#undef AUTOMATION
|
||||||
|
#define AUTOMATION(id, description) id,
|
||||||
|
#undef ROUTE
|
||||||
|
#define ROUTE(id, description) id,
|
||||||
|
#undef SEQUENCE
|
||||||
|
#define SEQUENCE(id) id,
|
||||||
|
constexpr int16_t compileTimeSequenceList[]={
|
||||||
|
#include "myAutomation.h"
|
||||||
|
0
|
||||||
|
};
|
||||||
|
constexpr int16_t stuffSize=sizeof(compileTimeSequenceList)/sizeof(int16_t) - 1;
|
||||||
|
|
||||||
|
|
||||||
|
// Compile time function to check for sequence nos.
|
||||||
|
constexpr bool hasseq(const int16_t value, const uint16_t pos=0 ) {
|
||||||
|
return pos>=stuffSize? false :
|
||||||
|
compileTimeSequenceList[pos]==value
|
||||||
|
|| hasseq(value,pos+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile time function to check for duplicate sequence nos.
|
||||||
|
constexpr bool hasdup(const int16_t value, const uint16_t pos ) {
|
||||||
|
return pos>=stuffSize? false :
|
||||||
|
compileTimeSequenceList[pos]==value
|
||||||
|
|| hasseq(value,pos+1)
|
||||||
|
|| hasdup(compileTimeSequenceList[pos],pos+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static_assert(!hasdup(compileTimeSequenceList[0],1),"Duplicate SEQUENCE/ROUTE/AUTOMATION detected");
|
||||||
|
|
||||||
|
//pass 1s static asserts to
|
||||||
|
// - check call and follows etc for existing sequence numbers
|
||||||
|
// - check range on LATCH/UNLATCH
|
||||||
|
// This pass generates no runtime data or code
|
||||||
|
#include "EXRAIL2MacroReset.h"
|
||||||
|
#undef CALL
|
||||||
|
#define CALL(id) static_assert(hasseq(id),"Sequence not found");
|
||||||
|
#undef FOLLOW
|
||||||
|
#define FOLLOW(id) static_assert(hasseq(id),"Sequence not found");
|
||||||
|
#undef START
|
||||||
|
#define START(id) static_assert(hasseq(id),"Sequence not found");
|
||||||
|
#undef SENDLOCO
|
||||||
|
#define SENDLOCO(cab,id) static_assert(hasseq(id),"Sequence not found");
|
||||||
|
#undef LATCH
|
||||||
|
#define LATCH(id) static_assert(id>=0 && id<MAX_FLAGS,"Id out of valid range 0-255" );
|
||||||
|
#undef UNLATCH
|
||||||
|
#define UNLATCH(id) static_assert(id>=0 && id<MAX_FLAGS,"Id out of valid range 0-255" );
|
||||||
|
#undef RESERVE
|
||||||
|
#define RESERVE(id) static_assert(id>=0 && id<MAX_FLAGS,"Id out of valid range 0-255" );
|
||||||
|
#undef FREE
|
||||||
|
#define FREE(id) static_assert(id>=0 && id<MAX_FLAGS,"Id out of valid range 0-255" );
|
||||||
|
#undef SPEED
|
||||||
|
#define SPEED(speed) static_assert(speed>=0 && speed<128,"Speed out of valid range 0-127");
|
||||||
|
#undef FWD
|
||||||
|
#define FWD(speed) static_assert(speed>=0 && speed<128,"Speed out of valid range 0-127");
|
||||||
|
#undef REV
|
||||||
|
#define REV(speed) static_assert(speed>=0 && speed<128,"Speed out of valid range 0-127");
|
||||||
|
|
||||||
|
#include "myAutomation.h"
|
||||||
|
|
||||||
// Pass 1h Implements HAL macro by creating exrailHalSetup function
|
// Pass 1h Implements HAL macro by creating exrailHalSetup function
|
||||||
// Also allows creating EXTurntable object
|
// Also allows creating EXTurntable object
|
||||||
#include "EXRAIL2MacroReset.h"
|
#include "EXRAIL2MacroReset.h"
|
||||||
#undef HAL
|
#undef HAL
|
||||||
#define HAL(haltype,params...) haltype::create(params);
|
#define HAL(haltype,params...) haltype::create(params);
|
||||||
void exrailHalSetup() {
|
#undef HAL_IGNORE_DEFAULTS
|
||||||
|
#define HAL_IGNORE_DEFAULTS ignore_defaults=true;
|
||||||
|
bool exrailHalSetup() {
|
||||||
|
bool ignore_defaults=false;
|
||||||
#include "myAutomation.h"
|
#include "myAutomation.h"
|
||||||
|
return ignore_defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass 1c detect compile time featurtes
|
// Pass 1c detect compile time featurtes
|
||||||
|
@ -396,6 +464,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define FWD(speed) OPCODE_FWD,V(speed),
|
#define FWD(speed) OPCODE_FWD,V(speed),
|
||||||
#define GREEN(signal_id) OPCODE_GREEN,V(signal_id),
|
#define GREEN(signal_id) OPCODE_GREEN,V(signal_id),
|
||||||
#define HAL(haltype,params...)
|
#define HAL(haltype,params...)
|
||||||
|
#define HAL_IGNORE_DEFAULTS
|
||||||
#define IF(sensor_id) OPCODE_IF,V(sensor_id),
|
#define IF(sensor_id) OPCODE_IF,V(sensor_id),
|
||||||
#define IFAMBER(signal_id) OPCODE_IFAMBER,V(signal_id),
|
#define IFAMBER(signal_id) OPCODE_IFAMBER,V(signal_id),
|
||||||
#define IFCLOSED(turnout_id) OPCODE_IFCLOSED,V(turnout_id),
|
#define IFCLOSED(turnout_id) OPCODE_IFCLOSED,V(turnout_id),
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#define GITHUB_SHA "devel-202401101409Z"
|
#define GITHUB_SHA "devel-202401180721Z"
|
||||||
|
|
34
IODevice.cpp
34
IODevice.cpp
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
// Link to halSetup function. If not defined, the function reference will be NULL.
|
// Link to halSetup function. If not defined, the function reference will be NULL.
|
||||||
extern __attribute__((weak)) void halSetup();
|
extern __attribute__((weak)) void halSetup();
|
||||||
extern __attribute__((weak)) void exrailHalSetup();
|
extern __attribute__((weak)) bool exrailHalSetup();
|
||||||
|
|
||||||
//==================================================================================================================
|
//==================================================================================================================
|
||||||
// Static methods
|
// Static methods
|
||||||
|
@ -60,33 +60,30 @@ void IODevice::begin() {
|
||||||
halSetup();
|
halSetup();
|
||||||
|
|
||||||
// include any HAL devices defined in exrail.
|
// include any HAL devices defined in exrail.
|
||||||
|
bool ignoreDefaults=false;
|
||||||
if (exrailHalSetup)
|
if (exrailHalSetup)
|
||||||
exrailHalSetup();
|
ignoreDefaults=exrailHalSetup();
|
||||||
|
if (ignoreDefaults) return;
|
||||||
|
|
||||||
// Predefine two PCA9685 modules 0x40-0x41 if no conflicts
|
// Predefine two PCA9685 modules 0x40-0x41 if no conflicts
|
||||||
// Allocates 32 pins 100-131
|
// Allocates 32 pins 100-131
|
||||||
if (checkNoOverlap(100, 16, 0x40)) {
|
const bool silent=true; // no message if these conflict
|
||||||
|
if (checkNoOverlap(100, 16, 0x40, silent)) {
|
||||||
PCA9685::create(100, 16, 0x40);
|
PCA9685::create(100, 16, 0x40);
|
||||||
} else {
|
|
||||||
DIAG(F("Default PCA9685 at I2C 0x40 disabled due to configured user device"));
|
|
||||||
}
|
}
|
||||||
if (checkNoOverlap(116, 16, 0x41)) {
|
|
||||||
|
if (checkNoOverlap(116, 16, 0x41, silent)) {
|
||||||
PCA9685::create(116, 16, 0x41);
|
PCA9685::create(116, 16, 0x41);
|
||||||
} else {
|
|
||||||
DIAG(F("Default PCA9685 at I2C 0x41 disabled due to configured user device"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, silent)) {
|
||||||
MCP23017::create(164, 16, 0x20);
|
MCP23017::create(164, 16, 0x20);
|
||||||
} else {
|
|
||||||
DIAG(F("Default MCP23017 at I2C 0x20 disabled due to configured user device"));
|
|
||||||
}
|
}
|
||||||
if (checkNoOverlap(180, 16, 0x21)) {
|
|
||||||
|
if (checkNoOverlap(180, 16, 0x21, silent)) {
|
||||||
MCP23017::create(180, 16, 0x21);
|
MCP23017::create(180, 16, 0x21);
|
||||||
} else {
|
|
||||||
DIAG(F("Default MCP23017 at I2C 0x21 disabled due to configured user device"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +336,10 @@ IODevice *IODevice::findDeviceFollowing(VPIN vpin) {
|
||||||
// returns true if pins DONT overlap with existing device
|
// returns true if pins DONT overlap with existing device
|
||||||
// TODO: Move the I2C address reservation and checks into the I2CManager code.
|
// TODO: Move the I2C address reservation and checks into the I2CManager code.
|
||||||
// That will enable non-HAL devices to reserve I2C addresses too.
|
// That will enable non-HAL devices to reserve I2C addresses too.
|
||||||
bool IODevice::checkNoOverlap(VPIN firstPin, uint8_t nPins, I2CAddress i2cAddress) {
|
// Silent is used by the default setup so that there is no message if the default
|
||||||
|
// device has already been handled by the user setup.
|
||||||
|
bool IODevice::checkNoOverlap(VPIN firstPin, uint8_t nPins,
|
||||||
|
I2CAddress i2cAddress, bool silent) {
|
||||||
#ifdef DIAG_IO
|
#ifdef DIAG_IO
|
||||||
DIAG(F("Check no overlap %u %u %s"), firstPin,nPins,i2cAddress.toString());
|
DIAG(F("Check no overlap %u %u %s"), firstPin,nPins,i2cAddress.toString());
|
||||||
#endif
|
#endif
|
||||||
|
@ -352,14 +352,14 @@ bool IODevice::checkNoOverlap(VPIN firstPin, uint8_t nPins, I2CAddress i2cAddres
|
||||||
VPIN lastDevPin=firstDevPin+dev->_nPins-1;
|
VPIN lastDevPin=firstDevPin+dev->_nPins-1;
|
||||||
bool noOverlap= firstPin>lastDevPin || lastPin<firstDevPin;
|
bool noOverlap= firstPin>lastDevPin || lastPin<firstDevPin;
|
||||||
if (!noOverlap) {
|
if (!noOverlap) {
|
||||||
DIAG(F("WARNING HAL Overlap, redefinition of Vpins %u to %u ignored."),
|
if (!silent) DIAG(F("WARNING HAL Overlap, redefinition of Vpins %u to %u ignored."),
|
||||||
firstPin, lastPin);
|
firstPin, lastPin);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check for overlapping I2C address
|
// Check for overlapping I2C address
|
||||||
if (i2cAddress && dev->_I2CAddress==i2cAddress) {
|
if (i2cAddress && dev->_I2CAddress==i2cAddress) {
|
||||||
DIAG(F("WARNING HAL Overlap. i2c Addr %s ignored."),i2cAddress.toString());
|
if (!silent) DIAG(F("WARNING HAL Overlap. i2c Addr %s ignored."),i2cAddress.toString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,8 @@ public:
|
||||||
void setGPIOInterruptPin(int16_t pinNumber);
|
void setGPIOInterruptPin(int16_t pinNumber);
|
||||||
|
|
||||||
// Method to check if pins will overlap before creating new device.
|
// Method to check if pins will overlap before creating new device.
|
||||||
static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1, I2CAddress i2cAddress=0);
|
static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1,
|
||||||
|
I2CAddress i2cAddress=0, bool silent=false);
|
||||||
|
|
||||||
// Method used by IODevice filters to locate slave pins that may be overlayed by their own
|
// Method used by IODevice filters to locate slave pins that may be overlayed by their own
|
||||||
// pin range.
|
// pin range.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* © 2022, Peter Cole. All rights reserved.
|
* © 2022, Peter Cole. All rights reserved.
|
||||||
|
* © 2022, Harald Barth. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of EX-CommandStation
|
* This file is part of EX-CommandStation
|
||||||
*
|
*
|
||||||
|
@ -100,8 +101,14 @@ private:
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +124,16 @@ 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);
|
||||||
_analoguePinBytes = analogueBytesNeeded;
|
if (_analogueInputStates != NULL &&
|
||||||
|
_analogueInputBuffer != NULL &&
|
||||||
|
_analoguePinMap != NULL) {
|
||||||
|
_analoguePinBytes = analogueBytesNeeded;
|
||||||
|
} else {
|
||||||
|
DIAG(F("EX-IOExpander I2C:%s ERROR alloc analog pin bytes"), _I2CAddress.toString());
|
||||||
|
_deviceState = DEVSTATE_FAILED;
|
||||||
|
_analoguePinBytes = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -364,14 +380,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
|
||||||
|
|
10
version.h
10
version.h
|
@ -3,7 +3,15 @@
|
||||||
|
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
#define VERSION "5.2.23"
|
#define VERSION "5.2.27"
|
||||||
|
// 5.2.27 - Bugfix: IOExpander memory allocation
|
||||||
|
// 5.2.26 - Silently ignore overridden HAL defaults
|
||||||
|
// - include HAL_IGNORE_DEFAULTS macro in EXRAIL
|
||||||
|
// 5.2.25 - Fix bug causing <X> after working <D commands
|
||||||
|
// 5.2.24 - Exrail macro asserts to catch
|
||||||
|
// : duplicate/missing automation/route/sequence/call ids
|
||||||
|
// : latches and reserves out of range
|
||||||
|
// : speeds out of range
|
||||||
// 5.2.23 - KeywordHasher _hk (no functional change)
|
// 5.2.23 - KeywordHasher _hk (no functional change)
|
||||||
// 5.2.22 - Bugfixes: Empty turnout descriptions ok; negative route numbers valid.
|
// 5.2.22 - Bugfixes: Empty turnout descriptions ok; negative route numbers valid.
|
||||||
// 5.2.21 - Add STARTUP_DELAY config option to delay CS bootup
|
// 5.2.21 - Add STARTUP_DELAY config option to delay CS bootup
|
||||||
|
|
Loading…
Reference in New Issue
Block a user