DCC++ EX Software Thread

David Cutting Apr 8, 2020

  1. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    58 by itself is not the address, it is 58,0,1 ... which is 229. 58,0,0 would be 228.

    The decoder would be 228-235 if the base address is set to 58,0.

    The address could never be 229 if it is 58,0,0. With the last bit of D being 0 it will always be even.

    It does :)

    If they follow the DCC spec then they will accept the packets just fine.

    There are 4096 decoder addresses allocated for accessories (0-4095, though all addresses above 4088 are reserved for broadcast). These map to the four groups of 512 having eight outputs each, which are typically used as four pairs of outputs. By convention the lowest order bit is used to select the A (even) or B (odd) output of the pair.

    I'd need to review the code again but it likely as simple as adding one to the address too early, it needs to be at the very end of the calculations. It may also be the case that he is not handling accessory decoder packets correctly.

    All correct on this part.
     
    KC Smith likes this.
  2. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    You also need to think of the JMRI side of this, they will need to special case the DCC++ logic to only send the C=0 packet to DCC++ when running the DCC++EX code base (make sure the <iDCC++ ...> header declares the code as the EX version).

    I would say add it to the <a ...> packet as a new option at the end that is optional and if they pass it then it should work for DCC++ and DCC++EX (verify this by sending <a 1 2 3 4> and make sure the DCC++ code handles it)
     
    KC Smith likes this.
  3. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    Re: I said, "Clearly DCC++ can't go over address 511

    Just t be clear, I was referring to Gregg's comments in the code:

    ADDRESS: the primary address of the decoder (0-511)
    SUBADDRESS: the subaddress of the decoder (0-3)
    ACTIVATE: 1=on (set), 0=off (clear)

    Note that many decoders and controllers combine the ADDRESS and SUBADDRESS into a single number, N,
    from 1 through a max of 2044,

    And if you test this, when you put in 511,3,1 (what I thought was the maximum packet value) you get this:

    10111111 10001111

    There isn't more room for any 1s ;) The 000 in the second by are 1s complemented so the maximum address of 9 bits is 111111111. That's 511. It's true if you make that a single part number, that is 2044. So 511 decoder addresses with 4 subaddresses. And this jives with what I just read in the DCC Wiki. But to complicate matters, it also says this:
    ---------------------------------------------------------------------
    You can have addresses from 1 to 2044. Each address location can control a pair of functions, usually either two solenoids for turnouts or two LEDs for signals.

    Different manufacturers view this range in one of two ways:

    1. ) 511 decoder addresses, each with 4 sub-addresses, or
    2. ) 2044 individual output addresses
    When configuring the decoder using the CV method, the NMRA defines two ways to set the address CVs:

    Decoder Address
    In this mode the decoder is configured with a 9-bit address which is considered to be the base address. The decoder can then have up to four pairs of outputs at this address.

    Output Address
    In this mode the decoder is configured with an 11-bit address which is considered to be the specific output pair address. The decoder may have only one output pair.
    ---------------------------------------------------------------------
    I take "may" in the above to mean "must only have" as opposed to "it could have more".

    This would seem to muddle things even more because that may explain what littleyoda was trying to do with Sigrok. He was adding bits together to take the 9 bit address and add the 2 subaddress bits. And THAT is how he got 233 for the address! So 233:1 in 11bit is the same as 58,0,1 in 9 bit address and 2 bit subaddress. But then what is 229,1 with the formula (N = (ADDRESS - 1) * 4 + SUBADDRESS + 1)? That is what we have been using, but I never saw how these formulas that go back and forth were derived.

    I don't know if we have to deal with that because the user would have to convert their decoder scheme. But to read this out properly, like in Sigrok, I can only see an option, like a checkbox, "use 11 bit addressing". Any more thoughts as to what, if anything, DCC++ needs to do to address what looks like 3 ways to do the same thing? I imagine that is why they have "learning" decoders; to sort through the mess for you. As long as the decoder itself can read the same bits, maybe it doesn't matter how WE refer to them, but I would still like to know what I am doing ;)
     
    KC Smith and Atani like this.
  4. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Probably we can let jmri manage this mess and provide some helping clues for users in the web interface or via the console output

    Sent from my ONEPLUS A5010 using Tapatalk
     
  5. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    That would likely be correct but the spec should declare that definitively.

    This finally clears things up a bit on the addressing I think. We should likely make this explicit in the interface (protocol and/or web) so that the users know how to correctly define a turnout. The current interface follows only "Decoder Address" it would seem.

    One possibility is that a decoder could use the last bit of D to expose the individual outputs (two or eight outputs depending on address mode), but I don't know if there are any decoders coded specifically to this sort of thought.
     
    KC Smith likes this.
  6. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    Who do you think are the top 3 decoder manufacturers? I'll write and call them and ask them how to best support their products. That may help.
     
  7. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    As long as the packets conform to the spec it should be fine. I only know of one possible case where testing is going to be required and that is with the decoders put out by Geoff Bunza (https://github.com/mrrwa/NmraDcc/tree/master/examples/SMA) I haven't looked at how these expose more than 4 or 8 pairs of outputs but I suspect it uses N consecutive addresses (Output Address mode)
     
    KC Smith likes this.
  8. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    I have 3 of those, and just haven't soldered one up yet. I'll probably to that this weekend. I've talked to him. He is also aware of the 2 part addressing and is one of the reasons he doesn't like DCC++. But he doesn't use JMRI either, or at least not to run trains. He added CV control in later versions and I saw reference to using functions F0-F17, but these can be a mobile decoder or an accessory/stationary decoder, so I'll have to look at the addressing and report back.
     
    KC Smith and Atani like this.
  9. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    The two part addressing scheme is from the spec and not specific to DCC++ outside of that is what Gregg decided to expose as the addressing scheme for turnouts, of which I fully agree with Geoff that it is not ideal and as we have seen through this investigation causes a lot of headaches for users. If we can simplify this in any way it will greatly improve the chances of users not getting confused by setting up turnouts (which is usually a one time exercise, but still it should be easier!)
     
    KC Smith likes this.
  10. David Cutting

    David Cutting TrainBoard Member

    62
    29
    3
    What kind of support does JMRI have for railcom? I'd assume I would need to add some new messages to both DCC++ and to JMRI, but I could be totally wrong. I guess my question is what does the plumbing need to look like and what is already in place?
     
  11. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Depends on the CS connection type... if the CS supports it and exposes it via an API then JMRI should display it somewhere.

    However, in most cases RailCom is going to be exposed in only a couple areas:
    1. occupancy detection (channel 1)
    2. POM responses (channel 2)
    3. decoder status (channel 2)
    most of these are hidden behind the CS though and in the case of POM responses that may be exposed to JMRI as part of a POM response payload (ie: it worked, or it failed). DCC++ currently fires and forgets POM requests. In the case of a RailCom equipped CS it may respond to JMRI's POM request with a success/fail message.

    Now the occupancy part could be interesting but only for small layouts with DCC++ being the sole producer of DCC packets and no boosters, with boosters it gets slightly more complicated. But occupancy data could be used as a sensor being activated etc.

    Yes to both, you will need to extend the <w> command to accept callback parameters (like <R>) and JMRI would need to be augmented to send these parameters.

    It's mostly not there.
     
  12. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    1. Geoff's decoder - It was initially a mobile decoder, so that is how it had 17 addresses. They are just CV,Value pairs and the 17 number was just because of the limitation of pins on an Arduino Pro Mini. He added stationary decoder capability and just uses 17 discrete addresses ;) Like I said, he hates multi-part addressing. Ha!

    2. Asking Geoff about his opinion, he shared this:

    Geoff Bunza said: "My reccommendation is to follow the lead of JMRI and Digitrax and consider it as one larger continuous address. I don't think many decoders pay attention to the enable bit. You could do this by a "set default addressing" command or with an alternate command as you suggested. I believe Marklin or some other European manufacturer uses the 2 bit offset (the one I can't stand), so you might keep some variation of it around to encourage global harmony."

    More info: Geoff Bunza MRH Blog

    The key points are that not a lot of people use the "C" on/of bit, and JMRI, Digitrax and the NMRA library all use this form of "flat" addressing. So I think now it is just digesting all of this and coming up with the "best" way and implement that. Bottom line is we will have the old way and a new way, maybe on the same command, maybe with a compile option, maybe with a new command. Also, thanks for the info you sent via email @Atani!
     
    KC Smith and Atani like this.
  13. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Starting to agree with him! lol

    ok let's table it as always sent as 1 (what DCC++ does now and also what ESP32 CS does).

    Kinda funny how DigiTrax was the originator of part of the standard and moved away from it :) Almost all systems have moved to the flat addressing (including ESP32 CS). Maybe it is time to deprecate and move away in DCC++EX?
     
  14. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    Deprecate, perhaps so! One more thing that i don't know how I missed with all this playing around, but unless I missed something as I tried all this, We seem to be offset by a value of 3. I believe JMRI may have corrected for this, but it was changed a year ago because someone noticed the 2 part address didn't match what was expected. Can you verify my results?

    this formula...
    int sw_address=1275;
    sw1=(sw_address+3)/4;
    sw2=(sw_address-(sw1*4))+3;

    gives 319,2

    Use this formula to reverse check it:

    N = (sw1 - 1) * 4 + sw2 + 1;

    N=319

    That gives: 10111111 10111101

    2s complement bits 4-7 and we get 100. Stick that in front of the 6 bit address:

    100111111 then add the 10 for the 2nd byte port address from bits 1 and 2 and we get:

    10011111110 but this is 1278, not 1275
    ---------------------------------------------------

    And looking at the largest possible value of 2044 we get:

    <a 511 3 1> yields 10111111 10001111. 1s complement and build...

    111111111 11 = 2047, not 2044 :(
     
    Last edited: May 16, 2020
  15. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Keep in mind user visible addresses start at one and DCC wire addresses start at zero... So it should come out as 319,1 I believe.

    this looks correct actually, the max address is 2048 but there are a handful that are reserved for broadcast.
     
  16. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    Looking at the code, JMRI is computing the address by taking our packet 10111111 10111101 for 1275 aka 319,2 and using this calculation to get the 11 bit address:

    addr = (((boardAddress - 1) << 2) | outputIndex) + 1;

    So 111111 subtract 1 becomes 111110.
    Shift it over 2 and we get 11111000
    Then 1s complement 011 is still 100 stick that on the front for 10011111000
    Take the 2 DD most significant bits from byte 2 (10) and add 1 to get 11
    OR it both bytes together:
    10011111000
    00000000011
    ---------------
    10011111011 = 1275!!!! OMG!! Fireworks! Parade!! Blue Angels Flyover!!!

    So as you said, this has something to do with addresses starting at 1 and ports/outputIndex starting at 0 (0-3)

    accessory 1272 address 319 port 0
    accessory 1273 address 319 port 1
    accessory 1274 address 319 port 2
    accessory 1275 address 319 port 3

    And this works the same for turnouts using the T command, so there is that to think about.:eek:
     
    KC Smith and Atani like this.
  17. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    this is the same as used in NmraDcc library :)
     
  18. UkBloke

    UkBloke TrainBoard Member

    42
    5
    3
    Firstly, thanks for letting me join your forum. I hope you don't come to regret it!

    Please be aware, I may be model railway novice but I'm not a novice programmer and I have some ideas that I hope you will find constructive.

    Just to keep you interested....

    DCC++ sometimes hangs ...

    Check out the 3 lines of code from PacketRegister::loadPacket which are the same in all DCC++ derivatives I have seen so far, including EX

    nextReg=r;
    this->nRepeat=nRepeat;
    maxLoadedReg=max(maxLoadedReg,nextReg);


    So, what happens if the signal generation interrupt pops half way through updating `nextReg` or `maxLoadedReg` ... the interrupt task will get a half-updated pointer and mayhem follows.

    Just because the function is marked `volatile` it doesn't protect you from this kind of problem.

    At the very least, these should be surrounded by `noInterrupts();` and `interrupts();`
     
  19. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Very true, this needs to be wrapped in a protective lock of some sort.
     
  20. UkBloke

    UkBloke TrainBoard Member

    42
    5
    3
    I have a better idea.... but you may want to wear your peril-sensitive sunglasses ;-)
     

Share This Page