DCCpp
This is the library version of a program for Arduino to control railroading DCC devices.
TextCommand.cpp
1 /**********************************************************************
2 
3 TextCommand.cpp
4 COPYRIGHT (c) 2013-2016 Gregg E. Berman
5 
6 Part of DCC++ BASE STATION for the Arduino
7 
8 **********************************************************************/
9 
10 // See TextCommand::parse() below for defined text commands.
11 
12 #include "TextCommand.h"
13 #ifdef USE_TEXTCOMMAND
14 
15 #ifdef VISUALSTUDIO
16 #include "string.h"
17 #else
18 extern unsigned int __heap_start;
19 extern void *__brkval;
20 #endif
21 
23 
24 char TextCommand::commandString[MAX_COMMAND_LENGTH+1];
25 
27 
28 void TextCommand::init(volatile RegisterList *_mRegs, volatile RegisterList *_pRegs, CurrentMonitor *_mMonitor){
29  commandString[0] = 0;
30 } // TextCommand:TextCommand
31 
33 
34 void TextCommand::process(){
35  char c;
36 
37  #if defined(USE_ETHERNET)
38 
39  EthernetClient client=INTERFACE.available();
40 
41  if (client) {
42  INTERFACE.println("HTTP/1.1 200 OK");
43  INTERFACE.println("Content-Type: text/html");
44  INTERFACE.println("Access-Control-Allow-Origin: *");
45  INTERFACE.println("Connection: close");
46  INTERFACE.println("");
47 
48  while (client.connected() && client.available()) { // while there is data on the network
49  c = client.read();
50  if (c == '<') // start of new command
51  sprintf(commandString, "");
52  else if (c == '>') // end of new command
53  parse(commandString);
54  else if (strlen(commandString) < MAX_COMMAND_LENGTH) // if comandString still has space, append character just read from network
55  sprintf(commandString, "%s%c", commandString, c); // otherwise, character is ignored (but continue to look for '<' or '>')
56  } // while
57 
58  client.stop();
59  }
60 
61  #else // SERIAL case
62 
63  while (INTERFACE.available()>0) { // while there is data on the serial line
64  c = INTERFACE.read();
65  if (c == '<') // start of new command
66  commandString[0] = 0;
67  else if (c == '>') // end of new command
68  parse(commandString);
69  else if (strlen(commandString)<MAX_COMMAND_LENGTH) // if comandString still has space, append character just read from serial line
70  sprintf(commandString, "%s%c", commandString, c); // otherwise, character is ignored (but continue to look for '<' or '>')
71  } // while
72 
73  #endif
74 
75 } // TextCommand:process
76 
78 
79 void TextCommand::parse(char *com){
80 
81 #ifdef DCCPP_DEBUG_MODE
82  Serial.print((char) com[0]);
83  Serial.println(F(" command"));
84 #endif
85 
86  switch(com[0]){
87 
88 /***** SET ENGINE THROTTLES USING 128-STEP SPEED CONTROL ****/
89 
90  case 't': // <t REGISTER CAB SPEED DIRECTION>
91 /*
92  * sets the throttle for a given register/cab combination
93  *
94  * REGISTER: an internal register number, from 1 through MAX_MAIN_REGISTERS (inclusive), to store the DCC packet used to control this throttle setting
95  * CAB: the short (1-127) or long (128-10293) address of the engine decoder
96  * SPEED: throttle speed from 0-126, or -1 for emergency stop (resets SPEED to 0)
97  * DIRECTION: 1=forward, 0=reverse. Setting direction when speed=0 or speed=-1 only effects directionality of cab lighting for a stopped train
98  *
99  * returns: <T REGISTER SPEED DIRECTION>
100  *
101  */
102 
103  DCCppClass::mainRegs.setThrottle(com+1);
104  break;
105 
106 /***** OPERATE ENGINE DECODER FUNCTIONS F0-F28 ****/
107 
108  case 'f': // <f CAB BYTE1 [BYTE2]>
109 /*
110  * turns on and off engine decoder functions F0-F28 (F0 is sometimes called FL)
111  * NOTE: setting requests transmitted directly to mobile engine decoder --- current state of engine functions is not stored by this program
112  *
113  * CAB: the short (1-127) or long (128-10293) address of the engine decoder
114  *
115  * To set functions F0-F4 on (=1) or off (=0):
116  *
117  * BYTE1: 128 + F1*1 + F2*2 + F3*4 + F4*8 + F0*16
118  * BYTE2: omitted
119  *
120  * To set functions F5-F8 on (=1) or off (=0):
121  *
122  * BYTE1: 176 + F5*1 + F6*2 + F7*4 + F8*8
123  * BYTE2: omitted
124  *
125  * To set functions F9-F12 on (=1) or off (=0):
126  *
127  * BYTE1: 160 + F9*1 +F10*2 + F11*4 + F12*8
128  * BYTE2: omitted
129  *
130  * To set functions F13-F20 on (=1) or off (=0):
131  *
132  * BYTE1: 222
133  * BYTE2: F13*1 + F14*2 + F15*4 + F16*8 + F17*16 + F18*32 + F19*64 + F20*128
134  *
135  * To set functions F21-F28 on (=1) of off (=0):
136  *
137  * BYTE1: 223
138  * BYTE2: F21*1 + F22*2 + F23*4 + F24*8 + F25*16 + F26*32 + F27*64 + F28*128
139  *
140  * returns: NONE
141  *
142  */
143  DCCppClass::mainRegs.setFunction(com+1);
144  break;
145 
146 /***** OPERATE STATIONARY ACCESSORY DECODERS ****/
147 
148  case 'a': // <a ADDRESS SUBADDRESS ACTIVATE>
149 /*
150  * turns an accessory (stationary) decoder on or off
151  *
152  * ADDRESS: the primary address of the decoder (0-511)
153  * SUBADDRESS: the subaddress of the decoder (0-3)
154  * ACTIVATE: 1=on (set), 0=off (clear)
155  *
156  * Note that many decoders and controllers combine the ADDRESS and SUBADDRESS into a single number, N,
157  * from 1 through a max of 2044, where
158  *
159  * N = (ADDRESS - 1) * 4 + SUBADDRESS + 1, for all ADDRESS>0
160  *
161  * OR
162  *
163  * ADDRESS = INT((N - 1) / 4) + 1
164  * SUBADDRESS = (N - 1) % 4
165  *
166  * returns: NONE
167  */
168  DCCppClass::mainRegs.setAccessory(com+1);
169  break;
170 
171 #ifdef USE_TURNOUT
172  /***** CREATE/EDIT/REMOVE/SHOW & OPERATE A TURN-OUT ****/
173 
174  case 'T': // <T ID THROW>
175 /*
176  * <T ID THROW>: sets turnout ID to either the "thrown" or "unthrown" position
177  *
178  * ID: the numeric ID (0-32767) of the turnout to control
179  * THROW: 0 (unthrown) or 1 (thrown)
180  *
181  * returns: <H ID THROW> or <X> if turnout ID does not exist
182  *
183  * *** SEE TURNOUT.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "T" COMMAND
184  * USED TO CREATE/EDIT/REMOVE/SHOW TURNOUT DEFINITIONS
185  */
186  Turnout::parse(com+1);
187  break;
188 #endif
189 
190 #ifdef USE_OUTPUT
191 /***** CREATE/EDIT/REMOVE/SHOW & OPERATE AN OUTPUT PIN ****/
192 
193  case 'Z': // <Z ID ACTIVATE>
194 /*
195  * <Z ID ACTIVATE>: sets output ID to either the "active" or "inactive" state
196  *
197  * ID: the numeric ID (0-32767) of the output to control
198  * ACTIVATE: 0 (active) or 1 (inactive)
199  *
200  * returns: <Y ID ACTIVATE> or <X> if output ID does not exist
201  *
202  * *** SEE OUTPUTS.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "O" COMMAND
203  * USED TO CREATE/EDIT/REMOVE/SHOW TURNOUT DEFINITIONS
204  */
205  Output::parse(com+1);
206  break;
207 #endif
208 
209 #ifdef USE_SENSOR
210 /***** CREATE/EDIT/REMOVE/SHOW A SENSOR ****/
211 
212  case 'S':
213 /*
214  * *** SEE SENSOR.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "S" COMMAND
215  * USED TO CREATE/EDIT/REMOVE/SHOW SENSOR DEFINITIONS
216  */
217  Sensor::parse(com+1);
218  break;
219 
220 /***** SHOW STATUS OF ALL SENSORS ****/
221 
222  case 'Q': // <Q>
223 /*
224  * returns: the status of each sensor ID in the form <Q ID> (active) or <q ID> (not active)
225  */
226  Sensor::status();
227  break;
228 #endif
229 
230 /***** WRITE CONFIGURATION VARIABLE BYTE TO ENGINE DECODER ON MAIN OPERATIONS TRACK ****/
231 
232  case 'w': // <w CAB CV VALUE>
233 /*
234  * writes, without any verification, a Configuration Variable to the decoder of an engine on the main operations track
235  *
236  * CAB: the short (1-127) or long (128-10293) address of the engine decoder
237  * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024)
238  * VALUE: the value to be written to the Configuration Variable memory location (0-255)
239  *
240  * returns: NONE
241 */
242  DCCppClass::mainRegs.writeCVByteMain(com+1);
243  break;
244 
245 /***** WRITE CONFIGURATION VARIABLE BIT TO ENGINE DECODER ON MAIN OPERATIONS TRACK ****/
246 
247  case 'b': // <b CAB CV BIT VALUE>
248 /*
249  * writes, without any verification, a single bit within a Configuration Variable to the decoder of an engine on the main operations track
250  *
251  * CAB: the short (1-127) or long (128-10293) address of the engine decoder
252  * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024)
253  * BIT: the bit number of the Configurarion Variable regsiter to write (0-7)
254  * VALUE: the value of the bit to be written (0-1)
255  *
256  * returns: NONE
257 */
258  DCCppClass::mainRegs.writeCVBitMain(com+1);
259  break;
260 
261 /***** WRITE CONFIGURATION VARIABLE BYTE TO ENGINE DECODER ON PROGRAMMING TRACK ****/
262 
263  case 'W': // <W CV VALUE CALLBACKNUM CALLBACKSUB>
264 /*
265  * writes, and then verifies, a Configuration Variable to the decoder of an engine on the programming track
266  *
267  * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024)
268  * VALUE: the value to be written to the Configuration Variable memory location (0-255)
269  * CALLBACKNUM: an arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs that call this function
270  * CALLBACKSUB: a second arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs (e.g. DCC++ Interface) that call this function
271  *
272  * returns: <r CALLBACKNUM|CALLBACKSUB|CV Value)
273  * where VALUE is a number from 0-255 as read from the requested CV, or -1 if verificaiton read fails
274 */
275  DCCppClass::progRegs.writeCVByte(com+1);
276  break;
277 
278 /***** WRITE CONFIGURATION VARIABLE BIT TO ENGINE DECODER ON PROGRAMMING TRACK ****/
279 
280  case 'B': // <B CV BIT VALUE CALLBACKNUM CALLBACKSUB>
281 /*
282  * writes, and then verifies, a single bit within a Configuration Variable to the decoder of an engine on the programming track
283  *
284  * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024)
285  * BIT: the bit number of the Configurarion Variable memory location to write (0-7)
286  * VALUE: the value of the bit to be written (0-1)
287  * CALLBACKNUM: an arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs that call this function
288  * CALLBACKSUB: a second arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs (e.g. DCC++ Interface) that call this function
289  *
290  * returns: <r CALLBACKNUM|CALLBACKSUB|CV BIT VALUE)
291  * where VALUE is a number from 0-1 as read from the requested CV bit, or -1 if verificaiton read fails
292 */
293  DCCppClass::progRegs.writeCVBit(com+1);
294  break;
295 
296 /***** READ CONFIGURATION VARIABLE BYTE FROM ENGINE DECODER ON PROGRAMMING TRACK ****/
297 
298  case 'R': // <R CV CALLBACKNUM CALLBACKSUB>
299 /*
300  * reads a Configuration Variable from the decoder of an engine on the programming track
301  *
302  * CV: the number of the Configuration Variable memory location in the decoder to read from (1-1024)
303  * CALLBACKNUM: an arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs that call this function
304  * CALLBACKSUB: a second arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs (e.g. DCC++ Interface) that call this function
305  *
306  * returns: <r CALLBACKNUM|CALLBACKSUB|CV VALUE)
307  * where VALUE is a number from 0-255 as read from the requested CV, or -1 if read could not be verified
308 */
309  DCCppClass::progRegs.readCV(com+1);
310  break;
311 
312 /***** TURN ON POWER FROM MOTOR SHIELD TO TRACKS ****/
313 
314  case '1': // <1>
315 /*
316  * enables power from the motor shield to the main operations and programming tracks
317  *
318  * returns: <p1>
319  */
320  if (DCCppConfig::SignalEnablePinProg != 255)
321  digitalWrite(DCCppConfig::SignalEnablePinProg,HIGH);
322  if (DCCppConfig::SignalEnablePinMain != 255)
323  digitalWrite(DCCppConfig::SignalEnablePinMain,HIGH);
324  INTERFACE.println("<p1>");
325  break;
326 
327 /***** TURN OFF POWER FROM MOTOR SHIELD TO TRACKS ****/
328 
329  case '0': // <0>
330 /*
331  * disables power from the motor shield to the main operations and programming tracks
332  *
333  * returns: <p0>
334  */
335  if (DCCppConfig::SignalEnablePinProg != 255)
336  digitalWrite(DCCppConfig::SignalEnablePinProg, LOW);
337  if (DCCppConfig::SignalEnablePinMain != 255)
338  digitalWrite(DCCppConfig::SignalEnablePinMain, LOW);
339  INTERFACE.println("<p0>");
340  break;
341 
342 /***** READ MAIN OPERATIONS TRACK CURRENT ****/
343 
344  case 'c': // <c>
345 /*
346  * reads current being drawn on main operations track
347  *
348  * returns: <a CURRENT>
349  * where CURRENT = 0-1024, based on exponentially-smoothed weighting scheme
350  */
351  INTERFACE.print("<a");
352  INTERFACE.print(int(DCCppClass::MainMonitor.current));
353  INTERFACE.println(">");
354  break;
355 
356 /***** READ STATUS OF DCC++ BASE STATION ****/
357 
358  case 's': // <s>
359 /*
360  * returns status messages containing track power status, throttle status, turn-out status, and a version number
361  * NOTE: this is very useful as a first command for an interface to send to this sketch in order to verify connectivity and update any GUI to reflect actual throttle and turn-out settings
362  *
363  * returns: series of status messages that can be read by an interface to determine status of DCC++ Base Station and important settings
364  */
365  if(digitalRead(DCCppConfig::SignalEnablePinProg)==LOW) // could check either PROG or MAIN
366  INTERFACE.println("<p0>");
367  else
368  INTERFACE.println("<p1>");
369 
370  for(int i=1;i<=MAX_MAIN_REGISTERS;i++){
371  if(DCCppClass::mainRegs.speedTable[i]==0)
372  continue;
373  INTERFACE.print("<T");
374  INTERFACE.print(i); INTERFACE.print(" ");
375  if(DCCppClass::mainRegs.speedTable[i]>0){
376  INTERFACE.print(DCCppClass::mainRegs.speedTable[i]);
377  INTERFACE.print(" 1>");
378  } else{
379  INTERFACE.print(- DCCppClass::mainRegs.speedTable[i]);
380  INTERFACE.print(" 0>");
381  }
382  }
383  INTERFACE.print("<iDCCpp LIBRARY BASE STATION FOR ARDUINO ");
384  //INTERFACE.print(ARDUINO_TYPE);
385  //INTERFACE.print(" / ");
386  //INTERFACE.print(MOTOR_SHIELD_NAME);
387  INTERFACE.print(": V-");
388  INTERFACE.print(VERSION);
389  INTERFACE.print(" / ");
390  INTERFACE.print(__DATE__);
391  INTERFACE.print(" ");
392  INTERFACE.print(__TIME__);
393  INTERFACE.println(">");
394 
395  INTERFACE.print("<N ");
396 #if defined(USE_ETHERNET)
397  INTERFACE.print("ETHERNET :");
398  INTERFACE.print(Ethernet.localIP());
399  INTERFACE.println(">");
400 #else
401  INTERFACE.println("SERIAL>");
402 #endif
403 
404 #ifdef USE_TURNOUT
405  Turnout::show();
406 #endif
407 #ifdef USE_OUTPUT
408  Output::show();
409 #endif
410 #ifdef USE_SENSOR
411  Sensor::show();
412 #endif
413  break;
414 
415 /***** STORE SETTINGS IN EEPROM ****/
416 
417 #ifdef USE_EEPROM
418  case 'E': // <E>
419 /*
420  * stores settings for turnouts and sensors EEPROM
421  *
422  * returns: <e nTurnouts nSensors>
423 */
424 
425  EEStore::store();
426  INTERFACE.print("<e ");
427  INTERFACE.print(EEStore::eeStore->data.nTurnouts);
428  INTERFACE.print(" ");
429  INTERFACE.print(EEStore::eeStore->data.nSensors);
430  INTERFACE.print(" ");
431  INTERFACE.print(EEStore::eeStore->data.nOutputs);
432  INTERFACE.println(">");
433  break;
434 
435 /***** CLEAR SETTINGS IN EEPROM ****/
436 
437  case 'e': // <e>
438 /*
439  * clears settings for Turnouts in EEPROM
440  *
441  * returns: <O>
442 */
443 
444  EEStore::clear();
445  INTERFACE.print("<O>");
446  break;
447 #endif
448 
449 /***** PRINT CARRIAGE RETURN IN SERIAL MONITOR WINDOW ****/
450 
451  case ' ': // < >
452 /*
453  * simply prints a carriage return - useful when interacting with Ardiuno through serial monitor window
454  *
455  * returns: a carriage return
456 */
457  INTERFACE.println("");
458  break;
459 
464 
465 /***** ENTER DIAGNOSTIC MODE ****/
466 
467  case 'D': // <D>
468 /*
469  * changes the clock speed of the chip and the pre-scaler for the timers so that you can visually see the DCC signals flickering with an LED
470  * SERIAL COMMUNICAITON WILL BE INTERUPTED ONCE THIS COMMAND IS ISSUED - MUST RESET BOARD OR RE-OPEN SERIAL WINDOW TO RE-ESTABLISH COMMS
471  */
472 
473  Serial.println("nEntering Diagnostic Mode...");
474  delay(1000);
475 
476  bitClear(TCCR1B,CS12); // set Timer 1 prescale=8 - SLOWS NORMAL SPEED BY FACTOR OF 8
477  bitSet(TCCR1B,CS11);
478  bitClear(TCCR1B,CS10);
479 
480  #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) // Configuration for UNO
481 
482  bitSet(TCCR0B,CS02); // set Timer 0 prescale=256 - SLOWS NORMAL SPEED BY A FACTOR OF 4
483  bitClear(TCCR0B,CS01);
484  bitClear(TCCR0B,CS00);
485 
486  #else // Configuration for MEGA
487 
488  bitClear(TCCR3B,CS32); // set Timer 3 prescale=8 - SLOWS NORMAL SPEED BY A FACTOR OF 8
489  bitSet(TCCR3B,CS31);
490  bitClear(TCCR3B,CS30);
491 
492  #endif
493 
494  CLKPR=0x80; // THIS SLOWS DOWN SYSYEM CLOCK BY FACTOR OF 256
495  CLKPR=0x08; // BOARD MUST BE RESET TO RESUME NORMAL OPERATIONS
496 
497  break;
498 
499 /***** WRITE A DCC PACKET TO ONE OF THE REGSITERS DRIVING THE MAIN OPERATIONS TRACK ****/
500 
501  case 'M': // <M REGISTER BYTE1 BYTE2 [BYTE3] [BYTE4] [BYTE5]>
502 /*
503  * writes a DCC packet of two, three, four, or five hexidecimal bytes to a register driving the main operations track
504  * FOR DEBUGGING AND TESTING PURPOSES ONLY. DO NOT USE UNLESS YOU KNOW HOW TO CONSTRUCT NMRA DCC PACKETS - YOU CAN INADVERTENTLY RE-PROGRAM YOUR ENGINE DECODER
505  *
506  * REGISTER: an internal register number, from 0 through MAX_MAIN_REGISTERS (inclusive), to write (if REGISTER=0) or write and store (if REGISTER>0) the packet
507  * BYTE1: first hexidecimal byte in the packet
508  * BYTE2: second hexidecimal byte in the packet
509  * BYTE3: optional third hexidecimal byte in the packet
510  * BYTE4: optional fourth hexidecimal byte in the packet
511  * BYTE5: optional fifth hexidecimal byte in the packet
512  *
513  * returns: NONE
514  */
515  DCCppClass::mainRegs.writeTextPacket(com+1);
516  break;
517 
518 /***** WRITE A DCC PACKET TO ONE OF THE REGSITERS DRIVING THE MAIN OPERATIONS TRACK ****/
519 
520  case 'P': // <P REGISTER BYTE1 BYTE2 [BYTE3] [BYTE4] [BYTE5]>
521 /*
522  * writes a DCC packet of two, three, four, or five hexidecimal bytes to a register driving the programming track
523  * FOR DEBUGGING AND TESTING PURPOSES ONLY. DO NOT USE UNLESS YOU KNOW HOW TO CONSTRUCT NMRA DCC PACKETS - YOU CAN INADVERTENTLY RE-PROGRAM YOUR ENGINE DECODER
524  *
525  * REGISTER: an internal register number, from 0 through MAX_MAIN_REGISTERS (inclusive), to write (if REGISTER=0) or write and store (if REGISTER>0) the packet
526  * BYTE1: first hexidecimal byte in the packet
527  * BYTE2: second hexidecimal byte in the packet
528  * BYTE3: optional third hexidecimal byte in the packet
529  * BYTE4: optional fourth hexidecimal byte in the packet
530  * BYTE5: optional fifth hexidecimal byte in the packet
531  *
532  * returns: NONE
533  */
534  DCCppClass::progRegs.writeTextPacket(com+1);
535  break;
536 
537 /***** ATTEMPTS TO DETERMINE HOW MUCH FREE SRAM IS AVAILABLE IN ARDUINO ****/
538 
539 #ifndef VISUALSTUDIO
540  case 'F': // <F>
541 /*
542  * measure amount of free SRAM memory left on the Arduino based on trick found on the internet.
543  * Useful when setting dynamic array sizes, considering the Uno only has 2048 bytes of dynamic SRAM.
544  * Unfortunately not very reliable --- would be great to find a better method
545  *
546  * returns: <f MEM>
547  * where MEM is the number of free bytes remaining in the Arduino's SRAM
548  */
549  int v;
550  INTERFACE.print("<f");
551  INTERFACE.print((int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval));
552  INTERFACE.println(">");
553  break;
554 #endif
555 
556 /***** LISTS BIT CONTENTS OF ALL INTERNAL DCC PACKET REGISTERS ****/
557 
558  case 'L': // <L>
559 /*
560  * lists the packet contents of the main operations track registers and the programming track registers
561  * FOR DIAGNOSTIC AND TESTING USE ONLY
562  */
563  INTERFACE.println("");
564  for(Register *p = DCCppClass::mainRegs.reg; p <= DCCppClass::mainRegs.maxLoadedReg;p++){
565  INTERFACE.print("M"); INTERFACE.print((int)(p - DCCppClass::mainRegs.reg)); INTERFACE.print(":t");
566  INTERFACE.print((int)p); INTERFACE.print("t");
567  INTERFACE.print((int)(p->activePacket)); INTERFACE.print("t");
568  INTERFACE.print(p->activePacket->nBits); INTERFACE.print("t");
569  for(int i=0;i<10;i++){
570  INTERFACE.print(p->activePacket->buf[i],HEX); INTERFACE.print("t");
571  }
572  INTERFACE.println("");
573  }
574  for(Register *p = DCCppClass::progRegs.reg; p <= DCCppClass::progRegs.maxLoadedReg;p++){
575  INTERFACE.print("P"); INTERFACE.print((int)(p - DCCppClass::progRegs.reg)); INTERFACE.print(":t");
576  INTERFACE.print((int)p); INTERFACE.print("t");
577  INTERFACE.print((int)p->activePacket); INTERFACE.print("t");
578  INTERFACE.print(p->activePacket->nBits); INTERFACE.print("t");
579  for(int i=0;i<10;i++){
580  INTERFACE.print(p->activePacket->buf[i],HEX); INTERFACE.print("t");
581  }
582  INTERFACE.println("");
583  }
584  INTERFACE.println("");
585  break;
586 
587  } // switch
588 }; // SerialCommand::parse
589 
591 
592 #endif