01/23/03 rev 04/10/08
Our do-it-yourself (DIY) DCC served the Teton Short Line well for several years until our HO modular club converted to DCC. After months of study and controversy, they selected the EasyDCC system by CVP Products It was installed about a year ago and we love it. EasyDCC has a great track record starting with it's description in several MR articles in 1997. As an electronic engineer, I can appreciate the quality of design and construction. The more we used it, the more I realized that the Teton Short Line operating experience would be enhanced if we had the four digit addressing and our crew could enjoy the familiarity of EasyDCC. Visitors could use their own power without reprogramming too. I studied the well documented EasyDCC system and found that it would be a relatively easy task to interface it to the TSL computer so that we could retain our very desirable walk-around cabs. EasyDCC has an RS232 port that will interface with your computer at 9600 baud. Twenty pages of the 180 page online manual explain the protocals. A letter about being a good boy to the North Pole resulted in Santa delivering the EZ Command Station on 12/25/02. In a very short time it was interfaced to our boosters and controlling trains. It took a few more, actually quite a few, more hours to get our cabs to control it. QBASIC has been the language of choice for the TSL embedded computer for most of its years and has evolved to more than 4000 lines of code controlling everything from cabs to dispatcher graphics. it would be a monstrous effort to change it, so we won't. The EasyDCC manual has examples using generic BASIC that might be useful for an initial acquaintance. To control trains via the EasyDCC RS232 port requires you to enter the SPEED/DIRECTION commands originating in my cab system, into the DCC queue. Consists can be built and modified via this port but controlling consists has to have a little further understanding. Paul Bender posted an explanation to the EasyDCC Yahoo group on 04/10/08 that makes it quite clear.
You have to understand there are three different types of consisting supported. First, you can simply assign all the locomotives in the consist the same address (This is known as basic or primary address consisting). Second, you can consist the locomotives in the command station. I refer to this as Command Station Assisted Consisting(CSAC). On an EasyDCC system, this is a "Standard Consist". For a CSAC to work, packets are always sent out to each locomotive in the consist. Third, you can consist the locomotives in the decoder, using CV19 - the consist address. I refer to this as Decoder Assisted Consisting (DAC), some people call this Advanced Consisting, which is the term Digitrax uses to describe this feature. (For more info, refer to the background information section here: http://jmri.sourceforge.net/help/en/html/tools/consisttool/ConsistTool.shtml ) On an EasyDCC system, you can build both DACs and Standard Consists using the serial port. Because of the way in which throttle commands are sent to the EasyDCC system through the serial port (which requires sending the NMRA DCC packets ourself), the command station does not decode or modify the packets we send. The result is that we CAN control a Basic Consist or DAC by sending commands to the consist address, but we have to do more work to command a "Standard Consist". With a "Standard Consist", If we just sent commands to the consist address, the only locomotive(s) that will move would have an address corresponding to the consist address. To control a "Standard Consist" through the serial port, we need to request the details of what locomotives are contained in the consist from the command station and send out the required commands to each locomotive within that consist, instead of sending one command to the consist address. The protocol used on the cab bus is different than the one used with the serial port. This allows the command station to automatically send out the required commands for a "Standard Consist" when a cab selects and controls a consist.=====================================================================I much appreciated Pauls clear explanation of the consisting situations. Please note that I DO NOT load the consist info into the command station and so it will not show if you ask the command station to display consist information, however as Paul describes you might want to do just that.
It is important to understand that the commands we add to the queue via the serial port do not interfere with the normal use of wired or radio cabs that are part of the EasyDCC system- Obviously, you can't control the SAME loco from more than one cab whether it be radio, wired, RS232 or the two on the command stataion.
Here is some of QBASIC code that we use
=====================================================================
SUB EZconsists STATIC 'new 01/08/03 'This SUB, EZconsists interfaces the computer consists with EZdcc 'It is one way only i.e. consists created on EZ do not come here. 'A consist change results in KILL CONSIST command to EZ and then 'the consist is rebuilt. The consist number is the Lead Loco. DIM OldConsist(5) DIM OldChkSum(5) 'look for changes and output them Trace = 0 'local for program developement ' OverKill = 0 'EZ usually doesn't accept first kill AlertEZ: 'the first Kill to EZ is rejected with ? k$ = "GKFF" CALL EZdccSend(k$) FOR CabNo = 0 TO 4 ChkSum(CabNo) = 0 FOR Loco = 1 TO 4 ChkSum(CabNo) = ChkSum(CabNo) XOR Consist(CabNo, Loco) NEXT Loco IF Trace THEN PRINT "Cab"; CabNo; "OldChkSum"; OldChkSum(CabNo); PRINT "ChkSum"; ChkSum(CabNo) FOR c = 1 TO 4: PRINT Consist(CabNo, c); : NEXT: PRINT END IF IF ChkSum(CabNo) <> OldChkSum(CabNo) THEN 'open the port and send the cab consist KillConsists: ' Use the lead loco two digit number OverKill = OverKill + 1 k$ = HEX$(OldConsist(CabNo)) 'old consist in case it changed k$ = "GK" + RIGHT$(("00" + k$), 2) IF Trace THEN PRINT "Kill"; k$; CALL EZdccSend(k$) k$ = HEX$(ABS(Consist(CabNo, 1))) 'current consist k$ = "GK" + RIGHT$(("00" + k$), 2) IF Trace THEN PRINT "kill"; k$; CALL EZdccSend(k$) NewConsist: 'The lead loco is also the consist number and cannot be reverse. IF (Consist(CabNo, 1)) = 0 THEN GOTO NullLoco OldConsist(CabNo) = Consist(CabNo, 1) 'the "new" old consist yy$ = HEX$(ABS(Consist(CabNo, 1))) 'this is consist number yy$ = RIGHT$(("00" + yy$), 2) FOR Loco = 2 TO 4 'add the rest of them j$ = "GN" 'IF (consist(CabNo, Loco)) = 0 THEN GOTO NullLoco IF (Consist(CabNo, Loco)) < 0 THEN j$ = "GR" k$ = HEX$(ABS(Consist(CabNo, Loco))) k$ = j$ + yy$ + RIGHT$(("0000" + k$), 4) IF Trace THEN PRINT k$ + " "; CALL EZdccSend(k$) NullLoco: NEXT Loco 'save a new CheckSum ChkSum = Consist(CabNo, 1) XOR Consist(CabNo, 2) ChkSum = ChkSum XOR Consist(CabNo, 3) XOR Consist(CabNo, 4) OldChkSum(CabNo) = ChkSum END IF 'IF Trace THEN CALL Waitkey NEXT CabNo IF Trace THEN LPRINT "EZconsists done" ': CALL Waitkey END SUB SUB EZdccSend (k$) 'new 01/05/03 'receives a string from SUB EZconsists or SUB EZwriteQ and sends it. LOCATE 30, 1: PRINT SPACE$(10); CALL EZopenPort ClearInputBuffer: a$ = "" LOCATE 30, 1: PRINT k$; Transmit k$ + CHR$(13) Startime! = TIMER 'look for a dead port SendValid: TimeNow! = TIMER IF (TimeNow! - Startime!) > .25 THEN BadPort = -1: GOTO BadEZport IF DataWaiting THEN a$ = CHR$(ReadChar) IF a$ <> CHR$(13) THEN LOCATE 30, 9: PRINT a$; IF a$ = CHR$(13) THEN GOTO EZdccSendEnd END IF c$ = INKEY$ IF c$ = CHR$(3) THEN END GOTO SendValid BadEZport: Delay$ = LEFT$(STR$(TimeNow! - Startime!), 5) Text$ = "EZdcc PORT IS BAD-" + Delay$ CALL PrntStr(Text$, 12, 10, LtRed + 16) 'make it flash 'PRINT CHR$(7); 'ring the bell EZdccSendEnd: CloseComm END SUB SUB EZopenPort 'new 01/05/03 'initialize the comm port with added library 'OpenComm port,IRQ,WordLen,Parity,StopBits,BaudRate,Handshake,0 Port = 1: Length = 8: Parity = 0: Bits = 1: Rate& = 9600: HS = 1 OpenComm Port, 0, Length, Parity, Bits, Rate&, HS, 0 CarrierDetect 0 'don't monitor- disables UEVENT trip END SUB SUB EZwriteQ STATIC '01/20/03 'This SUB replaces the DCCarray used with our old DIY DCC system. It is 'no longer necessary to maintain the array, but simply send changes to 'EZdcc. The SUB Cab2DCC assigns new speeds to the locos of each consist. 'In accordance with EZdcc specs, to put a command in the Queue, we only 'send the letter "Q" plus three bytes for address, speed/drctn and the 'checksum. Send the letter "D" plus the address to remove from queue so 'that EZ cabs can use the address without conflict. 'Initially, only short addresses will be used in keeping with 'the graphics and cab indications. This is called only from the Exec loop. DIM OldLocoSpd(21) Trace = 0 'displays the array for program developement 'This is the Packet structure without preambles. '---------------------------------------------------------------------- 'pattern for baseline 8 bit address with 28 speed steps. ' 0AAAAAAA-01DsSSSS-EEEEEEEE ' byte1 byte2 byte3 byte4 byte5 ' lower case [s] is the LSB of the 5-bit speed-MSB follows ' speed 12 (01D1 0010) = 2nd speed step ' speed 02 (01D0 0010) = 1st speed step ' speed 01 or 10 = emergency stop- we don't use it ' speed 00 (00D0 0000) = stop and then dequeue '---------------------------------------------------------------------- FOR Loco = 1 TO LocoMany 'PRINT "EZwriteQ1"; Loco; LocoSpd(Loco); OldLocoSpd(Loco) IF LocoSpd(Loco) <> OldLocoSpd(Loco) THEN 'format & send Qpacket to EZ ShortAdrs = LocoDat(Loco, 1) AND 127 'last two digits of eng# Byte1 = ShortAdrs '0AAAAAAA Byte2 = 64 OR LocoSpd(Loco) '01DsSSSS->0100000 Byte3 = Byte1 XOR Byte2 ' LPRINT "EZwriteQ2"; Loco GOSUB AssemblePacket 'assemble and send to EZdcc IF Trace THEN GOSUB TestPrintPacket OldLocoSpd(Loco) = LocoSpd(Loco) END IF NEXT Loco CALL ScreenStat(3) 'update the screen EXIT SUB AssemblePacket: 'assemble and send the string in HEX format Byte1$ = RIGHT$(("00" + HEX$(Byte1)), 2) 'short address Byte2$ = RIGHT$(("00" + HEX$(Byte2)), 2) 'speed & drctn Byte3$ = RIGHT$(("00" + HEX$(Byte3)), 2) 'checksum Qpacket$(Loco) = "Q" + Byte1$ + Byte2$ + Byte3$ 'put in queue k$ = Qpacket$(Loco) CALL EZdccSend(k$) IF (Byte2$ = "40" OR Byte2$ = "60") THEN 'dequeue @ zero speed k$ = "D00" + Byte1$ 'remove from queue CALL EZdccSend(k$) END IF RETURN TestPrintPacket: PRINT "Loco"; Loco; Spd(Loco); OldLocoSpd(Loco) PRINT "Packet"; "Loco"; Loco; Qpacket$(Loco); PRINT Int2Bin$(Byte3); PRINT Int2Bin$(Byte4); PRINT Int2Bin$(Byte5) 'Waitkey 'pause RETURN END SUB