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!
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
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.
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.