Skip to content

Commit

Permalink
Compile success for Decoder (not tested)
Browse files Browse the repository at this point in the history
  • Loading branch information
habazut committed Dec 30, 2024
1 parent b7fe953 commit b1f7af3
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 5 deletions.
18 changes: 13 additions & 5 deletions CommandStation-EX.ino
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
#include "DCCEX.h"
#include "Display_Implementation.h"
#include "Sniffer.h"
Sniffer *DCCSniffer = NULL;
#include "DCCDecoder.h"
Sniffer *dccSniffer = NULL;
DCCDecoder *dccDecoder = NULL;

#ifdef CPU_TYPE_ERROR
#error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH THE ARCHITECTURES LISTED IN defines.h
Expand Down Expand Up @@ -126,7 +128,8 @@ void setup()
// Start RMFT aka EX-RAIL (ignored if no automnation)
RMFT::begin();

DCCSniffer = new Sniffer(16);
dccSniffer = new Sniffer(16);
dccDecoder = new DCCDecoder();

// Invoke any DCC++EX commands in the form "SETUP("xxxx");"" found in optional file mySetup.h.
// This can be used to create turnouts, outputs, sensors etc. through the normal text commands.
Expand Down Expand Up @@ -168,15 +171,15 @@ void loopdiag(unsigned long timeout)
if (timeout != 0) {
unsigned long diff = now - lasttimestamp;
if (diff > timeout) {
if (DCCSniffer){
uint64_t val = DCCSniffer->getDebug();
if (dccSniffer){
uint64_t val = dccSniffer->getDebug();
int n = 64;
Serial.print("< ");
while (n--) {
Serial.print(val&(1ULL<<n)?"1":"0");
}
Serial.println(" >");
(DCCSniffer->fetchPacket()).print(Serial);
(dccSniffer->fetchPacket()).print(Serial);
}
lasttimestamp = millis();
return;
Expand All @@ -188,6 +191,11 @@ void loop()
{
// Some debug for sniffer code
loopdiag(937); // Do not use a value that does divide even in 80Mhz ticks
if (dccSniffer) {
DCCPacket d = dccSniffer->fetchPacket();
if (dccDecoder && d.len())
dccDecoder->parse(d);
}
digitalWrite(2,LOW);

// The main sketch has responsibilities during loop()
Expand Down
59 changes: 59 additions & 0 deletions DCCDecoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <Arduino.h>
#include "DCCPacket.h"
#include "LocoTable.h"

class DCCDecoder {
public:
DCCDecoder() {};
bool parse(DCCPacket p);
private:
};


bool DCCDecoder::parse(DCCPacket p) {
byte *d = p.data();
byte *instr = 0;
uint16_t addr;
bool locoInfoChanged = 0;
byte decoderType = 0; // use 0 as none
if (d[0] == 0B11111111) { // Idle packet
return false;
}
if (bitRead(d[0],7) == 0) { // bit7 == 0 => loco short addr
decoderType = 1;
instr = d+1;
addr = d[0];
} else {
if (bitRead(d[0],6) == 1) { // bit7 == 1 and bit6 == 1 => loco long addr
decoderType = 1;
instr = d+2;
addr = 256 * (d[0] & 0B00111111) + d[1];
}
}
if (decoderType == 1) {
switch (instr[0] & 0xE0) {
case 0x20: // 001x-xxxx Extended commands
if (instr[0] == 0B00111111) { // 128 speed steps
if ((locoInfoChanged = LocoTable::updateLoco(addr, instr[1])) == true) {
// send speed change to DCCEX here
}
}
break;
case 0x40: // 010x-xxxx Speed
case 0x60: // 011x-xxxx
if ((locoInfoChanged = LocoTable::updateLoco(addr, instr[0] & 0B00111111)) == true) {
// send speed change to DCCEX here
}
break;
case 0x80: // 100x-xxxx Function group 1
break;
case 0xA0: // 101x-xxxx Function group 3 and 2
break;
case 0xC0: // 110x-xxxx Extended
break;
case 0xE0: // 111x-xxxx Config vars
break;
}
}
return false;
}
130 changes: 130 additions & 0 deletions LocoTable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* Copyright (c) 2023 Harald Barth
*
* This source is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "LocoTable.h"

LocoTable::LOCO LocoTable::speedTable[MAX_LOCOS] = { {0,0,0,0,0,0} };
int LocoTable::highestUsedReg = 0;

int LocoTable::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"));
return -1;
}
if (reg==firstEmpty){
speedTable[reg].loco = locoId;
speedTable[reg].speedCode=128; // default direction forward
speedTable[reg].groupFlags=0;
speedTable[reg].functions=0;
}
if (reg > highestUsedReg) highestUsedReg = reg;
return reg;
}

// returns false only if loco existed but nothing was changed
bool LocoTable::updateLoco(int loco, byte speedCode) {
if (loco==0) {
/*
// broadcast stop/estop but dont change direction
for (int reg = 0; reg < highestUsedReg; reg++) {
if (speedTable[reg].loco==0) continue;
byte newspeed=(speedTable[reg].speedCode & 0x80) | (speedCode & 0x7f);
if (speedTable[reg].speedCode != newspeed) {
speedTable[reg].speedCode = newspeed;
CommandDistributor::broadcastLoco(reg);
}
}
*/
return true;
}

// determine speed reg for this loco
int reg=lookupSpeedTable(loco, false);
if (reg>=0) {
speedTable[reg].speedcounter++;
if (speedTable[reg].speedCode!=speedCode) {
speedTable[reg].speedCode = speedCode;
return true;
} else {
return false;
}
} else {
// new
reg=lookupSpeedTable(loco, true);
if(reg >=0) speedTable[reg].speedCode = speedCode;
return true;
}
}

bool LocoTable::updateFunc(int loco, byte func, int shift) {
unsigned long previous;
unsigned long newfunc;
bool retval = false; // nothing was touched
int reg = lookupSpeedTable(loco, false);
if (reg < 0) { // not found
retval = true;
reg = lookupSpeedTable(loco, true);
newfunc = previous = 0;
} else {
newfunc = previous = speedTable[reg].functions;
}

speedTable[reg].funccounter++;

if(shift == 1) { // special case for light
newfunc &= ~1UL;
newfunc |= ((func & 0B10000) >> 4);
}
newfunc &= ~(0B1111UL << shift);
newfunc |= ((func & 0B1111) << shift);

if (newfunc != previous) {
speedTable[reg].functions = newfunc;
retval = true;
}
return retval;
}

void LocoTable::dumpTable(Stream *output) {
output->print("\n-----------Table---------\n");
for (byte reg = 0; reg <= highestUsedReg; reg++) {
if (speedTable[reg].loco != 0) {
output->print(speedTable[reg].loco);
output->print(' ');
output->print(speedTable[reg].speedCode);
output->print(' ');
output->print(speedTable[reg].functions);
output->print(" #funcpacks:");
output->print(speedTable[reg].funccounter);
output->print(" #speedpacks:");
output->print(speedTable[reg].speedcounter);
speedTable[reg].funccounter = 0;
speedTable[reg].speedcounter = 0;
output->print('\n');
}
}
}
44 changes: 44 additions & 0 deletions LocoTable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* Copyright (c) 2023 Harald Barth
*
* This source is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>

#define MAX_LOCOS 128

class LocoTable {
public:
void forgetLoco(int cab) {
int reg=lookupSpeedTable(cab, false);
if (reg>=0) speedTable[reg].loco=0;
}
static int lookupSpeedTable(int locoId, bool autoCreate);
static bool updateLoco(int loco, byte speedCode);
static bool updateFunc(int loco, byte func, int shift);
static void dumpTable(Stream *output);

private:
struct LOCO
{
int loco;
byte speedCode;
byte groupFlags;
unsigned long functions;
unsigned int funccounter;
unsigned int speedcounter;
};
static LOCO speedTable[MAX_LOCOS];
static int highestUsedReg;
};
1 change: 1 addition & 0 deletions Sniffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Sniffer {
inline DCCPacket fetchPacket() {
noInterrupts();
DCCPacket d(dcclen, dccbytes);
dcclen = 0;
interrupts();
return d;
};
Expand Down

0 comments on commit b1f7af3

Please sign in to comment.