mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 16:16:13 +01:00
Compare commits
38 Commits
8efd3a310b
...
3409f57e1c
Author | SHA1 | Date | |
---|---|---|---|
|
3409f57e1c | ||
|
0587e6fc09 | ||
|
3cda869c6e | ||
|
59d855549e | ||
|
e3081a7e56 | ||
|
8eec85edcf | ||
|
d753eb43e3 | ||
|
9aac34b403 | ||
|
be218d3032 | ||
|
4b04a80e6f | ||
|
b752666899 | ||
|
3d6f41398d | ||
|
7503421eb6 | ||
|
274affce45 | ||
|
b29a01f436 | ||
|
1101cfd637 | ||
|
3fa2edb0da | ||
|
423d1932ae | ||
|
dec39a2ae1 | ||
|
821115caad | ||
|
daa2ffc459 | ||
|
9728d19b19 | ||
|
99a09c713f | ||
|
a5b73c823a | ||
|
8036ba1c48 | ||
|
6f076720f7 | ||
|
d899da5898 | ||
|
3ce9d2ec88 | ||
|
9ebb1c5fb1 | ||
|
19efa749b8 | ||
|
36cc46e88d | ||
|
bba74a08f6 | ||
|
ab58c38e7b | ||
|
d4f0a7c8f3 | ||
|
ba0a41b6f2 | ||
|
bf17f2018b | ||
|
67387d2dc3 | ||
|
adb8b56c92 |
|
@ -310,6 +310,11 @@ void CommandDistributor::broadcastRaw(clientType type, char * msg) {
|
|||
broadcastReply(type, F("%s"),msg);
|
||||
}
|
||||
|
||||
void CommandDistributor::broadcastMessage(char * message) {
|
||||
broadcastReply(COMMAND_TYPE, F("<m \"%s\">\n"),message);
|
||||
broadcastReply(WITHROTTLE_TYPE, F("Hm%s\n"),message);
|
||||
}
|
||||
|
||||
void CommandDistributor::broadcastTrackState(const FSH* format, byte trackLetter, const FSH *modename, int16_t dcAddr) {
|
||||
broadcastReply(COMMAND_TYPE, format, trackLetter, modename, dcAddr);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ public :
|
|||
static void forget(byte clientId);
|
||||
static void broadcastRouteState(uint16_t routeId,byte state);
|
||||
static void broadcastRouteCaption(uint16_t routeId,const FSH * caption);
|
||||
static void broadcastMessage(char * message);
|
||||
|
||||
// Handling code for virtual LCD receiver.
|
||||
static Print * getVirtualLCDSerial(byte screen, byte row);
|
||||
|
|
|
@ -65,6 +65,9 @@
|
|||
#ifdef EXRAIL_WARNING
|
||||
#warning You have myAutomation.h but your hardware has not enough memory to do that, so EX-RAIL DISABLED
|
||||
#endif
|
||||
// compile time check, passwords 1 to 7 chars do not work, so do not try to compile with them at all
|
||||
// remember trailing '\0', sizeof("") == 1.
|
||||
#define PASSWDCHECK(S) static_assert(sizeof(S) == 1 || sizeof(S) > 8, "Password shorter than 8 chars")
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
@ -102,10 +105,12 @@ void setup()
|
|||
// Start Ethernet if it exists
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
#if WIFI_ON
|
||||
PASSWDCHECK(WIFI_PASSWORD); // compile time check
|
||||
WifiInterface::setup(WIFI_SERIAL_LINK_SPEED, F(WIFI_SSID), F(WIFI_PASSWORD), F(WIFI_HOSTNAME), IP_PORT, WIFI_CHANNEL, WIFI_FORCE_AP);
|
||||
#endif // WIFI_ON
|
||||
#else
|
||||
// ESP32 needs wifi on always
|
||||
PASSWDCHECK(WIFI_PASSWORD); // compile time check
|
||||
WifiESP::setup(WIFI_SSID, WIFI_PASSWORD, WIFI_HOSTNAME, IP_PORT, WIFI_CHANNEL, WIFI_FORCE_AP);
|
||||
#endif // ARDUINO_ARCH_ESP32
|
||||
|
||||
|
|
44
DCC.cpp
44
DCC.cpp
|
@ -153,6 +153,22 @@ uint8_t DCC::getThrottleSpeedByte(int cab) {
|
|||
return speedTable[reg].speedCode;
|
||||
}
|
||||
|
||||
// returns 0 to 7 for frequency
|
||||
uint8_t DCC::getThrottleFrequency(int cab) {
|
||||
#if defined(ARDUINO_AVR_UNO)
|
||||
(void)cab;
|
||||
return 0;
|
||||
#else
|
||||
int reg=lookupSpeedTable(cab);
|
||||
if (reg<0)
|
||||
return 0; // use default frequency
|
||||
// shift out first 29 bits so we have the 3 "frequency bits" left
|
||||
uint8_t res = (uint8_t)(speedTable[reg].functions >>29);
|
||||
//DIAG(F("Speed table %d functions %l shifted %d"), reg, speedTable[reg].functions, res);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns direction on loco
|
||||
// or true/forward on "loco not found"
|
||||
bool DCC::getThrottleDirection(int cab) {
|
||||
|
@ -183,43 +199,55 @@ bool DCC::setFn( int cab, int16_t functionNumber, bool on) {
|
|||
b[nB++] = functionNumber >>7 ; // high order bits
|
||||
}
|
||||
DCCWaveform::mainTrack.schedulePacket(b, nB, 4);
|
||||
return true;
|
||||
}
|
||||
// We use the reminder table up to 28 for normal functions.
|
||||
// We use 29 to 31 for DC frequency as well so up to 28
|
||||
// are "real" functions and 29 to 31 are frequency bits
|
||||
// controlled by function buttons
|
||||
if (functionNumber > 31)
|
||||
return true;
|
||||
|
||||
int reg = lookupSpeedTable(cab);
|
||||
if (reg<0) return false;
|
||||
|
||||
// Take care of functions:
|
||||
// Set state of function
|
||||
unsigned long previous=speedTable[reg].functions;
|
||||
unsigned long funcmask = (1UL<<functionNumber);
|
||||
uint32_t previous=speedTable[reg].functions;
|
||||
uint32_t funcmask = (1UL<<functionNumber);
|
||||
if (on) {
|
||||
speedTable[reg].functions |= funcmask;
|
||||
} else {
|
||||
speedTable[reg].functions &= ~funcmask;
|
||||
}
|
||||
if (speedTable[reg].functions != previous) {
|
||||
if (functionNumber <= 28)
|
||||
updateGroupflags(speedTable[reg].groupFlags, functionNumber);
|
||||
CommandDistributor::broadcastLoco(reg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Flip function state
|
||||
// Flip function state (used from withrottle protocol)
|
||||
void DCC::changeFn( int cab, int16_t functionNumber) {
|
||||
if (cab<=0 || functionNumber>28) return;
|
||||
if (cab<=0 || functionNumber>31) return;
|
||||
int reg = lookupSpeedTable(cab);
|
||||
if (reg<0) return;
|
||||
unsigned long funcmask = (1UL<<functionNumber);
|
||||
speedTable[reg].functions ^= funcmask;
|
||||
if (functionNumber <= 28) {
|
||||
updateGroupflags(speedTable[reg].groupFlags, functionNumber);
|
||||
}
|
||||
CommandDistributor::broadcastLoco(reg);
|
||||
}
|
||||
|
||||
int DCC::getFn( int cab, int16_t functionNumber) {
|
||||
if (cab<=0 || functionNumber>28) return -1; // unknown
|
||||
// Report function state (used from withrottle protocol)
|
||||
// returns 0 false, 1 true or -1 for do not know
|
||||
int8_t DCC::getFn( int cab, int16_t functionNumber) {
|
||||
if (cab<=0 || functionNumber>31)
|
||||
return -1; // unknown
|
||||
int reg = lookupSpeedTable(cab);
|
||||
if (reg<0) return -1;
|
||||
if (reg<0)
|
||||
return -1;
|
||||
|
||||
unsigned long funcmask = (1UL<<functionNumber);
|
||||
return (speedTable[reg].functions & funcmask)? 1 : 0;
|
||||
|
|
5
DCC.h
5
DCC.h
|
@ -61,13 +61,14 @@ public:
|
|||
static void setThrottle(uint16_t cab, uint8_t tSpeed, bool tDirection);
|
||||
static int8_t getThrottleSpeed(int cab);
|
||||
static uint8_t getThrottleSpeedByte(int cab);
|
||||
static uint8_t getThrottleFrequency(int cab);
|
||||
static bool getThrottleDirection(int cab);
|
||||
static void writeCVByteMain(int cab, int cv, byte bValue);
|
||||
static void writeCVBitMain(int cab, int cv, byte bNum, bool bValue);
|
||||
static void setFunction(int cab, byte fByte, byte eByte);
|
||||
static bool setFn(int cab, int16_t functionNumber, bool on);
|
||||
static void changeFn(int cab, int16_t functionNumber);
|
||||
static int getFn(int cab, int16_t functionNumber);
|
||||
static int8_t getFn(int cab, int16_t functionNumber);
|
||||
static uint32_t getFunctionMap(int cab);
|
||||
static void updateGroupflags(byte &flags, int16_t functionNumber);
|
||||
static void setAccessory(int address, byte port, bool gate, byte onoff = 2);
|
||||
|
@ -99,7 +100,7 @@ public:
|
|||
int loco;
|
||||
byte speedCode;
|
||||
byte groupFlags;
|
||||
unsigned long functions;
|
||||
uint32_t functions;
|
||||
};
|
||||
static LOCO speedTable[MAX_LOCOS];
|
||||
static int lookupSpeedTable(int locoId, bool autoCreate=true);
|
||||
|
|
|
@ -68,7 +68,7 @@ Once a new OPCODE is decided upon, update this list.
|
|||
K, Reserved for future use - Potentially Railcom
|
||||
l, Loco speedbyte/function map broadcast
|
||||
L, Reserved for LCC interface (implemented in EXRAIL)
|
||||
m,
|
||||
m, message to throttles broadcast
|
||||
M, Write DCC packet
|
||||
n,
|
||||
N,
|
||||
|
@ -283,25 +283,22 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||
return; // filterCallback asked us to ignore
|
||||
case 't': // THROTTLE <t [REGISTER] CAB SPEED DIRECTION>
|
||||
{
|
||||
if (params==1) { // <t cab> display state
|
||||
int16_t cab;
|
||||
int16_t tspeed;
|
||||
int16_t direction;
|
||||
|
||||
if (params==1) { // <t cab> display state
|
||||
int16_t slot=DCC::lookupSpeedTable(p[0],false);
|
||||
if (slot>=0) {
|
||||
DCC::LOCO * sp=&DCC::speedTable[slot];
|
||||
StringFormatter::send(stream,F("<l %d %d %d %l>\n"),
|
||||
sp->loco,slot,sp->speedCode,sp->functions);
|
||||
}
|
||||
if (slot>=0)
|
||||
CommandDistributor::broadcastLoco(slot);
|
||||
else // send dummy state speed 0 fwd no functions.
|
||||
StringFormatter::send(stream,F("<l %d -1 128 0>\n"),p[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t cab;
|
||||
int16_t tspeed;
|
||||
int16_t direction;
|
||||
|
||||
if (params == 4)
|
||||
{ // <t REGISTER CAB SPEED DIRECTION>
|
||||
// ignore register p[0]
|
||||
cab = p[1];
|
||||
tspeed = p[2];
|
||||
direction = p[3];
|
||||
|
@ -582,12 +579,13 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||
DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1.
|
||||
return;
|
||||
|
||||
#ifdef HAS_ENOUGH_MEMORY
|
||||
case 'c': // SEND METER RESPONSES <c>
|
||||
// No longer useful because of multiple tracks See <JG> and <JI>
|
||||
if (params>0) break;
|
||||
TrackManager::reportObsoleteCurrent(stream);
|
||||
return;
|
||||
|
||||
#endif
|
||||
case 'Q': // SENSORS <Q>
|
||||
Sensor::printAll(stream);
|
||||
return;
|
||||
|
|
|
@ -87,6 +87,7 @@ class DCCTimer {
|
|||
static void reset();
|
||||
|
||||
private:
|
||||
static void DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency);
|
||||
static int freeMemory();
|
||||
static volatile int minimum_free_memory;
|
||||
static const int DCC_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <avr/boot.h>
|
||||
#include <avr/wdt.h>
|
||||
#include "DCCTimer.h"
|
||||
#include "DIAG.h"
|
||||
#ifdef DEBUG_ADC
|
||||
#include "TrackManager.h"
|
||||
#endif
|
||||
|
@ -189,6 +190,81 @@ void DCCTimer::reset() {
|
|||
|
||||
}
|
||||
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) {
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, f);
|
||||
}
|
||||
void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t fbits) {
|
||||
#if defined(ARDUINO_AVR_UNO)
|
||||
// Not worth doin something here as:
|
||||
// If we are on pin 9 or 10 we are on Timer1 and we can not touch Timer1 as that is our DCC source.
|
||||
// If we are on pin 5 or 6 we are on Timer 0 ad we can not touch Timer0 as that is millis() etc.
|
||||
// We are most likely not on pin 3 or 11 as no known motor shield has that as brake.
|
||||
#endif
|
||||
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
||||
// Speed mapping is done like this:
|
||||
// No functions buttons: 000 0 -> low 131Hz
|
||||
// Only F29 pressed 001 1 -> mid 490Hz
|
||||
// F30 with or w/o F29 01x 2-3 -> high 3400Hz
|
||||
// F31 with or w/o F29/30 1xx 4-7 -> supersonic 62500Hz
|
||||
uint8_t abits;
|
||||
uint8_t bbits;
|
||||
if (pin == 9 || pin == 10) { // timer 2 is different
|
||||
|
||||
if (fbits >= 4)
|
||||
abits = B00000011;
|
||||
else
|
||||
abits = B00000001;
|
||||
|
||||
if (fbits >= 4)
|
||||
bbits = B0001;
|
||||
else if (fbits >= 2)
|
||||
bbits = B0010;
|
||||
else if (fbits == 1)
|
||||
bbits = B0100;
|
||||
else // fbits == 0
|
||||
bbits = B0110;
|
||||
|
||||
TCCR2A = (TCCR2A & B11111100) | abits; // set WGM0 and WGM1
|
||||
TCCR2B = (TCCR2B & B11110000) | bbits; // set WGM2 and 3 bits of prescaler
|
||||
DIAG(F("Timer 2 A=%x B=%x"), TCCR2A, TCCR2B);
|
||||
|
||||
} else { // not timer 9 or 10
|
||||
abits = B01;
|
||||
|
||||
if (fbits >= 4)
|
||||
bbits = B1001;
|
||||
else if (fbits >= 2)
|
||||
bbits = B0010;
|
||||
else if (fbits == 1)
|
||||
bbits = B0011;
|
||||
else
|
||||
bbits = B0100;
|
||||
|
||||
switch (pin) {
|
||||
// case 9 and 10 taken care of above by if()
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
// Timer4
|
||||
TCCR4A = (TCCR4A & B11111100) | abits; // set WGM0 and WGM1
|
||||
TCCR4B = (TCCR4B & B11100000) | bbits; // set WGM2 and WGM3 and divisor
|
||||
//DIAG(F("Timer 4 A=%x B=%x"), TCCR4A, TCCR4B);
|
||||
break;
|
||||
case 46:
|
||||
case 45:
|
||||
case 44:
|
||||
// Timer5
|
||||
TCCR5A = (TCCR5A & B11111100) | abits; // set WGM0 and WGM1
|
||||
TCCR5B = (TCCR5B & B11100000) | bbits; // set WGM2 and WGM3 and divisor
|
||||
//DIAG(F("Timer 5 A=%x B=%x"), TCCR5A, TCCR5B);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
||||
#define NUM_ADC_INPUTS 16
|
||||
#else
|
||||
|
|
|
@ -151,10 +151,26 @@ void DCCTimer::reset() {
|
|||
ESP.restart();
|
||||
}
|
||||
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) {
|
||||
if (f >= 16)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, f);
|
||||
else if (f == 7)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 62500);
|
||||
else if (f >= 4)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 32000);
|
||||
else if (f >= 3)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 16000);
|
||||
else if (f >= 2)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3400);
|
||||
else if (f == 1)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 480);
|
||||
else
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 131);
|
||||
}
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
|
||||
#ifdef SOC_LEDC_SUPPORT_HS_MODE
|
||||
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1)
|
||||
#else
|
||||
|
@ -164,7 +180,7 @@ void DCCTimer::reset() {
|
|||
static int8_t pin_to_channel[SOC_GPIO_PIN_COUNT] = { 0 };
|
||||
static int cnt_channel = LEDC_CHANNELS;
|
||||
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency) {
|
||||
void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency) {
|
||||
if (pin < SOC_GPIO_PIN_COUNT) {
|
||||
if (pin_to_channel[pin] != 0) {
|
||||
ledcSetup(pin_to_channel[pin], frequency, 8);
|
||||
|
|
|
@ -134,6 +134,11 @@ void DCCTimer::reset() {
|
|||
while(true){}
|
||||
}
|
||||
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) {
|
||||
}
|
||||
void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t fbits) {
|
||||
}
|
||||
|
||||
int16_t ADCee::ADCmax() {
|
||||
return 4095;
|
||||
}
|
||||
|
|
|
@ -165,6 +165,11 @@ void DCCTimer::reset() {
|
|||
while(true) {};
|
||||
}
|
||||
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) {
|
||||
}
|
||||
void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t fbits) {
|
||||
}
|
||||
|
||||
#define NUM_ADC_INPUTS NUM_ANALOG_INPUTS
|
||||
|
||||
uint16_t ADCee::usedpins = 0;
|
||||
|
|
|
@ -266,6 +266,23 @@ void DCCTimer::reset() {
|
|||
while(true) {};
|
||||
}
|
||||
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) {
|
||||
if (f >= 16)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, f);
|
||||
else if (f == 7)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 62500);
|
||||
else if (f >= 4)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 32000);
|
||||
else if (f >= 3)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 16000);
|
||||
else if (f >= 2)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3400);
|
||||
else if (f == 1)
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 480);
|
||||
else
|
||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 131);
|
||||
}
|
||||
|
||||
// TODO: rationalise the size of these... could really use sparse arrays etc.
|
||||
static HardwareTimer * pin_timer[100] = {0};
|
||||
static uint32_t channel_frequency[100] = {0};
|
||||
|
@ -276,7 +293,7 @@ static uint32_t pin_channel[100] = {0};
|
|||
// sophisticated about detecting any clash between the timer we'd like to use for PWM and the ones
|
||||
// currently used for HA so they don't interfere with one another. For now we'll just make PWM
|
||||
// work well... then work backwards to integrate with HA mode if we can.
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency)
|
||||
void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency)
|
||||
{
|
||||
if (pin_timer[pin] == NULL) {
|
||||
// Automatically retrieve TIM instance and channel associated to pin
|
||||
|
|
|
@ -150,6 +150,11 @@ void DCCTimer::reset() {
|
|||
SCB_AIRCR = 0x05FA0004;
|
||||
}
|
||||
|
||||
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) {
|
||||
}
|
||||
void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t fbits) {
|
||||
}
|
||||
|
||||
int16_t ADCee::ADCmax() {
|
||||
return 4095;
|
||||
}
|
||||
|
|
43
EXRAIL2.cpp
43
EXRAIL2.cpp
|
@ -669,6 +669,45 @@ void RMFT2::loop2() {
|
|||
}
|
||||
break;
|
||||
|
||||
case OPCODE_SETFREQ:
|
||||
// Frequency is default 0, or 1, 2,3
|
||||
//if (loco) DCC::setFn(loco,operand,true);
|
||||
switch (operand) {
|
||||
case 0: // default - all F-s off
|
||||
if (loco) {
|
||||
DCC::setFn(loco,29,false);
|
||||
DCC::setFn(loco,30,false);
|
||||
DCC::setFn(loco,31,false);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (loco) {
|
||||
DCC::setFn(loco,29,true);
|
||||
DCC::setFn(loco,30,false);
|
||||
DCC::setFn(loco,31,false);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (loco) {
|
||||
DCC::setFn(loco,29,false);
|
||||
DCC::setFn(loco,30,true);
|
||||
DCC::setFn(loco,31,false);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (loco) {
|
||||
DCC::setFn(loco,29,false);
|
||||
DCC::setFn(loco,30,false);
|
||||
DCC::setFn(loco,31,true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
; // do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_RESUME:
|
||||
pausingTask=NULL;
|
||||
driveLoco(speedo);
|
||||
|
@ -1295,6 +1334,7 @@ void RMFT2::thrungeString(uint32_t strfar, thrunger mode, byte id) {
|
|||
break;
|
||||
case thrunge_parse:
|
||||
case thrunge_broadcast:
|
||||
case thrunge_message:
|
||||
case thrunge_lcd:
|
||||
default: // thrunge_lcd+1, ...
|
||||
if (!buffer) buffer=new StringBuffer();
|
||||
|
@ -1332,6 +1372,9 @@ void RMFT2::thrungeString(uint32_t strfar, thrunger mode, byte id) {
|
|||
case thrunge_withrottle:
|
||||
CommandDistributor::broadcastRaw(CommandDistributor::WITHROTTLE_TYPE,buffer->getString());
|
||||
break;
|
||||
case thrunge_message:
|
||||
CommandDistributor::broadcastMessage(buffer->getString());
|
||||
break;
|
||||
case thrunge_lcd:
|
||||
LCD(id,F("%s"),buffer->getString());
|
||||
break;
|
||||
|
|
|
@ -51,7 +51,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
|||
OPCODE_JOIN,OPCODE_UNJOIN,OPCODE_READ_LOCO1,OPCODE_READ_LOCO2,
|
||||
#endif
|
||||
OPCODE_POM,
|
||||
OPCODE_START,OPCODE_SETLOCO,OPCODE_SENDLOCO,OPCODE_FORGET,
|
||||
OPCODE_START,OPCODE_SETLOCO,OPCODE_SETFREQ,OPCODE_SENDLOCO,OPCODE_FORGET,
|
||||
OPCODE_PAUSE, OPCODE_RESUME,OPCODE_POWEROFF,OPCODE_POWERON,
|
||||
OPCODE_ONCLOSE, OPCODE_ONTHROW, OPCODE_SERVOTURNOUT, OPCODE_PINTURNOUT,
|
||||
OPCODE_PRINT,OPCODE_DCCACTIVATE,OPCODE_ASPECT,
|
||||
|
@ -94,7 +94,7 @@ enum thrunger: byte {
|
|||
thrunge_serial,thrunge_parse,
|
||||
thrunge_serial1, thrunge_serial2, thrunge_serial3,
|
||||
thrunge_serial4, thrunge_serial5, thrunge_serial6,
|
||||
thrunge_lcn,
|
||||
thrunge_lcn,thrunge_message,
|
||||
thrunge_lcd, // Must be last!!
|
||||
};
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
#undef LCCX
|
||||
#undef LCN
|
||||
#undef MOVETT
|
||||
#undef MESSAGE
|
||||
#undef ONACTIVATE
|
||||
#undef ONACTIVATEL
|
||||
#undef ONAMBER
|
||||
|
@ -156,6 +157,7 @@
|
|||
#undef SET_TRACK
|
||||
#undef SET_POWER
|
||||
#undef SETLOCO
|
||||
#undef SETFREQ
|
||||
#undef SIGNAL
|
||||
#undef SIGNALH
|
||||
#undef SPEED
|
||||
|
@ -252,6 +254,7 @@
|
|||
#define LCD(row,msg)
|
||||
#define SCREEN(display,row,msg)
|
||||
#define LCN(msg)
|
||||
#define MESSAGE(msg)
|
||||
#define MOVETT(id,steps,activity)
|
||||
#define ONACTIVATE(addr,subaddr)
|
||||
#define ONACTIVATEL(linear)
|
||||
|
@ -312,6 +315,7 @@
|
|||
#define SET_TRACK(track,mode)
|
||||
#define SET_POWER(track,onoff)
|
||||
#define SETLOCO(loco)
|
||||
#define SETFREQ(loco,freq)
|
||||
#define SIGNAL(redpin,amberpin,greenpin)
|
||||
#define SIGNALH(redpin,amberpin,greenpin)
|
||||
#define SPEED(speed)
|
||||
|
|
|
@ -95,14 +95,14 @@ 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 ) {
|
||||
constexpr bool hasseq(const int16_t value, const int16_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 ) {
|
||||
constexpr bool hasdup(const int16_t value, const int16_t pos ) {
|
||||
return pos>=stuffSize? false :
|
||||
compileTimeSequenceList[pos]==value
|
||||
|| hasseq(value,pos+1)
|
||||
|
@ -118,8 +118,8 @@ static_assert(!hasdup(compileTimeSequenceList[0],1),"Duplicate SEQUENCE/ROUTE/AU
|
|||
// This pass generates no runtime data or code
|
||||
#include "EXRAIL2MacroReset.h"
|
||||
#undef ASPECT
|
||||
#define ASPECT(address,value) static_assert((address & 0x7ff)== address, "invalid Address"); \
|
||||
static_assert((value & 0x1F)== value, "Invalid value");
|
||||
#define ASPECT(address,value) static_assert(address <=2044, "invalid Address"); \
|
||||
static_assert(address>=-3, "Invalid value");
|
||||
#undef CALL
|
||||
#define CALL(id) static_assert(hasseq(id),"Sequence not found");
|
||||
#undef FOLLOW
|
||||
|
@ -253,6 +253,9 @@ const int StringMacroTracker1=__COUNTER__;
|
|||
#define PRINT(msg) THRUNGE(msg,thrunge_print)
|
||||
#undef LCN
|
||||
#define LCN(msg) THRUNGE(msg,thrunge_lcn)
|
||||
#undef MESSAGE
|
||||
#define MESSAGE(msg) THRUNGE(msg,thrunge_message)
|
||||
|
||||
#undef ROUTE_CAPTION
|
||||
#define ROUTE_CAPTION(id,caption) \
|
||||
case (__COUNTER__ - StringMacroTracker1) : {\
|
||||
|
@ -350,6 +353,8 @@ const FSH * RMFT2::getTurntableDescription(int16_t turntableId) {
|
|||
#define TT_ADDPOSITION(turntable_id,position,value,home,description...) T_DESC(turntable_id,position,description)
|
||||
|
||||
const FSH * RMFT2::getTurntablePositionDescription(int16_t turntableId, uint8_t positionId) {
|
||||
(void)turntableId;
|
||||
(void)positionId;
|
||||
#include "myAutomation.h"
|
||||
return NULL;
|
||||
}
|
||||
|
@ -514,6 +519,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
|||
#define SCREEN(display,id,msg) PRINT(msg)
|
||||
#define STEALTH(code...) PRINT(dummy)
|
||||
#define LCN(msg) PRINT(msg)
|
||||
#define MESSAGE(msg) PRINT(msg)
|
||||
#define MOVETT(id,steps,activity) OPCODE_SERVO,V(id),OPCODE_PAD,V(steps),OPCODE_PAD,V(EXTurntable::activity),OPCODE_PAD,V(0),
|
||||
#define ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr),
|
||||
#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3),
|
||||
|
@ -581,6 +587,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
|||
#define SET_TRACK(track,mode) OPCODE_SET_TRACK,V(TRACK_MODE_##mode <<8 | TRACK_NUMBER_##track),
|
||||
#define SET_POWER(track,onoff) OPCODE_SET_POWER,V(TRACK_POWER_##onoff),OPCODE_PAD, V(TRACK_NUMBER_##track),
|
||||
#define SETLOCO(loco) OPCODE_SETLOCO,V(loco),
|
||||
#define SETFREQ(loco,freq) OPCODE_SETLOCO,V(loco), OPCODE_SETFREQ,V(freq),
|
||||
#define SIGNAL(redpin,amberpin,greenpin)
|
||||
#define SIGNALH(redpin,amberpin,greenpin)
|
||||
#define SPEED(speed) OPCODE_SPEED,V(speed),
|
||||
|
|
|
@ -1 +1 @@
|
|||
#define GITHUB_SHA "devel-202402171752Z"
|
||||
#define GITHUB_SHA "devel-202403182018Z"
|
||||
|
|
|
@ -83,6 +83,7 @@ void EXTurntable::_loop(unsigned long currentMicros) {
|
|||
// Read returns status as obtained in our loop.
|
||||
// Return false if our status value is invalid.
|
||||
int EXTurntable::_read(VPIN vpin) {
|
||||
(void)vpin; // surpress warning
|
||||
if (_deviceState == DEVSTATE_FAILED) return 0;
|
||||
if (_stepperStatus > 1) {
|
||||
return false;
|
||||
|
@ -127,6 +128,8 @@ void EXTurntable::_writeAnalogue(VPIN vpin, int value, uint8_t activity, uint16_
|
|||
vpin, value, activity, duration);
|
||||
DIAG(F("I2CManager write I2C Address:%d stepsMSB:%d stepsLSB:%d activity:%d"),
|
||||
_I2CAddress.toString(), stepsMSB, stepsLSB, activity);
|
||||
#else
|
||||
(void)duration;
|
||||
#endif
|
||||
if (activity < 4) _stepperStatus = 1; // Tell the device driver Turntable-EX is busy
|
||||
_previousStatus = _stepperStatus;
|
||||
|
|
104
MotorDriver.cpp
104
MotorDriver.cpp
|
@ -325,49 +325,23 @@ uint16_t taurustones[28] = { 165, 175, 196, 220,
|
|||
220, 196, 175, 165 };
|
||||
#endif
|
||||
#endif
|
||||
void MotorDriver::setDCSignal(byte speedcode) {
|
||||
void MotorDriver::setDCSignal(byte speedcode, uint8_t frequency /*default =0*/) {
|
||||
if (brakePin == UNUSED_PIN)
|
||||
return;
|
||||
switch(brakePin) {
|
||||
#if defined(ARDUINO_AVR_UNO)
|
||||
// Not worth doin something here as:
|
||||
// If we are on pin 9 or 10 we are on Timer1 and we can not touch Timer1 as that is our DCC source.
|
||||
// If we are on pin 5 or 6 we are on Timer 0 ad we can not touch Timer0 as that is millis() etc.
|
||||
// We are most likely not on pin 3 or 11 as no known motor shield has that as brake.
|
||||
#endif
|
||||
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
||||
case 9:
|
||||
case 10:
|
||||
// Timer2 (is differnet)
|
||||
TCCR2A = (TCCR2A & B11111100) | B00000001; // set WGM1=0 and WGM0=1 phase correct PWM
|
||||
TCCR2B = (TCCR2B & B11110000) | B00000110; // set WGM2=0 ; set divisor on timer 2 to 1/256 for 122.55Hz
|
||||
//DIAG(F("2 A=%x B=%x"), TCCR2A, TCCR2B);
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
// Timer4
|
||||
TCCR4A = (TCCR4A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for normal PWM 8-bit
|
||||
TCCR4B = (TCCR4B & B11100000) | B00000100; // set WGM2=0 and WGM3=0 for normal PWM 8 bit and div 1/256 for 122.55Hz
|
||||
break;
|
||||
case 46:
|
||||
case 45:
|
||||
case 44:
|
||||
// Timer5
|
||||
TCCR5A = (TCCR5A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for normal PWM 8-bit
|
||||
TCCR5B = (TCCR5B & B11100000) | B00000100; // set WGM2=0 and WGM3=0 for normal PWM 8 bit and div 1/256 for 122.55Hz
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// spedcoode is a dcc speed & direction
|
||||
byte tSpeed=speedcode & 0x7F; // DCC Speed with 0,1 stop and speed steps 2 to 127
|
||||
byte tDir=speedcode & 0x80;
|
||||
byte brake;
|
||||
|
||||
if (tSpeed <= 1) brake = 255;
|
||||
else if (tSpeed >= 127) brake = 0;
|
||||
else brake = 2 * (128-tSpeed);
|
||||
if (invertBrake)
|
||||
brake=255-brake;
|
||||
|
||||
{ // new block because of variable f
|
||||
#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32)
|
||||
{
|
||||
int f = 131;
|
||||
int f = frequency;
|
||||
#ifdef VARIABLE_TONES
|
||||
if (tSpeed > 2) {
|
||||
if (tSpeed <= 58) {
|
||||
|
@ -375,19 +349,15 @@ void MotorDriver::setDCSignal(byte speedcode) {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, f); // set DC PWM frequency to 100Hz XXX May move to setup
|
||||
}
|
||||
#endif
|
||||
if (tSpeed <= 1) brake = 255;
|
||||
else if (tSpeed >= 127) brake = 0;
|
||||
else brake = 2 * (128-tSpeed);
|
||||
if (invertBrake)
|
||||
brake=255-brake;
|
||||
#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32)
|
||||
//DIAG(F("Brake pin %d freqency %d"), brakePin, f);
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, f); // set DC PWM frequency
|
||||
DCCTimer::DCCEXanalogWrite(brakePin,brake);
|
||||
#else
|
||||
#else // all AVR here
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, frequency); // frequency steps
|
||||
analogWrite(brakePin,brake);
|
||||
#endif
|
||||
}
|
||||
|
||||
//DIAG(F("DCSignal %d"), speedcode);
|
||||
if (HAVE_PORTA(fastSignalPin.shadowinout == &PORTA)) {
|
||||
noInterrupts();
|
||||
|
@ -436,58 +406,26 @@ void MotorDriver::throttleInrush(bool on) {
|
|||
return;
|
||||
if ( !(trackMode & (TRACK_MODE_MAIN | TRACK_MODE_PROG | TRACK_MODE_EXT)))
|
||||
return;
|
||||
byte duty = on ? 208 : 0;
|
||||
byte duty = on ? 207 : 0; // duty of 81% at 62500Hz this gives pauses of 3usec
|
||||
if (invertBrake)
|
||||
duty = 255-duty;
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
if(on) {
|
||||
DCCTimer::DCCEXanalogWrite(brakePin,duty);
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, 62500);
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, 7); // 7 means max
|
||||
} else {
|
||||
ledcDetachPin(brakePin);
|
||||
}
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
if(on) {
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, 62500);
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, 7); // 7 means max
|
||||
DCCTimer::DCCEXanalogWrite(brakePin,duty);
|
||||
} else {
|
||||
pinMode(brakePin, OUTPUT);
|
||||
}
|
||||
#else
|
||||
#else // all AVR here
|
||||
if(on){
|
||||
switch(brakePin) {
|
||||
#if defined(ARDUINO_AVR_UNO)
|
||||
// Not worth doin something here as:
|
||||
// If we are on pin 9 or 10 we are on Timer1 and we can not touch Timer1 as that is our DCC source.
|
||||
// If we are on pin 5 or 6 we are on Timer 0 ad we can not touch Timer0 as that is millis() etc.
|
||||
// We are most likely not on pin 3 or 11 as no known motor shield has that as brake.
|
||||
#endif
|
||||
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
||||
case 9:
|
||||
case 10:
|
||||
// Timer2 (is different)
|
||||
TCCR2A = (TCCR2A & B11111100) | B00000011; // set WGM0=1 and WGM1=1 for fast PWM
|
||||
TCCR2B = (TCCR2B & B11110000) | B00000001; // set WGM2=0 and prescaler div=1 (max)
|
||||
DIAG(F("2 A=%x B=%x"), TCCR2A, TCCR2B);
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
// Timer4
|
||||
TCCR4A = (TCCR4A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for fast PWM 8-bit
|
||||
TCCR4B = (TCCR4B & B11100000) | B00001001; // set WGM2=1 and WGM3=0 for fast PWM 8 bit and div=1 (max)
|
||||
break;
|
||||
case 46:
|
||||
case 45:
|
||||
case 44:
|
||||
// Timer5
|
||||
TCCR5A = (TCCR5A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for fast PWM 8-bit
|
||||
TCCR5B = (TCCR5B & B11100000) | B00001001; // set WGM2=1 and WGM3=0 for fast PWM 8 bit and div=1 (max)
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, 7); // 7 means max
|
||||
}
|
||||
analogWrite(brakePin,duty);
|
||||
#endif
|
||||
|
|
|
@ -34,9 +34,15 @@ template<class T> inline T operator| (T a, T b) { return (T)((int)a | (int)b); }
|
|||
template<class T> inline T operator& (T a, T b) { return (T)((int)a & (int)b); }
|
||||
template<class T> inline T operator^ (T a, T b) { return (T)((int)a ^ (int)b); }
|
||||
enum TRACK_MODE : byte {TRACK_MODE_NONE = 1, TRACK_MODE_MAIN = 2, TRACK_MODE_PROG = 4,
|
||||
TRACK_MODE_DC = 8, TRACK_MODE_EXT = 16, TRACK_MODE_BOOST = 32,
|
||||
TRACK_MODE_ALL = 62, // only to operate all tracks
|
||||
TRACK_MODE_INV = 64, TRACK_MODE_DCX = 72 /*DC + INV*/, TRACK_MODE_AUTOINV = 128};
|
||||
TRACK_MODE_DC = 8, TRACK_MODE_EXT = 16,
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
TRACK_MODE_BOOST = 32,
|
||||
#else
|
||||
TRACK_MODE_BOOST = 0,
|
||||
#endif
|
||||
TRACK_MODE_ALL = TRACK_MODE_MAIN|TRACK_MODE_PROG|TRACK_MODE_DC|TRACK_MODE_EXT|TRACK_MODE_BOOST,
|
||||
TRACK_MODE_INV = 64,
|
||||
TRACK_MODE_DCX = TRACK_MODE_DC|TRACK_MODE_INV, TRACK_MODE_AUTOINV = 128};
|
||||
|
||||
#define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH
|
||||
#define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW
|
||||
|
@ -187,7 +193,7 @@ class MotorDriver {
|
|||
}
|
||||
};
|
||||
inline pinpair getSignalPin() { return pinpair(signalPin,signalPin2); };
|
||||
void setDCSignal(byte speedByte);
|
||||
void setDCSignal(byte speedByte, uint8_t frequency=0);
|
||||
void throttleInrush(bool on);
|
||||
inline void detachDCSignal() {
|
||||
#if defined(__arm__)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* © 2022-2023 Paul M. Antoine
|
||||
* © 2021 Fred Decker
|
||||
* © 2020-2023 Harald Barth
|
||||
* © 2020-2024 Harald Barth
|
||||
* (c) 2020 Chris Harlow. All rights reserved.
|
||||
* (c) 2021 Fred Decker. All rights reserved.
|
||||
* (c) 2020 Harald Barth. All rights reserved.
|
||||
|
@ -57,6 +57,10 @@
|
|||
// of the brake pin on the motor bridge is inverted
|
||||
// (HIGH == release brake)
|
||||
|
||||
// You can have a CS wihout any possibility to do any track signal.
|
||||
// That's strange but possible.
|
||||
#define NO_SHIELD F("No shield at all")
|
||||
|
||||
// Arduino STANDARD Motor Shield, used on different architectures:
|
||||
|
||||
#if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* © 2022 Chris Harlow
|
||||
* © 2022,2023 Harald Barth
|
||||
* © 2022-2024 Harald Barth
|
||||
* © 2023 Colin Murdoch
|
||||
* All rights reserved.
|
||||
*
|
||||
|
@ -19,6 +19,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "defines.h"
|
||||
#include "TrackManager.h"
|
||||
#include "FSH.h"
|
||||
#include "DCCWaveform.h"
|
||||
|
@ -40,7 +41,7 @@
|
|||
MotorDriver * TrackManager::track[MAX_TRACKS];
|
||||
int16_t TrackManager::trackDCAddr[MAX_TRACKS];
|
||||
|
||||
byte TrackManager::lastTrack=0;
|
||||
int8_t TrackManager::lastTrack=-1;
|
||||
bool TrackManager::progTrackSyncMain=false;
|
||||
bool TrackManager::progTrackBoosted=false;
|
||||
int16_t TrackManager::joinRelay=UNUSED_PIN;
|
||||
|
@ -182,7 +183,7 @@ void TrackManager::setDCSignal(int16_t cab, byte speedbyte) {
|
|||
FOR_EACH_TRACK(t) {
|
||||
if (trackDCAddr[t]!=cab && cab != 0) continue;
|
||||
if (track[t]->getMode() & TRACK_MODE_DC)
|
||||
track[t]->setDCSignal(speedbyte);
|
||||
track[t]->setDCSignal(speedbyte, DCC::getThrottleFrequency(trackDCAddr[t]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,7 +219,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
|||
if (mode & TRACK_MODE_BOOST) {
|
||||
//DIAG(F("Track=%c mode boost pin %d"),trackToSet+'A', p.pin);
|
||||
pinMode(BOOSTER_INPUT, INPUT);
|
||||
gpio_matrix_in(26, SIG_IN_FUNC228_IDX, false); //pads 224 to 228 available as loopback
|
||||
gpio_matrix_in(BOOSTER_INPUT, SIG_IN_FUNC228_IDX, false); //pads 224 to 228 available as loopback
|
||||
gpio_matrix_out(p.pin, SIG_IN_FUNC228_IDX, false, false);
|
||||
if (p.invpin != UNUSED_PIN) {
|
||||
gpio_matrix_out(p.invpin, SIG_IN_FUNC228_IDX, true /*inverted*/, false);
|
||||
|
@ -328,8 +329,8 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
|||
}
|
||||
|
||||
void TrackManager::applyDCSpeed(byte t) {
|
||||
uint8_t speedByte=DCC::getThrottleSpeedByte(trackDCAddr[t]);
|
||||
track[t]->setDCSignal(speedByte);
|
||||
track[t]->setDCSignal(DCC::getThrottleSpeedByte(trackDCAddr[t]),
|
||||
DCC::getThrottleFrequency(trackDCAddr[t]));
|
||||
}
|
||||
|
||||
bool TrackManager::parseEqualSign(Print *stream, int16_t params, int16_t p[])
|
||||
|
@ -361,7 +362,8 @@ bool TrackManager::parseEqualSign(Print *stream, int16_t params, int16_t p[])
|
|||
if (params==2 && p[1]=="EXT"_hk) // <= id EXT>
|
||||
return setTrackMode(p[0],TRACK_MODE_EXT);
|
||||
#ifdef BOOSTER_INPUT
|
||||
if (params==2 && p[1]=="BOOST"_hk) // <= id BOOST>
|
||||
if (TRACK_MODE_BOOST != 0 && // compile time optimization
|
||||
params==2 && p[1]=="BOOST"_hk) // <= id BOOST>
|
||||
return setTrackMode(p[0],TRACK_MODE_BOOST);
|
||||
#endif
|
||||
if (params==2 && p[1]=="AUTO"_hk) // <= id AUTO>
|
||||
|
@ -400,11 +402,11 @@ const FSH* TrackManager::getModeName(TRACK_MODE tm) {
|
|||
modename=F("EXT");
|
||||
else if(tm & TRACK_MODE_BOOST) {
|
||||
if(tm & TRACK_MODE_AUTOINV)
|
||||
modename=F("B A");
|
||||
modename=F("BOOST A");
|
||||
else if (tm & TRACK_MODE_INV)
|
||||
modename=F("B I");
|
||||
modename=F("BOOST I");
|
||||
else
|
||||
modename=F("B");
|
||||
modename=F("BOOST");
|
||||
}
|
||||
else if (tm & TRACK_MODE_DC) {
|
||||
if (tm & TRACK_MODE_INV)
|
||||
|
@ -497,6 +499,10 @@ void TrackManager::setTrackPower(TRACK_MODE trackmodeToMatch, POWERMODE powermod
|
|||
// Set track power for this track, inependent of mode
|
||||
void TrackManager::setTrackPower(POWERMODE powermode, byte t) {
|
||||
MotorDriver *driver=track[t];
|
||||
if (driver == NULL) { // track is not defined at all
|
||||
DIAG(F("Error: Track %c does not exist"), t+'A');
|
||||
return;
|
||||
}
|
||||
TRACK_MODE trackmode = driver->getMode();
|
||||
POWERMODE oldpower = driver->getPower();
|
||||
if (trackmode & TRACK_MODE_NONE) {
|
||||
|
@ -554,14 +560,17 @@ bool TrackManager::getPower(byte t, char s[]) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
void TrackManager::reportObsoleteCurrent(Print* stream) {
|
||||
// This function is for backward JMRI compatibility only
|
||||
// It reports the first track only, as main, regardless of track settings.
|
||||
// <c MeterName value C/V unit min max res warn>
|
||||
#ifdef HAS_ENOUGH_MEMORY
|
||||
int maxCurrent=track[0]->raw2mA(track[0]->getRawCurrentTripValue());
|
||||
StringFormatter::send(stream, F("<c CurrentMAIN %d C Milli 0 %d 1 %d>\n"),
|
||||
track[0]->raw2mA(track[0]->getCurrentRaw(false)), maxCurrent, maxCurrent);
|
||||
#else
|
||||
(void)stream;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackManager::reportCurrent(Print* stream) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* © 2022 Chris Harlow
|
||||
* © 2022 Harald Barth
|
||||
* © 2022-2024 Harald Barth
|
||||
* © 2023 Colin Murdoch
|
||||
*
|
||||
* All rights reserved.
|
||||
|
@ -46,7 +46,7 @@ const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
|||
class TrackManager {
|
||||
public:
|
||||
static void Setup(const FSH * shieldName,
|
||||
MotorDriver * track0,
|
||||
MotorDriver * track0=NULL,
|
||||
MotorDriver * track1=NULL,
|
||||
MotorDriver * track2=NULL,
|
||||
MotorDriver * track3=NULL,
|
||||
|
@ -108,7 +108,7 @@ class TrackManager {
|
|||
|
||||
private:
|
||||
static void addTrack(byte t, MotorDriver* driver);
|
||||
static byte lastTrack;
|
||||
static int8_t lastTrack;
|
||||
static byte nextCycleTrack;
|
||||
static void applyDCSpeed(byte t);
|
||||
|
||||
|
|
|
@ -247,8 +247,9 @@ DCCTurntable::DCCTurntable(uint16_t id) : Turntable(id, TURNTABLE_DCC) {}
|
|||
StringFormatter::send(stream, F("<i %d DCCTURNTABLE>\n"), _turntableData.id);
|
||||
}
|
||||
|
||||
// EX-Turntable specific code for moving to the specified position
|
||||
bool DCCTurntable::setPositionInternal(uint8_t position, uint8_t activity) {
|
||||
// EX-Turntable specific code for moving to the specified position
|
||||
bool DCCTurntable::setPositionInternal(uint8_t position, uint8_t activity) {
|
||||
(void) activity;
|
||||
#ifndef IO_NO_HAL
|
||||
int16_t value = getPositionValue(position);
|
||||
if (position == 0 || !value) return false; // Return false if it's not a valid position
|
||||
|
@ -263,6 +264,6 @@ DCCTurntable::DCCTurntable(uint16_t id) : Turntable(id, TURNTABLE_DCC) {}
|
|||
(void)position;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -571,7 +571,7 @@ void WiThrottle::sendRoutes(Print* stream) {
|
|||
|
||||
void WiThrottle::sendFunctions(Print* stream, byte loco) {
|
||||
int16_t locoid=myLocos[loco].cab;
|
||||
int fkeys=29;
|
||||
int fkeys=32; // upper limit (send functions 0 to 31)
|
||||
myLocos[loco].functionToggles=1<<2; // F2 (HORN) is a non-toggle
|
||||
|
||||
#ifdef EXRAIL_ACTIVE
|
||||
|
@ -621,7 +621,7 @@ void WiThrottle::sendFunctions(Print* stream, byte loco) {
|
|||
#endif
|
||||
|
||||
for(int fKey=0; fKey<fkeys; fKey++) {
|
||||
int fstate=DCC::getFn(locoid,fKey);
|
||||
int8_t fstate=DCC::getFn(locoid,fKey);
|
||||
if (fstate>=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),myLocos[loco].throttle,LorS(locoid),locoid,fstate,fKey);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,13 @@
|
|||
|
||||
#include "StringFormatter.h"
|
||||
|
||||
#define VERSION "5.2.35"
|
||||
#define VERSION "5.2.40"
|
||||
// 5.2.40 - Allow no shield
|
||||
// 5.2.39 - Functions for DC frequency: Use func up to F31
|
||||
// 5.2.38 - Exrail MESSAGE("text") to send a user message to all
|
||||
// connected throttles (uses <m "text"> and withrottle Hmtext.
|
||||
// 5.2.37 - Bugfix ESP32: Use BOOSTER_INPUT define
|
||||
// 5.2.36 - Variable frequency for DC mode
|
||||
// 5.2.35 - Bugfix: Make DCC Extended Accessories follow RCN-213
|
||||
// 5.2.34 - <A address aspect> Command fopr DCC Extended Accessories
|
||||
// - Exrail ASPECT(address,aspect) for above.
|
||||
|
|
Loading…
Reference in New Issue
Block a user