DCC++ BaseStation DCC_SIGNAL MACRO code

Texas Tim Dec 3, 2016

  1. Texas Tim

    Texas Tim TrainBoard Member

    53
    52
    9
    I got a chance to dig into the DCC++ BaseStation code and I am a bit confuse with the DCC_SIGNAL MACRO logic.

    Code:
    #define DCC_SIGNAL(R,N) \
      if(R.currentBit==R.currentReg->activePacket->nBits){    /* IF no more bits in this DCC Packet */ \
        R.currentBit=0;                                       /*   reset current bit pointer and determine which Register and Packet to process next--- */ \
        if(R.nRepeat>0 && R.currentReg==R.reg){               /*   IF current Register is first Register AND should be repeated */ \
          R.nRepeat--;                                        /*     decrement repeat count; result is this same Packet will be repeated */ \
        } else if(R.nextReg!=NULL){                           /*   ELSE IF another Register has been updated */ \
          R.currentReg=R.nextReg;                             /*     update currentReg to nextReg */ \
          R.nextReg=NULL;                                     /*     reset nextReg to NULL */ \
          R.tempPacket=R.currentReg->activePacket;            /*     flip active and update Packets */ \
          R.currentReg->activePacket=R.currentReg->updatePacket; \
          R.currentReg->updatePacket=R.tempPacket; \
        } else{                                               /*   ELSE simply move to next Register */ \
          if(R.currentReg==R.maxLoadedReg)                    /*     BUT IF this is last Register loaded */ \
            R.currentReg=R.reg;                               /*       first reset currentReg to base Register, THEN */ \
          R.currentReg++;                                     /*     increment current Register (note this logic causes Register[0] to be skipped when simply cycling through all Registers) */ \
        }                                                     /*   END-ELSE */ \
      }                                                       /* END-IF: currentReg, activePacket, and currentBit should now be properly set to point to next DCC bit */ \
                                                              \
      if(R.currentReg->activePacket->buf[R.currentBit/8] & R.bitMask[R.currentBit%8]){     /* IF bit is a ONE */ \
        OCR ## N ## A=DCC_ONE_BIT_TOTAL_DURATION_TIMER ## N;                               /*   set OCRA for timer N to full cycle duration of DCC ONE bit */ \
        OCR ## N ## B=DCC_ONE_BIT_PULSE_DURATION_TIMER ## N;                               /*   set OCRB for timer N to half cycle duration of DCC ONE but */ \
      } else{                                                                              /* ELSE it is a ZERO */ \
        OCR ## N ## A=DCC_ZERO_BIT_TOTAL_DURATION_TIMER ## N;                              /*   set OCRA for timer N to full cycle duration of DCC ZERO bit */ \
        OCR ## N ## B=DCC_ZERO_BIT_PULSE_DURATION_TIMER ## N;                              /*   set OCRB for timer N to half cycle duration of DCC ZERO bit */ \
      }                                                                                    /* END-ELSE */ \
                                                                                           \
      R.currentBit++;                                         /* point to next bit in current Packet */
      
    Basically, when the BaseStation starts up, the R.currentBit is initialized zero, and all the registers's nBits are also zero.

    Base on what I read and understood, the R.currentBit is always incremented (by R.currentBit++) at the end of the MACRO, after the first interrupt, the logic will never get into the this
    Code:
    if(R.currentBit==R.currentReg->activePacket->nBits)
    
    because the currentBit now is no longer zero, while all nBits still zero.

    eventually, this line will hit over the buf limit (of 10-bytes) and goes thru all the registers and into out of bound memory.
    Code:
    if(R.currentReg->activePacket->buf[R.currentBit/8] & R.bitMask[R.currentBit%8])
    
    Would this not cause any issue?

    Also, it is ok to continue send ZERO bit to the track?

    Any clarification will be greatly appreciated. Thanks!
     
    Scott Eric Catalano likes this.
  2. Travis Farmer

    Travis Farmer TrainBoard Member

    352
    320
    14
    Code:
    if(R.currentReg==R.maxLoadedReg) /* BUT IF this is last Register loaded */ \ 
      R.currentReg=R.reg; /* first reset currentReg to base Register, THEN */ \ 
    R.currentReg++;
    the single line IF statement checks for max, and resets to R.reg, then it increments.

    ~Travis
     
    Scott Eric Catalano likes this.
  3. Texas Tim

    Texas Tim TrainBoard Member

    53
    52
    9
    but that check is within:
    Code:
    if(R.currentBit==R.currentReg->activePacket->nBits){
    }
    I m thinking out loud here.
    When BaseStation starts, R.currentBit=0; and R.currentReg is pointing to first register, which shall be all zero. So first interrupt comes in, this will be true
    Code:
    R.currentBit==R.currentReg->activePacket->nBits
    
    and since first register has not been use, repeat=0, and no next-register, the execution will run
    Code:
    if(R.currentReg==R.maxLoadedReg) /* BUT IF this is last Register loaded */ \
      R.currentReg=R.reg; /* first reset currentReg to base Register, THEN */ \
    R.currentReg++;
    
    and currentReg is indeed same as maxLoadedReg, then it set it back to the first register with R.currentReg=R.reg, but then moves the pointer to the next register with R.currentReg++.
    Then it gets out of the if {} block. Send all ZERO signal, increment R.currentBit++.
    *** Next (2nd and on) interrupt comes,
    currentBit now is 1, so it wont go into the
    if {} block, it sends all ZERO signal again. And increment currrentBit, and repeat at the *** above and on and on.
    Am I missing the execution flow somehow somewhere.
     
    Scott Eric Catalano likes this.
  4. Texas Tim

    Texas Tim TrainBoard Member

    53
    52
    9
    I found the answer to my own question and confusion above. The scenarios I described will never occur because during BaseStation starts up, the setup() code will always load idle-packet into register-1 on both main and programming track before the interrupts were enabled.

    This is a good exercise to read and try to understand the DCC++ code. :)
     
    Scott Eric Catalano likes this.

Share This Page