Git Product home page Git Product logo

nmradcc's Introduction

NmraDcc

NMRA Digital Command Control (DCC) Library

This library allows you to interface to a NMRA DCC track signal and receive DCC commands.

The library currently supports the AVR ATTiny84/85 & ATMega88/168/328/32u4 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.

Warning as of version 1.4.4 support has been removed for the following two call-back functions, which will cause your sketch to silently stop working:

extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State )
extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State) 

Developers: Use of the supplied git pre-commit hook is encouraged. This will require installation of the 'astyle' package for formatting source file. See http://astyle.sourceforge.net for details on this package.

On Linux or Mac development machines, run the following command after you clone the repository:

   ln -s support/pre-commit .git/hooks/pre-commit

Reformatting the source code to the preferred style is easy using astyle. Just run 'astyle --options=.astylerc NmraDcc.h NmraDcc.cpp'

nmradcc's People

Contributors

bobjacobsen avatar frightrisk avatar gbglacier avatar jueff avatar kiwi64ajs avatar littleyoda avatar m1118 avatar per1234 avatar roelandkluit avatar trusty77 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nmradcc's Issues

DCCInterface_TurntableControl question

I have a very big interest in this example. My hardware is a bit different though. I have my dcc interface going to my arduino uno, along with a TB6600 stepper motor driver. When I load the sketch for this, and open the serial monitor. I can see that the arduino is getting the dcc responses. However mo stepper is not moving. I can feel that it's on. It just doesnt move. Ideas?

ESP32 uses SPIEEPROM to store CVs

I understand ESP32's NMRADCC to write CVs to a flash block, I'm worried that frequent reads and writes will drastically shorten the RAM life. For this, I would like to be able to create an external EEPROM storage space for storing CVs via SPI
How does this require adjusting the code?

ESP32 build error

I try to build an ESP32 DCC based on NMRADCC, it seems that there are some problems in the interrupt definition part, how should I solve it?

src\NmraDcc.cpp: In function 'void ExternalInterruptHandler()':
src\NmraDcc.cpp:369:26: warning: unused variable 'DCC_IrqRunning' [-Wunused-variable]
static byte halfBit, DCC_IrqRunning, preambleBitCount;
^
src\motor_ctrl.cpp: In function 'int MOTOR_GetBEMF()':
src\motor_ctrl.cpp:367:15: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
aAve = aAve + analogRead(MOTOR_READ) >> 2;
^
src\motor_ctrl.cpp:388:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^

notifyDccAccTurnoutOutput() is for when CV29_OUTPUT_ADDRESS_MODE *IS* set?

notifyDccAccTurnoutBoard() and notifyDccAccTurnoutOutput() both seem to have the same cut and pasted comments. Shouldn't the former be for when CV29_OUTPUT_ADDRESS_MODE is 0 and the latter for when it is 1 (set)? I can't link I guess without being a member of this repo, but it is this PR: #53

NmraDcc/NmraDcc.h

Lines 523 to 527 in 681b362

* notifyDccAccTurnoutOutput() Output oriented callback for a turnout accessory decoder.
* Most useful when CV29_OUTPUT_ADDRESS_MODE is not set.
* Decoders of this type have 4 paired turnout outputs per board.
* OutputPower is 1 if the power is on, and 0 otherwise.
*

Wrong LEDs inNmraDccMultiFunctionMotorDecoder

There an error is in NmraDccMultiFunctionMotorDecoder, lines 295-296

It should be

  digitalWrite(LED_PIN_FWD, newDirection ? HIGH : LOW);
  digitalWrite(LED_PIN_REV, newDirection ? LOW : HIGH);

instead of

  digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
  digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);

Forward corresponds to newDirection == HIGH.

ESP32 version stops working when loosing interrupts or signal is bad

sometimes ESP32 runs into the problem, that no DCC data are processed anymore.

I found out that in error state we have

  • DccRx.State = WAIT_PREAMBLE
  • ISRLevel = 0
  • ISRWatch = 1

so this code
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && digitalRead( DccProcState.ExtIntPinNum ) != (ISRLevel) ) ) {
will always detect a short bit, because when interrupt filter is RISING the ExtIntPinNum will never be 0.
This fault situation needs a reboot.

It seems that the problems comes from this code

#ifdef ESP32
	ISRWatch = ISREdge;
#else
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
// enable level checking ( with direct port reading @ AVR )
ISRChkMask = DccProcState.ExtIntMask;       
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
#endif

because ISRChkMask and ISRLevel are not set correctly (in ESP32 case)

The fixed code could look like this - but maybe it's not the only location where levels aren't set correctly.

#ifdef ESP32
    ISRWatch = ISREdge;
#else
    attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
#endif
// enable level checking ( with direct port reading @ AVR )
ISRChkMask = DccProcState.ExtIntMask;       
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;

Any way to help?

Have used the library somewhat on and off for experiments.
Added functions, fixed some things, debugged others. Nothing major.

Want to know if you guys/gals need any help with the code? or if there is any way I can help.

Performance of NmraDcc on Arduino Nano Every (and other new ATMega processors)

Hello

I'm experimenting with some new ATMega processors (4808, 4809, 128DA), originally for my own DCC decoding libraries (still following the OpenDecoder approach of using a timer) but 9as comparison and check) also with the NmraDcc library.

The good news is that the NmraDcc library compiles and runs on the Nano Every. However, like my own decoding library, performance on these new processors turns out to be considerably slower than that on the 328. There are several reasons for that, the most important one being the overhead created by attachInterrupt(). On the UNO is takes roughly 3,5 microseconds after the pin change until the "user code" within the ISR starts. On the Nano Every this time is twice as long, around 7 microseconds 9depending if the standard Arduino boards of the MegaCoreX is used). See also my earlier post in the Arduino forum: https://forum.arduino.cc/t/difference-in-time-between-interrupt-start-on-mega-2560-and-nano-every-4809/897591/15
Unfortunately, not only attachInterrupt() is considerably slower, but also micros() (you can find several discussions of that in the various fora).

My question is therefore whether others observe the same performance problems of NmraDcc on these new ATMega processors. I understand that the NmraDcc library will run on lightly loaded Nano Every boards, but I'm running into problems if I include (my own) RS_Bus feedback library. Also the RS-Bus raises an Interrupt roughly every 100 microseconds, and two of these libraries together don't work reliably.

For my own DCC decoder library I decided to make a drastic change, and add some of the new features that these new 480X and 128DA processors offer. Basically I connect the DCC input signal to the Event system, which triggers a timer as output. This saves me the (overhead of the) DCC input ISR, and the timer gives me a very stable reading of the DCC signal.

I would be interested in what others think of this.

Aiko

More than one locomotive / function decoder address

Hallo,,
is there a possibility that you can use more than one locomotive address. e.g. Address 100 is configured, the second address is then address 101 and possibly a third one with address 102 etc.

Thanks for your Info.

Olaf

Is the AdvancedCVAck version something to be pulled into master?

Hello. What is the difference between the two branches? Can you tell me how you are doing the ACK? What function is creating a current draw or is it only for Railcom where some piece of hardware does this? A standard Arduino had no ability to generate a 60mA pulse that I know of so for a decoder not attached to other hardware, have you thought of a way to send an ACK?

How to Use Curve (Speed Table)

I want the multi-function decoder to support a 28-step speedometer, so I store 28 steps of speed values in CV67 to CV94, and set value 16 in CV29.
I noticed that the void notifyDccSpeed() function is used to define a specific speedometer value. But there is no such setting in any of the examples, so I'm not sure about it.
Is it understood like this:

void notifyDccSpeed(uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps)
{
uint16_t aSpeedRef = 0;

if (Speed >= 1)
{
aSpeedRef = Dcc.getCV(67+Speed-1);
}
else
{

#ifdef DCC_DEBUG
Serial.println("***** Emagency STOP **** ");
#endif
aSpeedRef = 0;
}
.........

Another: I looked at a lot of documentation on CV29(Bit 4), and it was all about CV25. But I don't understand that CV25 is associated with the curve table. Please advise.

Failed to process DCC data

I use ESP32 as the decoder. IDF architecture +Arduino components. DCC++ EX for command station, and UART serial port for command input monitoring.
I plugged the decoder into the PROG track and tried to respond to the ACK using the motor drive (motor works fine)

` void notifyCVAck(void)

{ ESP_LOGI(LOGTAG_DCC, "notifyCVAck");

MOTOR_Ack();

}

void MOTOR_Ack(void)
{
ledcWrite(MOTOR_PWM_CH_B, 0);
ledcWrite(MOTOR_PWM_CH_A, 240); vTaskDelay(6 / portTICK_PERIOD_MS);
ledcWrite(MOTOR_PWM_CH_A, 0);

}
`
No response, no output from ESP_LOG

I tried to read the DCC package again:

`void notifyDccMsg(DCC_MSG *Msg)
{
ESP_LOG_BUFFER_HEXDUMP("DCC_MSG",Msg->Data,Msg->Size,ESP_LOG_INFO);

}
`

Power on PROG (EX command<1>), with result:

I (165159) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165169) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165179) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165189) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165199) DCC_MSG: 0x3ffb2e22 ff 00 ff |...|

Feel like NMRA DCC can receive DCC signal, but can't process it, or am I wrong? Please advise.

ESP32 support

After successfully running the Accessory test program that is part of the library I started using the code in a larger program. It started crashing as soon as the DCC signal was present, which pointed my look closer into the ISR.

In the process I think I have discovered some problems with the ISR:
a) for ESP32, it should be compiled with the IRAM_ATTR attribute like this: void IRAM_ATTR ExternalInterruptHandler(void)
For more information see here: https://techtutorialsx.com/2017/09/30/esp32-arduino-external-interrupts/
and here: espressif/arduino-esp32#489

b) I also added the MUX line: portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; and secured the access to the shard data in the ISR and the process routing:
portENTER_CRITICAL_ISR(&mux); DccRx.PacketCopy = DccRx.PacketBuf ; DccRx.DataReady = 1 ; portEXIT_CRITICAL_ISR(&mux);

Unfortunately, while all this is good, it was still crashing as soon as my program tried to access the file system (SPIFFS), eg. for loading config files or a serving a web page.

c) It turns out the real problem is the reattachment of interrupts within the IRS. As soon as I commented those lines out, the program stopped crashing, but unfortunately, it would no longer decode the DCC signals. So I found a workaround and defined a variable ISRWatch which holds the type of interrupt to look for, either falling, raising, or change. Then I replaced all attach interrupt functions by just changing the content of the ISRWatch variable and changed the attacheinterrupt call in the init function to CHANGE. Finally, I added a filter to the beginning of the ISR where I would check the type of interrupt and either return or proceed:

void IRAM_ATTR ExternalInterruptHandler(void)
{
switch (ISRWatch)
{
case CHANGE: break;
case RISING: if (digitalRead(DccProcState.ExtIntPinNum)) break;
case FALLING: if (digitalRead(DccProcState.ExtIntPinNum)) return; break;
}

In this quick fix I did not care about support for other processors etc. So maybe someone with good knowledge of the entire could make the proper adjustments so it works with all processors.

ESP8266 and ExternalInterruptHandler

Hi

testing my framework for a esp8266, I found three problems in ExternalInterruptHandler.
Because I'm not sure how to fix the problems platform independent, I have not created a Pull Request.

  1. All Functions called by an interrupt must be declared as ICACHE_RAM_ATTR

=>
ICACHE_RAM_ATTR void ExternalInterruptHandler(void)

  1. millis()
    millis() return a unsigned long on esp8226 and esp32. lastMicros, actMicros and bitMicros are currently declared as word/unsigned int. For the esp8266 and esp32 unsigend long is necessary,

static word lastMicros;
unsigned int actMicros, bitMicros;

=>

static unsigned long lastMicros = 0;
unsigned long actMicros, bitMicros;

Programming an accessory decoder from the command track

I'll start with a description of the situation as I see it - NmraDCC's documentation is sparse, so I had to "learn" from the examples.

Unlike multifunction decoders, it seems that accessory decoders are not supposed to be programmed via the command track. I found that using the FLAGS_DCC_ACCESSORY_DECODER flag tells NmraDCC not to change the CVs on the command track and to ignore CV1, CV9, CV17 and CV18.

However, there is a loophole: two additional CVs can be defined and given as an argument during initialization, so that an accessory decoder can also be programmed on the command track. However, most likely you want to have the same decoder address on both the programming and command track, which means that the same address is in three places: CV1/CV9, CV17/DV18, and additional CV pair. (You also need to put the address in CV17/DV18 so that the DCC controller can communicate with it as a virtual multifunction decoder).

Is what I have written so far correct?

This is a very clumsy solution. I know that by default the accessory decoder should ignore CV change requests on the command track. But it would be easier to control this directly from CV17/CV18. If those two values are 0x00 (or 0xC0 and 0x00), the decoder should ignore changes to CV, while the NmraDCC library should listen to CV change requests if those two values would specify a viable address.

Best regards

ESP32 motor pwm

Hello,
Is it possible to have a multifuctionmotordecoder example working with ESP32
thanks

NMRADCC on Attiny85 stops working over time

Hi. i'm using the NmraDCC lib. on an Attiny85 (tried several different Attiny85 boards), to control 2 relays as a reverse loop module. I'm using the turnout function of the NmraDCC lib. and it works flawlessly for like an hour, where after the module stops responding to the DCC commands (it may stop all commands / codehandling im not sure). A powercycle of the Attiny85, solves the problem, again for some time. As a quick powercycle helps, I don't think it's a heat issue. As mentioned I have tried several types om presoldered/preassembled Attiny85 boards and the result is the same. Has any of You experienced anything similar ? Is there a way of maybe resetting the Attiny85 codewise like every 30 min, or maybe every time the relays have been switched off ? (i know this is not elegant).
I think the Attiny85 has a perfect formfactor and handling cap. for a reverse loop module, so would really like to stay on this small platform.

ESP8266, exception and wdt reset

Hello,

I'm trying to run this library on ESP8266 which is stated to be compatible, but I get errors.

I've hooked up the DCC signal on D3 pin and uploaded the example "NmraDccMultiFunctionDecoder_1", after changing DCC_PIN to D3.

The sketch is working, I see the speed and function changes displayed in the serial monitor, but as soon as I try to send a write CV from the MultiMaus, I get an exception : " ets Jan 8 2013,rst cause:2, boot mode:(3,6)".

Then I tried "NmraDccMultiFunctionMotorDecoder" example, uncommented the DEBUG defines and defined the DCC_PIN to D3 (and LED and MOTOR pins even if nothing is hooked up on the physical pins).

Uploaded this sketch and I constantly get wdt reset errors in the serial monitor followed by the line "NMRA Dcc Multifunction Motor Decoder Demo" :
ets Jan 8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 3584, room 16
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
NMRA Dcc Multifunction Motor Decoder Demo

This error shows even when DCC signal is turned off.

Can someone point me out why this happens?

Cant get runing on RP2040 (Pi Pico)

Hello i trying to get it runing on My Pi Pico. i head read a fiew times "ARDUINO_ARCH_RP2040" so i thinked it wud work. but as i uploaded my simple sniffer sketch it just output "Sniffer Start". and dhat's it.
I tried also on an Arduino Nano and it worked.

#include <NmraDcc.h>
#define DCC_PIN   2
#define DCC_DECODER_VERSION_NUM 11  // Set the Decoder Version - Used by JMRI to Identify the decoder
NmraDcc  Dcc ;
DCC_MSG  Packet ;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Dcc.pin(0, DCC_PIN, 1);
  Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM,  FLAGS_DCC_ACCESSORY_DECODER , 0 );
  while (!Serial) {

  }
  Serial.println("Sniffer Start");

}

void loop() {
  // put your main code here, to run repeatedly:
  Dcc.process();
}
void notifyDccMsg( DCC_MSG * Msg)
{
  Serial.print("notifyDccMsg: ") ;
  for (uint8_t i = 0; i < Msg->Size; i++)
  {
    Serial.print(Msg->Data[i], HEX);
    Serial.write(' ');
  }
  Serial.println();
}

On the Hardware side i used bridge rectifier for Ground and a voltage devider that converts the rail voltage to 3.3V clamped with a zener diode and feed it through an schmittrigger. than into my Controller.

Can somone help me pleas?

Signal decoder save state to EEPROM

Hi,

I'm building my own signal (as in railway signal) decoder using your library. For this to work correctly, I need to persist the signal state to EEPROM, so that signals still show the same value after a reboot.

Hence, I have two questions:

  1. How do I best store the state? Do I use the CV library or are there EEPROM addresses I can mess with myself such that the library is not impacted?
  2. Does DCC specify (and your library support) a shutdown command? (This would be useful to have fewer write cycles and only persist at shutdown time, instead of multiple times throughout the operation)

Thanks!

using library without EEPROM

I'm trying to use an Adafruit Metro M0 (ARM Cortex M0 SAMD21blah based), and this device's Arduino library does not provide the EEPROM interface.

I've noodled up a generic CV database interface, and written one implementation that uses EEPROM and another that uses a file within the local filesystem (since I've got more than just N NMRA DCC CVs to store for my persistence needs).

My first plan was to set this up as a required reference argument to the NmraDcc constructor, and then use the generic interfaces within the NmraDcc code. This could probably even be done without a user sketch code change, where the NmraDcc() constructor would create an EEPROM object, and the NmraDccc(NmraCVDB &) constructor would allow the user to provide their own.

However, in putting the pieces together, I find that parts of the NmraDcc module are member functions within the object, and other parts are just standalone functions (which don't have access to the object internals).

Is there a fundamental reason for this separation of code between methods and functions?

Would you be interested in changes that move the "external" functions inside of the NmraDcc class, which would also permit the "externalization" of the EEPROM interface?

Alternately, I could try to rig this up using a separate standalone CV DB class, but that's doing even more to limit this code to only ever supporting a single DCC interface (which I think is already the case). And I think these changes would do more to break all existing code (or more specifically, require additions to existing sketches to add the declaration of the EEPROM (or other) based CV DB object.

Accessory decoder changes incompatible to previous versions

Hi Alex,
I detected, that the actual version 1.4.4 is no longer compatible to previous releases regarding the accessory decoder. The callback functions changed, and the old one is no longer available. Now sketches don't work anymore without any error message.
Is this really intended to be so?

Regards
Franz-Peter

Does the Case in switch(CV) not require a break?

I am compiling in EPS-IDF environment and mentioned a warning

D:/Esp-Doc/ESP-decoder/components/NmraDcc/NmraDcc.cpp: In function 'uint8_t writeCV(uint16_t, uint8_t)': D:/Esp-Doc/ESP-decoder/components/NmraDcc/NmraDcc.cpp:616:28: warning: this statement may fall through [-Wimplicit-fallthrough=] DccProcState.Flags = (DccProcState.Flags & ~FLAGS_CV29_BITS) | (Value & FLAGS_CV29_BITS); ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ D:/Esp-Doc/ESP-decoder/components/NmraDcc/NmraDcc.cpp:618:5: note: here case CV_ACCESSORY_DECODER_ADDRESS_LSB: // Also same CV for CV_MULTIFUNCTION_PRIMARY_ADDRESS

I found that there is no "break" at the end of each case of switch (CV). Is this intentional? Is there a problem if we do not deal with this warning?

Address Incorrect?

Hi there,

the library works awesome and I love it. I managed to build my turnout controller using it.

The only issue I am facing is that the address seem to be interpreted incorrectly.

If I use my Roco 10764 Base Station with multiMouse and send accessory enable / disable to an address. Then by sniffing within notifyDccAccState method by printing out the Addr (as DEC), I am getting values lower by 4 ... for example sending the command to Addr 5 prints out Addr=1, etc.

I can certainly fix it by adding 4 to it, but I would rather have this sorted out at the library level.

Any idea?

Thanks in advance!

Need a hand

I've tried running the various examples with no luck at all. I don't have an oscilloscope, so I can't be quite sure that I'm actually getting a DCC signal to the Arduino. Any pointers?

GPL vs MIT license

Dear all,

I very much appreciate your work. This also why I took your driver and ported it in the NodeMCU Lua a Lua based interactive firmware for ESP8266, ESP8285 and ESP32. It has been merged already in the dev branch of the project. It works very well and I'm glad I can play with NMRA DCC in Lua.

However one of the senior developpers has recently raised an issue (#3025) pointing out that your code is distributed under GPL license. The NodeMCU Lua project is distributed under MIT license which I understand is a bit wider. Including GPL code would require the project to be under GPL which not something that is on the table.

Therefore I would like to ask you to consider relicensing your great project under MIT license ๐Ÿ™. It would allow spreading it further into the world ๐Ÿ˜„.

Thank you. Best regads,

[Question] About interrupts on an ATMega328

Hi,

Great library you all created. Thanks!

My question is, can I use other pins than the 'standard' one (D2 on the Arduino) for inputting a DCC signal. F.i. the ATMega328P has a max of 23 programmable I/O pins all with the possibility of making them generate an interrupt. Say I want to use PD6 as input; this pin generates PCINT22 which would generate a jump to the PCI2 vector (and back). Is this already implemented in the library?

Thanks for reading/answering this,
Willem.

notifyDccSigOutputState not called

I am using release JMRI 4.18 and DCC++ Basestation to generate Extended Accessory packets. With NmraDccAccessoryDecoder_1 example it appears that notifyDccSigOutputState is not called.

The JMRI seems to generate correct packet:

JMRI:
[TX: M 0 80 71 02 F3]   Write DCC Packet Main Cmd: 
  Register: 0
  Packet: 80 71 02 F3

The packet seems to be received just fine, except for the last byte (perhaps the checksum gets zeroed while checking). Number '5' in debug output is the received message length:

NMRA DCC Example 1
Init Done
notifyDccMsg: 5:80 71 2 F3 0 
notifyDccMsg: 5:80 71 2 F3 0 
notifyDccMsg: 5:80 71 2 F3 0

Yet the notifyDccSigOutputState is never called.

Support for Emulated Storage

I have a version where I ported the code to Seeed Studio XIAO. The XIAO only has emulated storage. I have implemented a conditional compile so the EEPROM code works for getting and setting CVs. Attached are files. I also made changes to FlashStorage.h so that the read operations would be very efficient. Other MCUs can be added using a similar technique.

FlashStorage.h.txt
NmraDcc.h.txt
NmraDcc.cpp.txt

platfromio 6.1.6 Add NMRADCC library No corresponding EEPROM library found

I developed NMRADCC based on EPS32 and added NMRADCC in Platfromio (version:2.0.15) library, but during compilation, it was discovered that the EEPROM library could not be found.
I found a lot of EEPROM related libraries in the PlatformIO library manager, and I 'm not sure which one to choose.

Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/denky_d4.html
PLATFORM: Espressif 32 (4.1.0) > Denky D4 (PICO-V3-02)
HARDWARE: ESP32 240MHz, 320KB RAM, 8MB Flash
DEBUG: Current (esp-prog) External (esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:

  • framework-arduinoespressif32 @ 3.20001.0 (2.0.1)
  • tool-esptoolpy @ 1.30100.210531 (3.1.0)
  • toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch3
    LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
    LDF Modes: Finder ~ chain, Compatibility ~ soft
    Found 32 compatible libraries
    Scanning dependencies...
    Dependency Graph
    |-- NmraDcc @ 2.0.15
    |-- SPIFFS @ 2.0.0
    | |-- FS @ 2.0.0
    |-- FS @ 2.0.0
    Building in release mode
    Compiling .pio\build\denky_d4\src\main.cpp.o
    Compiling .pio\build\denky_d4\lib2a9\NmraDcc\NmraDcc.cpp.o
    .pio/libdeps/denky_d4/NmraDcc/NmraDcc.cpp:53:10: fatal error: EEPROM.h: No such file or directory


#include "EEPROM.h"
^~~~~~~~~~
compilation terminated.
*** [.pio\build\denky_d4\lib2a9\NmraDcc\NmraDcc.cpp.o] Error 1

[Question] DCCFunc, DDCSpeed and DCCTurnout at the same time

For my project, I want to receive DDCFunc, DDCSpeed and DDCTurnout.

Depending on the Parameter for the Constructor, I got DCCFunc and DDCSpeed or just DDCTurnout.
But I wasn't able to receive all three information. Is there an way to accomplish this?

Pullup not enabled on ESP32

Enabling pullup for ExtIntPin fails with ESP32.
Seems that old way to enable pullup by writing a 1 to the port doesn't work with ESP.

Changed code from

  pinMode( ExtIntPinNum, INPUT );
  if( EnablePullup )
    digitalWrite(ExtIntPinNum, HIGH);

to
pinMode( ExtIntPinNum, EnablePullup ? INPUT_PULLUP : INPUT );

then it works.

Document CV29 output/board addressing mode

Your extension to CV29 could be better documented!

As far as I can see it just changes two things:

  1. The way the accessory address is computed
  2. Which accessory callback is used i.e. notifyDccAccTurnoutBoard or notifyDccAccTurnoutOutput

Neither of which is very clear - which mode should an accessory implementor use and why?

Hello, I saw this reply and was very happy to see that someone else was using a XIAO. I am trying to get this compiled using the files listed here, but I keep running the compiler telling me that the class FlashClass has no member named 'read_offset'. I have the Nmra files in the Nmra folder in libraries, and the FlashStorage file in the library for the XIAO. I did try loading the FlashStorage library and putting it there with no help. My appologies for the newb question, but we all gotta start somewhere. Thanks!

          I have a version where I ported the code to Seeed Studio XIAO.   I have implemented a conditional compile so the EEPROM code works for getting and setting CVs.    Attached are files.   I also made changes to FlashStorage.h so that the read operations would be very efficient.   The XIAO only has emulated storage.    If can be backwards compatible so only one library is needed.

NmraDcc.h.txt
NmraDcc.cpp.txt
FlashStorage.h.txt

Originally posted by @billswartz7 in #38 (comment)

Support for advanced consisting when FLAGS_MY_ADDRESS_ONLY is set

DCC supports a decoder having a temporary secondary "consist" address in CV 19.

Would it be reasonable for the FLAGS_MY_ADDRESS_ONLY check around NmraDcc.cpp:966 to also check against this consist address? You might need a new method similar to the existing getMyAddr() that looked at an extra cv19 field in the DccProcState.

use of esp8266: SPI_FLASH_SEC_SIZE not declared in this scope

Hello,

if I try to compile a sketch (e.g. one of the examples delivered with the lib) using the current release of the NmraDcc lib I get the following error message in the Arduino IDE:

Arduino: 1.6.12 (Windows 7), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 921600, 4M (3M SPIFFS)"
In file included from C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp:33:0:
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp: In function 'uint8_t validCV(uint16_t, uint8_t)':
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.h:94:21: error: 'SPI_FLASH_SEC_SIZE' was not declared in this scope
#define MAXCV SPI_FLASH_SEC_SIZE
^
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp:494:12: note: in expansion of macro 'MAXCV'
if( CV > MAXCV )
^
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp: In member function 'void NmraDcc::init(uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.h:94:21: error: 'SPI_FLASH_SEC_SIZE' was not declared in this scope
#define MAXCV SPI_FLASH_SEC_SIZE
^
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp:1015:18: note: in expansion of macro 'MAXCV'
EEPROM.begin(MAXCV);
^
exit status 1

Should this be defined somewhere in the nmradcc.cpp or nmradcc.h file? Or am I missing something else?

Thanks for any help

Error compiling sketch NmraDccAccessoryDecoder_1

I am using the Arduino IDE level 1.8.19 and trying to compile sketch named NmraDccAccessoryDecoder_1 from the Accessory folder of the NmraDcc-master library. The error is 'DEFAULT_ACCESSORY_DECODER_ADDRESS' was not declared in this scope
I get the a similar error compiling sketch NmraDccMultifunctionDecoder_1 'DEFAULT_MULTIFUNCTION_DECODER_ADDRESS' was not declared in this scope
I have not made any changes to either sketch. I have used them as distributed.

Can you please explain how to correct this error.

Thank you,
Dale Gloer

OPS mode programming for Accessory Decoder does not work for extended address, missing support?

I'm using this Wonderfull library to build out an accessory decoder for my layout. I wanted the ability to use OPS mode programming to change some of my custom defined CV's. I'm not sure if I really understand the NMRA standard for handing accessory addressing. It seem both NCE and JRMI systems use extended addressing.
At line 1409 there is this code....

	  else if(pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming
	  {
        DB_PRINT("eDP: OPS Mode CV Programming Command");
          // Check for unsupported OPS Mode Addressing mode
	  	if(((pDccMsg->Data[1] & 0b10001001) != 1) && ((pDccMsg->Data[1] & 0b10001111) != 0x80))
	  	{
          DB_PRINT("eDP: Unsupported OPS Mode CV Addressing Mode");
          return;
        }
        
          // Check if this command is for our address or the broadcast address
        if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE)
        {
          DB_PRINT("eDP: Check Output Address:%d", OutputAddress);
          if((OutputAddress != getMyAddr()) && ( OutputAddress < 2045 ))
          {
            DB_PRINT("eDP: Output Address Not Matched");
          	return;
          }
        }

Both NCE and JMRI seems to send extended addresses for OPS Accessory Decoder programing.
If I make the following changes it seems to work, but I'm not sure if I understand the addressing completely

	  else if(pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming                       
	  {
            DB_PRINT("eDP: OPS Mode CV Programming Command");
          // Check for unsupported OPS Mode Addressing mode     JMS seems like we dont support extended addr
	  	if((pDccMsg->Data[1] & 0b10001100) == 0b00001100)                    // JMS enabled extended addresses
	  	{
              myDB_PRINT("eDP: Unsupported OPS Mode CV Addressing Mode");                                   
          return;
        }
          // Check if this command is for our address or the broadcast address
        if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE)
        {
          //JMS new code to fix address if CDDD = 0
          if((pDccMsg->Data[1] & 0b10001111) == 0x80)                        // JMS NEW
          {                                                                                                      // JMS NEW
            OutputAddress = BoardAddress;                                              // JMS NEW
            DB_PRINT("eDP: Updated Address");                                      // JMS NEW
          }                                                                                                     // JMS NEW

Are my changes correct? I can only test with NCE and JMRI with SPROG but so far seems to work as expected.

Uno randomly stops while decoding DCC signal

I am using an Uno to decode the DCC signal using a custom shield, but my code will randomly stop working. This is pretty easy for me to tell, since I blink LEDs on the board as long as DCC packets are incoming. The DCC signal is routed through an isolator and then to D2 on the Uno. Even if there are no packets coming across(DCC is not plugged in) it still seems to randomly stop after a few seconds.

Is there something to look at in order to debug this?

Resetting the decoder

On resetting the decoder, CV8 -> 8, notifyCVResetFactoryDefault() is triggered seven times. It is probably not a good idea for EEPROM to be rewritten too many times.

As a patch, I used if (FactoryDefaultCVIndex == 0) in front of FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);

This reduces seven EEPROM writes to "only" three.

I am using PiSPROG DCC controller/programmer and ATmega328.

Best regards!

SMB Examples drop packets

Hi,
I found out, that the SMB Examples lose packets. The reason is that the Dcc.process() function isn't called often enough.
The Dcc.process() function must be called at least once for every received packet. A DCC accessory packet may be around 6ms long ( including the preamble ). Therefore the Dcc.process() must be called more than once every 6ms. Because of the delay(8) in the loop of the examples this is not possible.

Normally this will not be apparent, because the central station repeats the packets several times.
But I think especially the examples should be programmed to not lose packets under normal conditions.

Question: Can DCC reading be paused temporarily?

(It feels a bit awkward to ask questions in GitHub. If there is a better place, please let me know.)

I'm trying to build a turn-out decoder with an ATTiny85. I couldn't find a servo library that doesn't interfere with NmraDcc. So I decided to create the pulses in the code. However, while there is a DCC signal on the tracks, the servo becomes jittery. I guess that is because the interrupt has more priority than the delayMicroseconds() function. So, i thought about turning DCC reading off while the servo is moving. My idea basically is:

  1. Read DCC
  2. When a packet with the correct address is received, turn of DCC reading
  3. Perform action that requires precise timing (like controlling a servo)
  4. When action has finished, turn back on DCC reading.

I'm aware that I would miss packets during the time DCC reading is turned off, but I don't have a need to switch turn-outs in quick succession.

So, is there a way to disable DCC reading termporarily? Or is there another way to get jitterless servo control?

This is the code I'm currently using, which disables the pulse after switching so that the servo stops trembling. It works, but it would be nice if I could move the servo slowly and steadily:

#include "NmraDcc.h"
NmraDcc  Dcc ;
DCC_MSG  Packet ;

const int adresse = 25; 

const int LED = 4;
const int relay = 3;
const int servo = 1;
int pos = 90;
unsigned long last_update;
unsigned long now;

void servo_pulse(int pin, int pos){
  int pulse = map(pos,0, 180, 850, 2050);
  digitalWrite(pin, HIGH);
  delayMicroseconds(pulse);
  digitalWrite(pin, LOW);
  delay(20);
}

void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
{ 
  switch(Addr){
    case adresse:
      if(Direction < 1){
        digitalWrite(LED, LOW);
        digitalWrite(relay, LOW);
        pos = 65;
      }else{
        digitalWrite(LED, HIGH);
        digitalWrite(relay, HIGH);
        pos = 115;
      }
      last_update = millis();
      break;
      default:
      break;
  }
}

void setup()
{
  Dcc.pin(0, 2, 1);
  Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
  pinMode(LED, OUTPUT);
  pinMode(relay, OUTPUT);
  pinMode(servo, OUTPUT);
}

void loop()
{
  Dcc.process();
  now = millis();
  if ((now - last_update) < 65){
    servo_pulse(servo, pos);
  } 
}

Hello is there a way to use and enter more than 28 functions?

Hello is there a way to use and enter more than 28 functions?

I would like to use more than the currently available functions 28 for a sound module, according to the RCN-212 DCC protocol
Operating commands for vehicle decoders Edition 01.12.2019 R
http://normen.railcommunity.de/RCN-212.pdf
Can be used max F68.
2.3.4 Function control F13-F68
These commands are two bytes long and have the following formats:
๏‚ท Function control F13-F20: 1101-1110 DDDD-DDDD
๏‚ท Function control F21-F28: 1101-1111 DDDD-DDDD
๏‚ท Function control F29-F36: 1101-1000 DDDD-DDDD
๏‚ท Function control F37-F44: 1101-1001 DDDD-DDDD
๏‚ท Function control F45-F52: 1101-1010 DDDD-DDDD
๏‚ท Function control F53-F60: 1101-1011 DDDD-DDDD
๏‚ท Function control F61-F68: 1101-1100 DDDD-DDDD

Is there any way to extend it?

Thank you for an info

Olaf Reis

Example files/testing

I have been been looking into various DCC options for accessory signal/turnout control & would like to see if I can get an Arduino to do this. From what I have read etc. it all looks possible but I cannot make sense of the example files I have download so can someone provide some info on what will work?

I have looked at the 'NmraDccAccessoryDecoder_1' file which I presume works with no modification, would be nice to find some more explanation on what sections/code does what if there is such a thing anywhere?

Also is there any way of outputting the DCC signal from a Arduino without a motor shield to test or is the signal not true enough to DCC?

Thanks

Reading of CV values does not work

Hi Alex,
I open a new issue, so we can discuss the acknowledgement problem here separately.
As I wrote already, with the actual version of 'master' reading of CV values in servicemode is no longer possible.

Some further thoughts to RailCom - as it is defined in NMRA S-9.3.2.
RailCom is a really big extension to standard DCC. It is far more than an 'advanced acknowledge'.
Bit 3 in CV29 should be named as what it really is: CV29_RailCom_ENABLE . If this bit is set in CV29 the decoder must conform to NMRA S-9.3.2 . I don't think you can build such a decoder with the lib so far. I am even not sure if it is possible with an AVR UNO/Nano at all. The timing in the RailCom cutout ist quite critical. In my opinion you need a free HW UART and maybe a HW Timer too. We should inhibit setting this bit.

With a standard Decoder (without RailCom) and programming in ops mode (POM) there is no acknowledgement at all. Programming in system mode requires the 6ms current pulse as acknowlegement. The most easiest way to accomplish this is to call notifyCVAck() only if we are in servicemode. I implemented this in my fork of the lib and can make a pull request if you agree with this solution.

Running NmraDcc on ESP8266

According to the Arduino IDE, when installing NmraDcc, the package supports ESP8266. Now trying to run on an ESP8266, Lolin Wemos D1R2, we fail to get any DCC messages decoded. The program and shield works fine on an UNO. Can you assist?

Question: How to electrically connect DCC pin to tracks

Hello,
I am new to DCC world, but do enjoy programming microcontrollers to control trains and track accessories. However, I do not know how to connect the signal pin of the Arduino to the tracks (e.g. where the ground and the pin input go and if there are any electrical components needed). I saw a schematic on-line that involved a resistor and and a diode, but I am not sure if that is universally applicable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.