#include #include #include "DCCWaveform.h" #include "DIAG.h" DCCWaveform DCCWaveform::mainTrack(MAIN_POWER_PIN,MAIN_SIGNAL_PIN,MAIN_SENSE_PIN,PREAMBLE_BITS_MAIN,true); DCCWaveform DCCWaveform::progTrack(PROG_POWER_PIN,PROG_SIGNAL_PIN,PROG_SENSE_PIN,PREAMBLE_BITS_PROG,false); void DCCWaveform::begin() { Timer3.initialize(58); Timer3.disablePwm(MAIN_SIGNAL_PIN); Timer3.disablePwm(PROG_SIGNAL_PIN); Timer3.attachInterrupt(interruptHandler); mainTrack.beginTrack(); progTrack.beginTrack(); } void DCCWaveform::loop() { mainTrack.checkPowerOverload(); progTrack.checkPowerOverload(); } // static // void DCCWaveform::interruptHandler() { // call the timer edge sensitive actions for progtrack and maintrack bool mainCall2=mainTrack.interrupt1(); bool progCall2=progTrack.interrupt1(); // call (if necessary) the procs to get the current bits // these must complete within 50microsecs of the interrupt // but they are only called ONCE PER BIT TRANSMITTED // after the rising edge of the signal if (mainCall2) mainTrack.interrupt2(); if (progCall2) progTrack.interrupt2(); } // An instance of this class handles the DCC transmissions for one track. (main or prog) // Interrupts are marshalled via the statics. // A track has a current transmit buffer, and a pending buffer. // When the current buffer is exhausted, either the pending buffer (if there is one waiting) or an idle buffer. // This bitmask has 9 entries as each byte is trasmitted as a zero + 8 bits. const byte bitMask[]={0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; DCCWaveform::DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo, byte preambleBits, bool isMain) { // establish appropriate pins powerPin=Arduino_to_GPIO_pin(powerPinNo); directionPin=Arduino_to_GPIO_pin(directionPinNo); sensePin=sensePinNo; isMainTrack=isMain; packetPending=false; memcpy(transmitPacket,idlePacket,sizeof(idlePacket)); state=0; requiredPreambles=preambleBits; bytes_sent=0; bits_sent=0; nextSampleDue=0; } void DCCWaveform::beginTrack() { pinMode2f(powerPin,OUTPUT); pinMode2f(directionPin,OUTPUT); pinMode(sensePin,INPUT); if (isMainTrack && RAILCOM_CUTOUT) { railcomBrakePin=Arduino_to_GPIO_pin(RAILCOM_BRAKE_PIN); pinMode2f(railcomBrakePin, OUTPUT); digitalWrite2f(railcomBrakePin, LOW); } setPowerMode(POWERMODE::ON); DIAG(F("\nTrack started sensePin=%d\n"),sensePin); } POWERMODE DCCWaveform::getPowerMode() { return powerMode; } void DCCWaveform::setPowerMode(POWERMODE mode) { powerMode=mode; digitalWrite2f(powerPin, mode==POWERMODE::ON ? HIGH:LOW); if (mode==POWERMODE::ON) schedulePacket(resetMessage,2,20); } void DCCWaveform::checkPowerOverload() { if (millis() 0 ) { currentBit=true; remainingPreambles--; return; } // beware OF 9-BIT MASK generating a zero to start each byte currentBit=transmitPacket[bytes_sent] & bitMask[bits_sent]; bits_sent++; // If this is the last bit of a byte, prepare for the next byte if (bits_sent==9) { // zero followed by 8 bits of a byte //end of Byte bits_sent=0; bytes_sent++; // if this is the last byte, prepere for next packet if (bytes_sent >= transmitLength) { // end of transmission buffer... repeat or switch to next message bytes_sent = 0; remainingPreambles=requiredPreambles; if (transmitRepeats > 0) { transmitRepeats--; } else if (packetPending) { // Copy pending packet to transmit packet for (int b=0;b=MAX_PACKET_SIZE) return; // allow for chksum while(packetPending) delay(1); byte checksum=0; for (int b=0;bmillis()) { upsamples++; int current=analogRead(sensePin); maxCurrent=max(maxCurrent,current); result=current > ACK_MIN_PULSE; } // Monitor current until ack signal dies back if (result) while( true) { downsamples++; int current=analogRead(sensePin); maxCurrent=max(maxCurrent,current); if (current<= ACK_MAX_NOT_PULSE) break; } // The following DIAG is really useful as it can show how long and how far the // current changes during an ACK from the decoder. // DIAG(F("\nack=%d max=%d, up=%d, down=%d "),result,maxCurrent, upsamples,downsamples); return result; }