Skip to content

Commit

Permalink
Servo signal (DCC-EX#227)
Browse files Browse the repository at this point in the history
Prepping for version 4.1

SERVO_SIGNAL definition in EXRAIL
SERVO_SIGNAL(vpin, redpos, amberpos, greenpos)

use RED/AMBER/GREEN as for led signals.

* SIGNALH, ATGTE, ATLT

UNTESTED

* Automatic ALIAS(name)

and _ in keywords

* EXRAIL FORGET current loco

* EXRAIL </KILL ALL>

* EXRAIL VIRTUAL_TURNOUT

* Cleanup version.h

* Update version.h (DCC-EX#223)

Rewrite & Updated the 4.0.0 Section

* </KILL ALL> fix

* Incoming LCN turnout throw.

* KILLALL macro

and DIAGNOSTIC messages when KILL command used.

* EXRAIL PARSE

* Rebuild throttle info getters

UNTESTED... create different methods to obtain throttle info without being withrottle specific.

Also implements turnout description of "*" as hidden.

* J command parsing

JA JR JT commands parsed
EXRAIL sets hidden turnout state
HIDDEN description macro
Turnouts hidden flag bit
UNO seems OK, MEGA UNTESTED

* Assist notes draft & syntax tweaks

* Throttle notes

* uno memory saver

* JA JR and <t cab>

* Subtle corrections

* Update version.h

* I2C code corrections

Corrections to I2C code:
1) I2CManager_Mega4809.h: Correct bitwise 'and' to logical 'and' - no impact.
2) I2CManager_Wire.h: Ensure that error codes from Wire subsystem are passed back to caller in queueRequest().

* RAG Ifs and cmds

* IF block perf/memory

* Allow negative route ids.

* correct GREEN keyword

* Update version.h

* myFilter auto detect

* Update version.h

* fix weak ref to myFilter

* ACK defaults now 50-2000-20000

* Update version.h

* Improved SIGNALs startup and diagnostics

* Update IO_PCA9685.cpp

* Allow turnout id 0

* Position servo pin used as GPIO

* NoPowerOff LEDS

* CALLBACK parameter optional for Write

* WRITE CV ON PROG <W CV VALUE>

Callback parameters are now optional on PROG

* Updated CV read command <R cv>

Equivalent to <V cv 0>  uses the verify callback.

Co-authored-by: Asbelos <[email protected]>
Co-authored-by: Kcsmith0708 <[email protected]>
Co-authored-by: Neil McKechnie <[email protected]>
Co-authored-by: Ash-4 <[email protected]>
  • Loading branch information
5 people authored May 3, 2022
1 parent 0ab3fe0 commit 977802f
Show file tree
Hide file tree
Showing 17 changed files with 633 additions and 204 deletions.
5 changes: 4 additions & 1 deletion DCC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -647,14 +647,17 @@ byte DCC::cv2(int cv) {
return lowByte(cv);
}

int DCC::lookupSpeedTable(int locoId) {
int DCC::lookupSpeedTable(int locoId, bool autoCreate) {
// determine speed reg for this loco
int firstEmpty = MAX_LOCOS;
int reg;
for (reg = 0; reg < MAX_LOCOS; reg++) {
if (speedTable[reg].loco == locoId) break;
if (speedTable[reg].loco == 0 && firstEmpty == MAX_LOCOS) firstEmpty = reg;
}

// return -1 if not found and not auto creating
if (reg== MAX_LOCOS && !autoCreate) return -1;
if (reg == MAX_LOCOS) reg = firstEmpty;
if (reg >= MAX_LOCOS) {
DIAG(F("Too many locos"));
Expand Down
5 changes: 2 additions & 3 deletions DCC.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ class DCC
static void forgetLoco(int cab); // removes any speed reminders for this loco
static void forgetAllLocos(); // removes all speed reminders
static void displayCabList(Print *stream);

static FSH *getMotorShieldName();
static inline void setGlobalSpeedsteps(byte s) {
globalSpeedsteps = s;
Expand All @@ -148,7 +147,8 @@ class DCC
unsigned long functions;
};
static LOCO speedTable[MAX_LOCOS];

static int lookupSpeedTable(int locoId, bool autoCreate=true);

private:
static byte joinRelay;
static byte loopStatus;
Expand All @@ -162,7 +162,6 @@ class DCC

static byte cv1(byte opcode, int cv);
static byte cv2(int cv);
static int lookupSpeedTable(int locoId);
static void issueReminders();
static void callback(int value);

Expand Down
123 changes: 115 additions & 8 deletions DCCEXParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "CommandDistributor.h"
#include "EEStore.h"
#include "DIAG.h"
#include "EXRAIL2.h"
#include <avr/wdt.h>

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -74,8 +75,10 @@ const int16_t HASH_KEYWORD_SPEED28 = -17064;
const int16_t HASH_KEYWORD_SPEED128 = 25816;
const int16_t HASH_KEYWORD_SERVO=27709;
const int16_t HASH_KEYWORD_VPIN=-415;
const int16_t HASH_KEYWORD_C=67;
const int16_t HASH_KEYWORD_T=84;
const int16_t HASH_KEYWORD_A='A';
const int16_t HASH_KEYWORD_C='C';
const int16_t HASH_KEYWORD_R='R';
const int16_t HASH_KEYWORD_T='T';
const int16_t HASH_KEYWORD_LCN = 15137;
const int16_t HASH_KEYWORD_HAL = 10853;
const int16_t HASH_KEYWORD_SHOW = -21309;
Expand All @@ -91,7 +94,7 @@ Print *DCCEXParser::stashStream = NULL;
RingStream *DCCEXParser::stashRingStream = NULL;
byte DCCEXParser::stashTarget=0;

// This is a JMRI command parser, one instance per incoming stream
// This is a JMRI command parser.
// It doesnt know how the string got here, nor how it gets back.
// It knows nothing about hardware or tracks... it just parses strings and
// calls the corresponding DCC api.
Expand Down Expand Up @@ -145,7 +148,7 @@ int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte
runningValue = 16 * runningValue + (hot - 'A' + 10);
break;
}
if (hot >= 'A' && hot <= 'Z')
if (hot=='_' || (hot >= 'A' && hot <= 'Z'))
{
// Since JMRI got modified to send keywords in some rare cases, we need this
// Super Kluge to turn keywords into a hash value that can be recognised later
Expand All @@ -162,9 +165,12 @@ int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte
return parameterCount;
}

FILTER_CALLBACK DCCEXParser::filterCallback = 0;
extern __attribute__((weak)) void myFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]);
FILTER_CALLBACK DCCEXParser::filterCallback = myFilter;
FILTER_CALLBACK DCCEXParser::filterRMFTCallback = 0;
AT_COMMAND_CALLBACK DCCEXParser::atCommandCallback = 0;

// deprecated
void DCCEXParser::setFilter(FILTER_CALLBACK filter)
{
filterCallback = filter;
Expand Down Expand Up @@ -214,10 +220,23 @@ void DCCEXParser::parse(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 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);
}
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>
cab = p[1];
Expand Down Expand Up @@ -333,7 +352,9 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
break;
if (params == 1) // <W id> Write new loco id (clearing consist and managing short/long)
DCC::setLocoId(p[0],callback_Wloco);
else // WRITE CV ON PROG <W CV VALUE [CALLBACKNUM] [CALLBACKSUB]>
else if (params == 4) // WRITE CV ON PROG <W CV VALUE [CALLBACKNUM] [CALLBACKSUB]>
DCC::writeCVByte(p[0], p[1], callback_W4);
else // WRITE CV ON PROG <W CV VALUE>
DCC::writeCVByte(p[0], p[1], callback_W);
return;

Expand Down Expand Up @@ -361,6 +382,13 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
return;

case 'R': // READ CV ON PROG
if (params == 1)
{ // <R CV> -- uses verify callback
if (!stashCallback(stream, p, ringStream))
break;
DCC::verifyCVByte(p[0], p[1], callback_Vbyte);
return;
}
if (params == 3)
{ // <R CV CALLBACKNUM CALLBACKSUB>
if (!stashCallback(stream, p, ringStream))
Expand Down Expand Up @@ -500,6 +528,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
DCC::setFn(p[0], p[1], p[2] == 1);
return;

#if WIFI_ON
case '+': // Complex Wifi interface command (not usual parse)
if (atCommandCallback && !ringStream) {
DCCWaveform::mainTrack.setPowerMode(POWERMODE::OFF);
Expand All @@ -508,6 +537,69 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
return;
}
break;
#endif

case 'J' : // throttle info access
{
if ((params<1) | (params>2)) break; // <J>
int16_t id=(params==2)?p[1]:0;
switch(p[0]) {
case HASH_KEYWORD_A: // <JA> returns automations/routes
StringFormatter::send(stream, F("<jA"));
if (params==1) {// <JA>
#ifdef EXRAIL_ACTIVE
sendFlashList(stream,RMFT2::routeIdList);
sendFlashList(stream,RMFT2::automationIdList);
#endif
}
else { // <JA id>
StringFormatter::send(stream,F(" %d %c \"%S\""),
id,
#ifdef EXRAIL_ACTIVE
RMFT2::getRouteType(id), // A/R
RMFT2::getRouteDescription(id)
#else
'X',F("")
#endif
);
}
StringFormatter::send(stream, F(">\n"));
return;
case HASH_KEYWORD_R: // <JR> returns rosters
StringFormatter::send(stream, F("<jR"));
#ifdef EXRAIL_ACTIVE
if (params==1) sendFlashList(stream,RMFT2::rosterIdList);
else StringFormatter::send(stream,F(" %d \"%S\" \"%S\""),
id, RMFT2::getRosterName(id), RMFT2::getRosterFunctions(id));
#endif
StringFormatter::send(stream, F(">\n"));
return;
case HASH_KEYWORD_T: // <JT> returns turnout list
StringFormatter::send(stream, F("<jT"));
if (params==1) { // <JT>
for ( Turnout * t=Turnout::first(); t; t=t->next()) {
if (t->isHidden()) continue;
StringFormatter::send(stream, F(" %d"),t->getId());
}
}
else { // <JT id>
Turnout * t=Turnout::get(id);
if (!t || t->isHidden()) StringFormatter::send(stream, F(" %d X"),id);
else StringFormatter::send(stream, F(" %d %c \"%S\""),
id,t->isThrown()?'T':'C',
#ifdef EXRAIL_ACTIVE
RMFT2::getTurnoutDescription(id)
#else
F("")
#endif
);
}
StringFormatter::send(stream, F(">\n"));
return;
default: break;
} // switch(p[1])
break; // case J
}

default: //anything else will diagnose and drop out to <X>
DIAG(F("Opcode=%c params=%d"), opcode, params);
Expand All @@ -521,6 +613,14 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
StringFormatter::send(stream, F("<X>\n"));
}

void DCCEXParser::sendFlashList(Print * stream,const int16_t flashList[]) {
for (int16_t i=0;;i++) {
int16_t value=GETFLASHW(flashList+i);
if (value==0) return;
StringFormatter::send(stream,F(" %d"),value);
}
}

bool DCCEXParser::parseZ(Print *stream, int16_t params, int16_t p[])
{

Expand Down Expand Up @@ -856,7 +956,14 @@ void DCCEXParser::commitAsyncReplyStream() {
void DCCEXParser::callback_W(int16_t result)
{
StringFormatter::send(getAsyncReplyStream(),
F("<r%d|%d|%d %d>\n"), stashP[2], stashP[3], stashP[0], result == 1 ? stashP[1] : -1);
F("<r %d %d>\n"), stashP[0], result == 1 ? stashP[1] : -1);
commitAsyncReplyStream();
}

void DCCEXParser::callback_W4(int16_t result)
{
StringFormatter::send(getAsyncReplyStream(),
F("<r%d|%d|%d %d>\n"), stashP[2], stashP[3], stashP[0], result == 1 ? stashP[1] : -1);
commitAsyncReplyStream();
}

Expand Down
2 changes: 2 additions & 0 deletions DCCEXParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct DCCEXParser
static int16_t stashP[MAX_COMMAND_PARAMS];
static bool stashCallback(Print * stream, int16_t p[MAX_COMMAND_PARAMS], RingStream * ringStream);
static void callback_W(int16_t result);
static void callback_W4(int16_t result);
static void callback_B(int16_t result);
static void callback_R(int16_t result);
static void callback_Rloco(int16_t result);
Expand All @@ -70,6 +71,7 @@ struct DCCEXParser
static FILTER_CALLBACK filterRMFTCallback;
static AT_COMMAND_CALLBACK atCommandCallback;
static void funcmap(int16_t cab, byte value, byte fstart, byte fstop);
static void sendFlashList(Print * stream,const int16_t flashList[]);

};

Expand Down
6 changes: 3 additions & 3 deletions DCCWaveform.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,16 @@ class DCCWaveform {
volatile bool ackPending;
volatile bool ackDetected;
int ackThreshold;
int ackLimitmA = 60;
int ackLimitmA = 50;
int ackMaxCurrent;
unsigned long ackCheckStart; // millis
unsigned int ackCheckDuration; // millis

unsigned int ackPulseDuration; // micros
unsigned long ackPulseStart; // micros

unsigned int minAckPulseDuration = 4000; // micros
unsigned int maxAckPulseDuration = 8500; // micros
unsigned int minAckPulseDuration = 2000; // micros
unsigned int maxAckPulseDuration = 20000; // micros

volatile static uint8_t numAckGaps;
volatile static uint8_t numAckSamples;
Expand Down
Loading

0 comments on commit 977802f

Please sign in to comment.