#include #include #include #include #include /* Constants */ #define FORWARD 1 #define REVERSE 0 #define FALSE 0 #define TRUE 1 #define ESCAPE 27 #define ENTER 13 #define UP_ARROW 0x9000 #define DOWN_ARROW 0xA000 #define RIGHT_ARROW 0x9A00 #define LEFT_ARROW 0x9600 #define BACKSPACE 8 #define uns unsigned #define unsl unsigned long #define NUM_CVS 107 #define LOCO_MFR_SIZE 10 #define LOCO_MODEL_SIZE 15 #define NUM_LOCOS 100 #define LOCO_SIZE (sizeof(struct loco_struct)) #define PICK_SIZE (sizeof(struct pick_struct)) #define DCC_MODEL_SIZE 15 #define NUM_DCC_MFRS 20 /* Prototypes */ int ClearBuffer(void); void Main_Menu(void); void FatalError(void); void DumpLocoData(void); void Dequeue_Packets(void); /* Structures */ struct loco_struct { char loco_mfr[LOCO_MFR_SIZE]; char loco_model[LOCO_MODEL_SIZE]; char dcc_model[DCC_MODEL_SIZE]; char dcc_mfr; short cv[NUM_CVS]; short reg[9]; char rescan; char paged; }; struct pick_struct { char name[40]; char index; char consist; char grabbed; short speed; short steps; short local_speed; short local_dir; short direction; char f[9]; }; struct dcc_mfr_struct { int id; char name[30]; }; /* Globals */ char com_port = 1; char buf[80]; char version[20]; PORT *port; int consist_scan = FALSE; int throttle_scan = FALSE; struct loco_struct *Loco[NUM_LOCOS]; struct pick_struct *Pick[NUM_LOCOS]; int Throttle[102]; short *LocoConsist; char *Queued; int DigitraxCVs[] = { 1,2,3,4,5,6,7,8,13,17,18,19,29,49,50,51,52,53,54,55,56,57,61,62,63,65,66, 67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, 90,91,92,93,94,95,105,106,-1 }; int LenzCVs[] = { 1,2,3,4,7,8,17,18,19,23,24,29,50,51,52,53,54,56,67,68,69,70,71,72,73,74, 75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,105,106,-1 }; int ZimoCVs[] = { 1,2,3,4,5,6,7,8,9,17,18,19,29,33,34,35,36,37,38,39,40,41,42,49,50,51,52, 53,54,55,56,57,58,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76, 77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,-1 }; int WangrowCVs[] = { 1,2,3,4,7,8,17,18,19,23,24,29,67,68,69,70,71,72,73,74,75,76,77,78,79,80, 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,-1 }; int NCECVs[] = { 1,2,3,4,9,17,18,19,23,24,29,30,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, 81,82,83,84,85,86,87,88,89,90,91,92,93,94,-1 }; struct dcc_mfr_struct dcc_mfr[] = { {0, "Unknown"}, {137, "A-Train Electronics"}, {135, "CVP Products"}, {129, "Digitrax"}, {133, "ICC"}, {99, "Lenz"}, {143, "MRC"}, {11, "NCE"}, {14, "PSI Dynatrol"}, {15, "Ramfixx"}, {139, "RealRail"}, {141, "Throttle-up"}, {131, "Trix"}, {12, "Wangrow"}, {145, "Zimo"}, {132, "ZTC"}, {1, "Arnold"}, {2, "Consist"}, {127, "Atlas"}, {13, "Homebrew"} }; #define DIGITRAX 3 #define LENZ 5 #define MRC 6 #define NCE 7 #define ARNOLD 16 #define ZIMO 14 #define WANGROW 13 #define CONSIST 17 #define ATLAS 18 char *Directions[] = {"Reverse", "Forward"}; char *decoder2regs[] = { "?", "Data 0", "Data 1", "Data 2", "Data 3", "Basic Config CV029", "Page", "Version CV007", "Manufacturer CV008" }; char *decoder1regs[] = { "?", "CV1, Decoder Address", "CV2, Vstart", "CV3, Accel Rate", "CV4, Brake Rate", "CV29, Basic Config", "Page", "CV7, Decoder Version", "CV8, Manufacturer" }; unsigned Speed_Parms28[] = { 0x00, /* stop */ 0x02, /* step 1 */ 0x12, /* step 2 */ 0x03, /* step 3 */ 0x13, /* step 4 */ 0x04, /* step 5 */ 0x14, /* step 6 */ 0x05, /* step 7 */ 0x15, /* step 8 */ 0x06, /* step 9 */ 0x16, /* step 10 */ 0x07, /* step 11 */ 0x17, /* step 12 */ 0x08, /* step 13 */ 0x18, /* step 14 */ 0x09, /* step 15 */ 0x19, /* step 16 */ 0x0A, /* step 17 */ 0x1A, /* step 18 */ 0x0B, /* step 19 */ 0x1B, /* step 20 */ 0x0C, /* step 21 */ 0x1C, /* step 22 */ 0x0D, /* step 23 */ 0x1D, /* step 24 */ 0x0E, /* step 25 */ 0x1E, /* step 26 */ 0x0F, /* step 27 */ 0x1F /* step 28 */ }; /*************************************************************************** Download the EPROM version number */ void GetVersion(void) { WriteBuffer(port, "V\r", 2); ReadBufferTimed(port, version, 13, 1000); if (port->count != 13) { FatalError(); } ClearBuffer(); } /*************************************************************************** EasyX - main */ void main(int argc, char **argv) { int n; int i = 0; FILE *fp; system("cls"); if (argc > 1) { if (stricmp(argv[1], "com2") == 0 || stricmp(argv[1], "2") == 0) { com_port = 2; } } LocoConsist = malloc((size_t) 10000 * sizeof(short)); Queued = malloc((size_t) 10000 * sizeof(char)); for (i = 0; i != 10000; ++i) { LocoConsist[i] = 0; Queued[i] = FALSE; } for (i = 0; i != NUM_LOCOS; ++i) { Loco[i] = malloc(LOCO_SIZE); if (Loco[i] == NULL) { exit (0); } memset(Loco[i], 0, LOCO_SIZE); Pick[i] = malloc(PICK_SIZE); if (Pick[i] == NULL) { exit (0); } memset(Pick[i], 0, PICK_SIZE); } fp = fopen("LOCO.DAT", "r+b"); i = 0; if (fp != NULL) { do { n = fread(Loco[i], LOCO_SIZE, 1, fp); ++i; } while (n == 1 && i < NUM_LOCOS); } else { fp = fopen("LOCO.DAT", "w+b"); } fclose(fp); system("cls"); if (com_port == 1) { port = PortOpenGreenleaf(COM1, 9600L, 'N', 8, 1); } else { port = PortOpenGreenleaf(COM2, 9600L, 'N', 8, 1); } if (port->status != ASSUCCESS) { printf("Open on COM%d failed, error: %d\n", com_port, port->status); printf("If your serial port is configured as COM2, type: EASYX COM2\n"); exit (0); } system("cls"); printf("Attempting to contact EasyDCC Command Station on COM%d...", com_port); ClearBuffer(); GetVersion(); Main_Menu(); system("cls"); Dequeue_Packets(); PortClose(port); DumpLocoData(); exit (0); } /*************************************************************************** remove control characters from string */ void Strip(char *str) { int i; for (i = 0; i < strlen(str); ++i) { if (str[i] < ' ') { str[i] = 0; } } } /************************************************************************** Convert a hex string to an integer */ short HexToInt(char *str) { int i; int n; int factor; int l = strlen(str); short result = 0; for (i = 0; i < l; ++i) { if (str[i] >= '0' && str[i] <= '9') { n = str[i] - '0'; } else if (str[i] >= 'A' && str[i] <= 'F') { n = str[i] - 'A' + 10; } else { system("cls"); printf("Bad param in HexToInt:\n %s\n", str); exit (0); } if (i == l - 1) { factor = 1; } else if (i == l - 2) { factor = 16; } else if (i == l - 3) { factor = 256; } else if (i == l - 4) { factor = 4096; } else { return (-1); } result += (short) (n * factor); } return (result); } /*************************************************************************** return loco addr (cv1 or cv17+18, depending on cv29 bit 5) */ int LocoAddr(int l) { int addr = Loco[l]->cv[1]; char temp[5]; if (Loco[l]->cv[29] & 0x20) { sprintf(temp, "%.2X%.2X", Loco[l]->cv[17] & 0x3F, Loco[l]->cv[18]); addr = HexToInt(temp); } return (addr); } /*************************************************************************** return loco addr (cv1 or v17+18, depending on cv29 bit 5) suitable for use over the RS-232 port */ uns NetAddr(int l) { uns addr = Loco[l]->cv[1]; char temp[5]; if (Loco[l]->cv[29] & 0x20) { sprintf(temp, "%.2X%.2X", Loco[l]->cv[17], Loco[l]->cv[18]); addr = HexToInt(temp); } return (addr); } /*************************************************************************** select a locomotive to configure */ int Select_Loco(int p_track) { int i; int n; int top = 0; int bot = 14; int cur = 0; int avail = -1; int num_locos = 0; int done = FALSE; int get_loco_data = FALSE; FILE *fp; do { num_locos = 0; get_loco_data = 0; for (i = 0; i != NUM_LOCOS; ++i) { if (Loco[i]->dcc_mfr == 0) { if (avail < 0) { avail = i; } } else if (Loco[i]->dcc_mfr != CONSIST) { sprintf ( Pick[num_locos]->name, "%04d %s %s", LocoAddr(i), Loco[i]->loco_mfr, Loco[i]->loco_model ); Pick[num_locos]->index = i; ++num_locos; } } if (avail != -1) { Pick[num_locos]->index = avail; strcpy(Pick[num_locos]->name, "Add new locomotive"); ++num_locos; } if (num_locos == 1) { get_loco_data = TRUE; } else { system("cls"); printf("Use UP/DOWN Arrows and ENTER to select a locomotive\n"); printf("ESC=Done, D=Delete, F=Write roster to file: "); for (i = 0; i != 15; ++i) { _settextposition(i + 4, 1); if (top + i >= num_locos) { printf(" "); } else { if (top + i == cur) { printf("->"); } else { printf(" "); } printf("%s", Pick[i + top]->name); } } _settextposition((cur - top) + 4, 1); buf[0] = 0; n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return (-1); } else if (n == ENTER) { if (cur == num_locos - 1) { get_loco_data = TRUE; } else if (p_track != -1) { system("cls"); printf("Edit locomotive information (Y/N)? "); do { buf[0] = 0; n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return (-1); } } while (buf[0] != 'Y' && buf[0] != 'N'); if (buf[0] == 'Y') { get_loco_data = TRUE; avail = Pick[cur]->index; } } done = TRUE; } else if (n == UP_ARROW) { if (cur != 0) { --cur; if (top > cur) { top = cur; --bot; } } } else if (n == DOWN_ARROW) { if (cur != num_locos - 1) { ++cur; if (cur > bot) { bot = cur; ++top; } } } else if (buf[0] == 'F') { fp = fopen("LOCO.TXT", "w"); for (i = 0; i != NUM_LOCOS; ++i) { if (Loco[i]->dcc_mfr != 0) { fprintf ( fp, "#%04d %s %s (%s %s)\n", LocoAddr(i), Loco[i]->loco_mfr, Loco[i]->loco_model, dcc_mfr[Loco[i]->dcc_mfr].name, Loco[i]->dcc_model ); } } fclose(fp); system("cls"); printf("Locomotive roster listing written to file: LOCO.TXT\n\n"); printf("Press a key: "); GetText(buf, 1, TRUE); system("cls"); } else if (buf[0] == 'D') { system("cls"); printf("Really delete %s (y/n)? ", Pick[cur]->name); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'Y' && buf[0] != 'N'); if (buf[0] == 'Y') { Loco[Pick[cur]->index]->dcc_mfr = 0; cur = 0; top = 0; bot = 14; } } } if (get_loco_data) { system("cls"); printf("Enter locomotive information\n\n"); printf("Manufacturer's name: "); n = GetText(Loco[avail]->loco_mfr, LOCO_MFR_SIZE - 1, FALSE); if (n != ESCAPE) { printf("\n\nDescription: "); n = GetText(Loco[avail]->loco_model, LOCO_MODEL_SIZE - 1, FALSE); } else { return (-1); } printf("\n\nDecoder model: "); n = GetText(Loco[avail]->dcc_model, DCC_MODEL_SIZE - 1, FALSE); if (n != ESCAPE) { Loco[avail]->rescan = TRUE; if (p_track == FALSE && Loco[avail]->dcc_mfr == 0) { system("cls"); for (i = 1; i != NUM_DCC_MFRS - 1; ++i) { printf("%c: %s\n", (i - 1) + 'A', dcc_mfr[i].name); } printf("\nEnter decoder mfr (A-P): "); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && (buf[0] < 'A' || buf[0] > 'P')); if (n == ESCAPE) { return (-1); } Loco[avail]->dcc_mfr = buf[0] - 'A' + 1; for (i = 1; i != NUM_CVS; ++i) { if (i < 9 || i == 29) { Loco[avail]->cv[i] = 0; } else { Loco[avail]->cv[i] = -1; } } Loco[avail]->cv[8] = dcc_mfr[Loco[avail]->dcc_mfr].id; printf("\nEnter primary locomotive address: "); n = GetText(buf, 3, FALSE); if (n == ESCAPE) { return (-1); } Loco[avail]->cv[1] = atoi(buf); if (Loco[avail]->cv[1] < 1 || Loco[avail]->cv[1] > 99) { Loco[avail]->cv[1] = 3; } } return (avail); } else { return (-1); } } } while (!done); if (p_track == TRUE && !Loco[Pick[cur]->index]->rescan) { system("cls"); printf("Rescan CV's (Y/N)? "); do { buf[0] = 0; n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return (-1); } } while (buf[0] != 'Y' && buf[0] != 'N'); if (buf[0] == 'Y') { Loco[Pick[cur]->index]->rescan = TRUE; } } return (Pick[cur]->index); } /*************************************************************************** Text description of a CV */ void CV_Text(int i, int decoder) { if (decoder == ATLAS) { decoder = LENZ; } switch (i) { case 1: printf("Locomotive ID (Address)\n"); break; case 2: printf("VSTART - Voltage level at first speed step\n"); break; case 3: printf("Acceleration Rate. The number of seconds to execute\n"); printf("an acceleration request = (CV3 * .896) / #STEPS\n"); printf("The higher the value, the slower the acceleration\n"); break; case 4: printf("Braking Rate. The number of seconds to execute a braking\n"); printf("request = (CV4 * .896) / #STEPS\n"); printf("The higher the value, the longer the braking distance\n"); break; case 5: printf("VMAX - Voltage level at maximum speed step\n"); break; case 6: printf("VMID - Voltage level at middle speed step\n"); break; case 7: printf("Decoder version number\n"); break; case 8: printf("Decoder manufacturer ID number\n"); break; case 9: printf("Total PWM period (motor pulse rate).\n"); printf("0=16kHz, 192=120Hz, 208=80Hz, 223=60Hz, 255=30Hz\n"); break; case 10: printf("EMF feedback cutout - speed step at which constant-speed\n"); printf("monitoring stops\n"); break; case 11: printf("Packet timeout - number of seconds decoder will maintain\n"); printf("current speed without receiving a new packet. 0=never timeout\n"); break; case 12: printf("Alternate power source type:\n"); printf("1 : Analog\n"); printf("2 : Radio\n"); printf("4 : Zero-1\n"); printf("8 : TRIX\n"); printf("16: CTC-16/Railcommand\n"); break; case 13: printf("Analog mode function states\n"); break; case 17: case 18: printf("CV17: Extended address MSB (enabled by CV29, bit 5)\n"); printf("CV18: Extended address LSB (enabled by CV29, bit 5)\n"); break; case 19: printf("Advanced consist number (bit 7=1 indicates reverse direction)\n"); break; case 21: printf("Respond to functions addressed to consist:\n"); printf(" Bit 0: F1 0=No, 1=Yes\n"); printf(" Bit 1: F2 0=No, 1=Yes\n"); printf(" Bit 2: F3 0=No, 1=Yes\n"); printf(" Bit 3: F4 0=No, 1=Yes\n"); printf(" Bit 4: F5 0=No, 1=Yes\n"); printf(" Bit 5: F6 0=No, 1=Yes\n"); printf(" Bit 6: F7 0=No, 1=Yes\n"); printf(" Bit 7: F8 0=No, 1=Yes\n"); break; case 22: printf("Respond to FL addressed to consist: 0=No, 1=Yes\n"); break; case 23: printf("Acceleration trim - additional acceleration rate to be\n"); printf("added to or subtracted from the base value in CV3\n"); printf("bit 7: 0=add, 1=subtract\n"); break; case 24: printf("Deceleration trim - additional deceleration rate to be\n"); printf("added to or subtracted from the base value in CV4\n"); printf("bit 7: 0=add, 1=subtract\n"); break; case 25: printf("Someone will have to explain this CV to me, I don't get it...\n"); break; case 29: printf("Basic Configuration:\n"); printf("Bit 0 - Locomotive direction (0=wires normal, 1=wires reversed)\n"); printf("Bit 1 - FL location (0=14 speed steps, 1=28 speed steps)\n"); printf("Bit 2 - Power source conversion (0=DCC only, 1=Analog OK)\n"); printf("Bit 3 - Advanced decoder acknowledgement - unused at this time\n"); printf("Bit 4 - Speed table (0=Table from CV2,5,6 1=Table from CV65-95)\n"); printf("Bit 5 - Extended addressing (0=disabled, 1=enabled)\n"); printf("Bit 6 - Unused\n"); printf("Bit 7 - Decoder type (0=Multifunction, 1=Accessory)\n"); break; case 30: printf("Current error condition. 0=no error\n"); break; case 33: printf("Output for FL-forward:\n"); printf(" Bit 0: 1=output #1\n"); printf(" Bit 1: 1=output #2\n"); printf(" Bit 2: 1=output #3\n"); printf(" Bit 3: 1=output #4\n"); printf(" Bit 4: 1=output #5\n"); printf(" Bit 5: 1=output #6\n"); printf(" Bit 6: 1=output #7\n"); printf(" Bit 7: 1=output #8\n"); break; case 34: printf("Output for FL-reverse:\n"); printf(" Bit 0: 1=output #1\n"); printf(" Bit 1: 1=output #2\n"); printf(" Bit 2: 1=output #3\n"); printf(" Bit 3: 1=output #4\n"); printf(" Bit 4: 1=output #5\n"); printf(" Bit 5: 1=output #6\n"); printf(" Bit 6: 1=output #7\n"); printf(" Bit 7: 1=output #8\n"); break; case 35: printf("Output for F1:\n"); printf(" Bit 0: 1=output #1\n"); printf(" Bit 1: 1=output #2\n"); printf(" Bit 2: 1=output #3\n"); printf(" Bit 3: 1=output #4\n"); printf(" Bit 4: 1=output #5\n"); printf(" Bit 5: 1=output #6\n"); printf(" Bit 6: 1=output #7\n"); printf(" Bit 7: 1=output #8\n"); break; case 36: printf("Output for F2:\n"); printf(" Bit 0: 1=output #1\n"); printf(" Bit 1: 1=output #2\n"); printf(" Bit 2: 1=output #3\n"); printf(" Bit 3: 1=output #4\n"); printf(" Bit 4: 1=output #5\n"); printf(" Bit 5: 1=output #6\n"); printf(" Bit 6: 1=output #7\n"); printf(" Bit 7: 1=output #8\n"); break; case 37: printf("Output for F3:\n"); printf(" Bit 0: 1=output #4\n"); printf(" Bit 1: 1=output #5\n"); printf(" Bit 2: 1=output #6\n"); printf(" Bit 3: 1=output #7\n"); printf(" Bit 4: 1=output #8\n"); printf(" Bit 5: 1=output #9\n"); printf(" Bit 6: 1=output #10\n"); printf(" Bit 7: 1=output #11\n"); break; case 38: printf("Output for F4:\n"); printf(" Bit 0: 1=output #4\n"); printf(" Bit 1: 1=output #5\n"); printf(" Bit 2: 1=output #6\n"); printf(" Bit 3: 1=output #7\n"); printf(" Bit 4: 1=output #8\n"); printf(" Bit 5: 1=output #9\n"); printf(" Bit 6: 1=output #10\n"); printf(" Bit 7: 1=output #11\n"); break; case 39: printf("Output for F5:\n"); printf(" Bit 0: 1=output #4\n"); printf(" Bit 1: 1=output #5\n"); printf(" Bit 2: 1=output #6\n"); printf(" Bit 3: 1=output #7\n"); printf(" Bit 4: 1=output #8\n"); printf(" Bit 5: 1=output #9\n"); printf(" Bit 6: 1=output #10\n"); printf(" Bit 7: 1=output #11\n"); break; case 40: printf("Output for F6:\n"); printf(" Bit 0: 1=output #4\n"); printf(" Bit 1: 1=output #5\n"); printf(" Bit 2: 1=output #6\n"); printf(" Bit 3: 1=output #7\n"); printf(" Bit 4: 1=output #8\n"); printf(" Bit 5: 1=output #9\n"); printf(" Bit 6: 1=output #10\n"); printf(" Bit 7: 1=output #11\n"); break; case 41: printf("Output for F7:\n"); printf(" Bit 0: 1=output #7\n"); printf(" Bit 1: 1=output #8\n"); printf(" Bit 2: 1=output #9\n"); printf(" Bit 3: 1=output #10\n"); printf(" Bit 4: 1=output #11\n"); printf(" Bit 5: 1=output #12\n"); printf(" Bit 6: 1=output #13\n"); printf(" Bit 7: 1=output #14\n"); break; case 42: printf("Output for F8:\n"); printf(" Bit 0: 1=output #7\n"); printf(" Bit 1: 1=output #8\n"); printf(" Bit 2: 1=output #9\n"); printf(" Bit 3: 1=output #10\n"); printf(" Bit 4: 1=output #11\n"); printf(" Bit 5: 1=output #12\n"); printf(" Bit 6: 1=output #13\n"); printf(" Bit 7: 1=output #14\n"); break; case 49: if (decoder == ZIMO) { printf("Signal controlled acceleration.\n"); } else if (decoder == DIGITRAX) { printf("Forward light effect, F0F\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 50: if (decoder == LENZ) { printf("Decoder configuration, byte 2:\n"); printf("Bit 0 - Not used\n"); printf("Bit 1 - 0=CV23/24 inactive, 1=CV23/24 modify CV3/4\n"); printf("Bit 2 - Brake momentum on DC operation (see manual)\n"); printf("Bit 3 - Not used\n"); printf("Bit 4 - Not used\n"); printf("Bit 5 - Not used\n"); printf("Bit 6 - Not used\n"); printf("Bit 7 - Not used\n"); } else if (decoder == ZIMO) { printf("Signal controlled deceleration\n"); } else if (decoder == DIGITRAX) { printf("Reverse light effect, F0R\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 51: if (decoder == LENZ) { printf("Lighting special effects for outputs A and B\n"); printf("Bit 0- 0:Directional headlights, 1:F0=Front, F1=Rear\n"); printf("Bit 1- 0:Dimming Disabled 1:CV52 Determines Dimming\n"); printf("Bit 2- 1:Bit 0 set and Bit 1 set=F4 dims F0\n"); printf("Bit 3- 1:Bit 0 set and Bit 2 set=F4 dims F1\n"); } else if (decoder == ZIMO) { printf("Signal controlled speed limit\n"); } else if (decoder == DIGITRAX) { printf("Function 1 effect\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 52: if (decoder == LENZ) { printf("Dimming - 0=dark, 255=max brightness\n"); } else if (decoder == DIGITRAX) { printf("Function 2 effect\n"); } else if (decoder == ZIMO) { printf("Signal controlled speed limit\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 53: if (decoder == LENZ) { printf("Lighting special effects for outputs C and D\n"); printf("Bit 0: 1=Output C blinks per CV56\n"); printf("Bit 1: 1=Output D blinks per CV56\n"); printf("Bit 2: 1=Outputs C&D act as Ditch Lights\n"); } else if (decoder == DIGITRAX) { printf("Function 3 effect\n"); } else if (decoder == ZIMO) { printf("Signal controlled speed limit\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 54: if (decoder == LENZ) { printf("Function assignment for output C\n"); printf("Bit 0: Output C is controlled by F1\n"); printf("Bit 1: Output C is controlled by F2\n"); printf("Bit 2: Output C is controlled by F3\n"); printf("Bit 3: Output C is controlled by F4\n"); printf("Bit 4: Output C is controlled by F5\n"); printf("Bit 5: Output C is controlled by F6\n"); printf("Bit 6: Output C is controlled by F7\n"); printf("Bit 7: Output C is controlled by F8\n"); } else if (decoder == DIGITRAX) { printf("Function 4 effect\n"); } else if (decoder == ZIMO) { printf("Signal controlled speed limit\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 55: if (decoder == LENZ) { printf("Function assignment for output D\n"); printf("Bit 0: Output D is controlled by F1\n"); printf("Bit 1: Output D is controlled by F2\n"); printf("Bit 2: Output D is controlled by F3\n"); printf("Bit 3: Output D is controlled by F4\n"); printf("Bit 4: Output D is controlled by F5\n"); printf("Bit 5: Output D is controlled by F6\n"); printf("Bit 6: Output D is controlled by F7\n"); printf("Bit 7: Output D is controlled by F8\n"); } else if (decoder == ZIMO) { printf("Signal controlled speed limit\n"); } else if (decoder == DIGITRAX) { printf("BEMF Static Compensation. This is like the stiffness of a spring.\n"); printf("The stiffer the spring, the more compensation you get. High values\n"); printf("give a more intense reaction and lower values give a less intense\n"); printf("reaction. Factory default is 80.\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 56: if (decoder == LENZ) { printf("Blink rate for outputs C and D\n"); } else if (decoder == ZIMO) { printf("Parameters for PID load compensation\n"); } else if (decoder == DIGITRAX) { printf("BEMF Dynamic Compensation. This is like the shock absorber on the spring\n"); printf("that helps to restore the spring to its new position. High values cause\n"); printf("rapid adaption to target speed and low values cause slower adaption to\n"); printf("target speed. Factory default is 30 (hex)\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 57: printf("Decoder specific function, see manual\n"); break; case 61: if (decoder == DIGITRAX) { printf("Direction headlight config & split field motor config\n"); } else if (decoder == ZIMO) { printf("Special ZIMO function mapping\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 62: if (decoder == DIGITRAX) { printf("FX rate and keep alive adjust\n"); } else if (decoder == ZIMO) { printf("Special speed table for sound effects\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 63: if (decoder == DIGITRAX) { printf("Ditch light blink hold time\n"); } else if (decoder == ZIMO) { printf("Special speed table for sound effects\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 64: if (decoder == ZIMO) { printf("Special speed table for sound effects\n"); } else { printf("Decoder specific function, see manual\n"); } break; case 65: printf("Kick start. Amount of extra kick when transition to step 1\n"); break; case 66: printf("Forward trim. Amount to multiply forward drive voltage by\n"); break; case 67: printf("Speed table - step 1\n"); break; case 68: printf("Speed table - step 2\n"); break; case 69: printf("Speed table - step 3\n"); break; case 70: printf("Speed table - step 4\n"); break; case 71: printf("Speed table - step 5\n"); break; case 72: printf("Speed table - step 6\n"); break; case 73: printf("Speed table - step 7\n"); break; case 74: printf("Speed table - step 8\n"); break; case 75: printf("Speed table - step 9\n"); break; case 76: printf("Speed table - step 10\n"); break; case 77: printf("Speed table - step 11\n"); break; case 78: printf("Speed table - step 12\n"); break; case 79: printf("Speed table - step 13\n"); break; case 80: printf("Speed table - step 14\n"); break; case 81: printf("Speed table - step 15\n"); break; case 82: printf("Speed table - step 16\n"); break; case 83: printf("Speed table - step 17\n"); break; case 84: printf("Speed table - step 18\n"); break; case 85: printf("Speed table - step 19\n"); break; case 86: printf("Speed table - step 20\n"); break; case 87: printf("Speed table - step 21\n"); break; case 88: printf("Speed table - step 22\n"); break; case 89: printf("Speed table - step 23\n"); break; case 90: printf("Speed table - step 24\n"); break; case 91: printf("Speed table - step 25\n"); break; case 92: printf("Speed table - step 26\n"); break; case 93: printf("Speed table - step 27\n"); break; case 94: printf("Speed table - step 28\n"); break; case 95: printf("Reverse trim - Amount to multiple reverse voltage by\n"); break; case 105: printf("User private ID #1\n"); break; case 106: printf("User private ID #2\n"); break; default: printf("Unknown function\n"); break; } } /*************************************************************************** Return binary value of a number */ char *BinValue(int x) { static char bits[9]; if (x & 1) { bits[7] = '1'; } else { bits[7] = '0'; } if (x & 2) { bits[6] = '1'; } else { bits[6] = '0'; } if (x & 4) { bits[5] = '1'; } else { bits[5] = '0'; } if (x & 8) { bits[4] = '1'; } else { bits[4] = '0'; } if (x & 0x10) { bits[3] = '1'; } else { bits[3] = '0'; } if (x & 0x20) { bits[2] = '1'; } else { bits[2] = '0'; } if (x & 0x40) { bits[1] = '1'; } else { bits[1] = '0'; } if (x & 0x80) { bits[0] = '1'; } else { bits[0] = '0'; } return (bits); } /************************************************************************** Look up decoder manufacturer */ int Find_Mfr(int cv8) { int i; for (i = 0; i != NUM_DCC_MFRS; ++i) { if (cv8 == dcc_mfr[i].id) { return (i); } } return (0); } /************************************************************************** Reload decoder CV/Reg values */ int Rescan_Decoder(int loco) { int p; int col; int cv; char c; char temp[4]; int i; int n; Loco[loco]->rescan = FALSE; Loco[loco]->paged = 0; Loco[loco]->dcc_mfr = 0; system("cls"); printf("Querying programming track..."); /* Get decoder mfr - try CV #8 directly */ sprintf(buf, "R008\r"); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 8, -1L); temp[0] = buf[5]; temp[1] = buf[6]; temp[2] = 0; if ( strncmp(buf, "CV", 2) == 0 && buf[5] != '-' && atoi(temp) != 0 && Find_Mfr(HexToInt(temp)) != 0 && HexToInt(temp) != 2 ) { ClearBuffer(); printf("\n\nDirect-Read CVs detected\n"); Loco[loco]->cv[8] = HexToInt(temp); Loco[loco]->paged = FALSE; } else { printf("\n\nDirect-Read CVs not detected, querying registers..."); /* No go, try reg 8 (mfr) next */ ClearBuffer(); strcpy(buf, "V8\r"); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 5, -1L); Strip(buf); ClearBuffer(); if (port->count == 0 || buf[2] == '-') { printf("\n\nProgramming track failure - can't communicate with decoder.\n"); printf("Press a key:"); GetText(buf, 1, TRUE); WriteBuffer(port, "X\r", 2); ClearBuffer(); return (-1); } printf("\n\nPage-Mode CVs detected\n"); temp[0] = buf[2]; temp[1] = buf[3]; temp[2] = 0; Loco[loco]->reg[8] = HexToInt(temp); Loco[loco]->cv[8] = Loco[loco]->reg[8]; Loco[loco]->paged = TRUE; ClearBuffer(); } if (Loco[loco]->cv[8] == 2) { Loco[loco]->cv[8] = 0; } i = Find_Mfr(Loco[loco]->cv[8]); Loco[loco]->dcc_mfr = i; printf("Decoder mfr is: %s\n", dcc_mfr[i].name); for (i = 0; i != NUM_CVS; ++i) { Loco[loco]->cv[i] = -1; } if (Loco[loco]->dcc_mfr == DIGITRAX) { for (i = 0; DigitraxCVs[i] != -1; ++i) { Loco[loco]->cv[DigitraxCVs[i]] = 0; } } else if (Loco[loco]->dcc_mfr == LENZ || Loco[loco]->dcc_mfr == ATLAS) { for (i = 0; LenzCVs[i] != -1; ++i) { Loco[loco]->cv[LenzCVs[i]] = 0; } } else if (Loco[loco]->dcc_mfr == WANGROW) { for (i = 0; WangrowCVs[i] != -1; ++i) { Loco[loco]->cv[WangrowCVs[i]] = 0; } } else if (Loco[loco]->dcc_mfr == NCE) { for (i = 0; NCECVs[i] != -1; ++i) { Loco[loco]->cv[NCECVs[i]] = 0; } } else if (Loco[loco]->dcc_mfr == ZIMO) { for (i = 0; ZimoCVs[i] != -1; ++i) { Loco[loco]->cv[ZimoCVs[i]] = 0; } } else { Loco[loco]->cv[1] = 0; Loco[loco]->cv[2] = 0; Loco[loco]->cv[3] = 0; Loco[loco]->cv[4] = 0; Loco[loco]->cv[7] = 0; Loco[loco]->cv[8] = 0; Loco[loco]->cv[29] = 0; } if (!Loco[loco]->paged) { printf("\nScanning CVs...\n\n"); for (i = 1, col = 0; i != NUM_CVS; ++i) { if (Loco[loco]->cv[i] != -1) { sprintf(buf, "R%.3X\r", i); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 8, -1L); if (strncmp(buf, "CV", 2) == 0 && buf[5] != '-') { temp[0] = buf[5]; temp[1] = buf[6]; temp[2] = 0; Loco[loco]->cv[i] = HexToInt(temp); printf("CV%03d: %03d ", i, Loco[loco]->cv[i]); ++col; if (col == 6) { col = 0; printf("\n"); } } else { Loco[loco]->cv[i] = -1; printf("\nUnsupported CV: %d (%-7.7s)\n", i, buf); } ClearBuffer(); } } } if (Loco[loco]->paged) { /* OK, now scan the CVS - one page at a time */ printf("Now scanning CVs in page mode...\n\n"); for (p = 1, col = 0; p != 28; ++p) { sprintf(buf, "S 6 %.2X\r", p); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1L); if (buf[0] != 'P') { system("cls"); printf("Unable to set page register to #%d\n", p); printf("Press any key to continue: "); GetText(buf, 1, TRUE); return (-1); } else { Loco[loco]->reg[6] = p; } for (i = 1; i <= 4; ++i) { cv = (((p - 1) * 4) + i); if (cv < NUM_CVS && Loco[loco]->cv[cv] != -1) { sprintf(buf, "V%d\r", i); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 5, -1L); Strip(buf); if (port->count == 0 || buf[2] == '-') { Loco[loco]->cv[cv] = -1; printf("CV%03d: --- ", cv); if (Loco[loco]->dcc_mfr == DIGITRAX && cv == 49) { for (n = 49; n <= 64; ++n) { Loco[loco]->cv[n] = -1; } } } else { temp[0] = buf[2]; temp[1] = buf[3]; temp[2] = 0; Loco[loco]->reg[i] = HexToInt(temp); Loco[loco]->cv[cv] = HexToInt(temp); printf("CV%03d: %03d ", cv, Loco[loco]->cv[cv]); } ++col; if (col == 6) { col = 0; printf("\n"); } ClearBuffer(); } } } sprintf(buf, "S 6 01\r", p); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1L); Loco[loco]->reg[6] = 1; } DumpLocoData(); return (0); } /*************************************************************************** dump loco data to file */ void DumpLocoData(void) { int i; FILE *fp; fp = fopen("LOCO.DAT", "r+b"); if (fp == NULL) { system("cls"); printf("FATAL ERROR: Cannot open LOCO.DAT\n"); exit (0); } for (i = 0; i != NUM_LOCOS; ++i) { fwrite(Loco[i], LOCO_SIZE, 1, fp); } fclose(fp); } /*************************************************************************** Enter high and low nibbles for a Digitrax FX CV */ int EnterDigitraxFXCV(void) { int n; uns l; uns h; printf("\n0: No effect, normal Function control of lead\n"); printf("1: Random Flicker\n"); printf("2: Mars Light\n"); printf("3: Flashing Headlight\n"); printf("4: Single Pulse Strobe\n"); printf("5: Double Pule Strobe\n"); printf("6: Rotary Beacon Simulation\n"); printf("7: Gyralite\n"); printf("8: Rule 17 Dimmable Headlight\n"); printf("9: FRED or end-of-train light\n"); printf("A: Right ditch light\n"); printf("B: Left ditch light\n"); printf("\nEnter new low nibble: "); n = GetText(buf, 1, FALSE); if (n == ESCAPE || buf[0] == 0) { return (-1); } l = HexToInt(buf); if (l < 0 || l > 15) { printf("Illegal value: %.X\n", l); printf("Press any key to continue:"); GetText(buf, 1, TRUE); return (-1); } printf("\n\n0: Forward effect, ON with function, effect phase A\n"); printf("1: Reverse effect, ON with function, effect phase B\n"); printf("2: ON with function, effect phase A, nondirectional\n"); printf("3: ON with function, effect phase B, nondirectional\n"); printf("4: ON with F0 on and FWD direction, effect phase A\n"); printf("5: ON with F0 on and REV direction, effect phase B\n"); printf("6: Special Logic for FWD Ditch Light or Rule 17 dimming\n"); printf("7: Special Logic for REV Ditch Light or Rule 17 dimming\n"); printf("\nEnter new high nibble: "); n = GetText(buf, 1, FALSE); if (n == ESCAPE || buf[0] == 0) { return (-1); } h = HexToInt(buf); if (h < 0 || h > 15) { printf("Illegal value: %d\n", n); printf("Press any key to continue:"); GetText(buf, 1, TRUE); return (-1); } if (h == 0x01) { l |= 0x10; } else if (h == 0x02) { l |= 0x20; } else if (h == 0x03) { l |= 0x30; } else if (h == 0x04) { l |= 0x40; } else if (h == 0x05) { l |= 0x50; } else if (h == 0x06) { l |= 0x60; } else if (h == 0x07) { l |= 0x70; } return ((int) l); } /*************************************************************************** Enter high and low nibbles for the Digitrax BEMF droop CV */ int EnterDigitraxDroopCV(void) { int n; uns l; uns h; printf("Speed stablization when using Regular Addressing\n\n"); printf("0 : Speed stabilzation OFF\n"); printf(".\n"); printf(".\n"); printf(".\n"); printf("F: Speed stablization is FULL ON\n"); printf("\nEnter new low nibble: "); n = GetText(buf, 1, FALSE); if (n == ESCAPE || buf[0] == 0) { return (-1); } l = HexToInt(buf); if (l < 0 || l > 15) { printf("Illegal value: %.X\n", l); printf("Press any key to continue:"); GetText(buf, 1, TRUE); return (-1); } printf("\n\nSpeed stablization when using Extended Addressing\n\n"); printf("0 : Speed stabilzation OFF\n"); printf(".\n"); printf(".\n"); printf(".\n"); printf("F: Speed stablization is FULL ON\n"); printf("\nEnter new high nibble: "); n = GetText(buf, 1, FALSE); if (n == ESCAPE || buf[0] == 0) { return (-1); } h = HexToInt(buf); if (h < 0 || h > 15) { printf("Illegal value: %d\n", n); printf("Press any key to continue:"); GetText(buf, 1, TRUE); return (-1); } if (h == 0x01) { l |= 0x10; } else if (h == 0x02) { l |= 0x20; } else if (h == 0x03) { l |= 0x30; } else if (h == 0x04) { l |= 0x40; } else if (h == 0x05) { l |= 0x50; } else if (h == 0x06) { l |= 0x60; } else if (h == 0x07) { l |= 0x70; } else if (h == 0x08) { l |= 0x80; } else if (h == 0x09) { l |= 0x90; } else if (h == 0x0A) { l |= 0xA0; } else if (h == 0x0B) { l |= 0xB0; } else if (h == 0x0C) { l |= 0xC0; } else if (h == 0x0D) { l |= 0xD0; } else if (h == 0x0E) { l |= 0xE0; } else if (h == 0x0F) { l |= 0xF0; } return ((int) l); } /*************************************************************************** Enter a new CV value in either decimal, hex or binary */ int EnterCV(int cv, int mfr, int l) { int n; char how; char temp[10]; if (mfr == DIGITRAX) { if (cv >= 49 && cv <= 54) { n = EnterDigitraxFXCV(); return (n); } else if (cv == 57) { n = EnterDigitraxDroopCV(); return (n); } } if (cv == 17 || cv == 18) { sprintf(temp, "%.2X%.2X", Loco[l]->cv[17] & 0x3F, Loco[l]->cv[18]); printf("Extended Address: %d\n", HexToInt(temp)); printf("\nEnter locomotive's full extended address (decimal): "); n = GetText(buf, 4, FALSE); if (n == ESCAPE || buf[0] == 0) { return (-1); } n = atoi(buf); return (n); } printf("\nEnter in Hex, Decimal or Binary (H/D/B)? "); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'H' && buf[0] != 'D' && buf[0] != 'B'); if (n == ESCAPE) { return (-1); } how = buf[0]; printf("\nEnter new value: "); n = GetText(buf, 8, FALSE); if (n == ESCAPE || buf[0] == 0) { return (-1); } if (how == 'H') { temp[0] = buf[0]; temp[1] = buf[1]; temp[2] = 0; n = HexToInt(temp); } else if (how == 'D') { n = atoi(buf); } else { if (strlen(buf) != 8) { printf("\n\nYou must enter all 8 bits of a binary value\n"); printf("Press any key to continue: "); GetText(buf, 1, TRUE); return (-1); } n = 0; if (buf[0] == '1') { n |= 0x80; } if (buf[1] == '1') { n |= 0x40; } if (buf[2] == '1') { n |= 0x20; } if (buf[3] == '1') { n |= 0x10; } if (buf[4] == '1') { n |= 0x08; } if (buf[5] == '1') { n |= 0x04; } if (buf[6] == '1') { n |= 0x02; } if (buf[7] == '1') { n |= 0x01; } } if (n < 0 || n > 255) { printf("Illegal value: %d\n", n); printf("Press any key to continue:"); GetText(buf, 1, TRUE); return (-1); } return (n); } /*************************************************************************** Sort locomotive roster */ void RosterSort(void) { int i; int j; int n; int done = FALSE; struct loco_struct temp; system("cls"); printf("Sort Locomotive Roster By:\n\n"); printf("A: Address\n"); printf("B: Locomotive Mfr\n"); printf("C: Decoder Mfr\n"); printf("D: Locomotive Description\n"); printf("E: Decoder Model\n\n"); printf("Selection (A-E, ESC=Done): "); n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return; } if (buf[0] >= 'A' && buf[0] <= 'E') { for (i = 0; i != NUM_LOCOS; ++i) { for (j = 0; j != NUM_LOCOS; ++j) { if (buf[0] == 'A') { if (LocoAddr(i) < LocoAddr(j)) { memcpy(&temp, Loco[i], LOCO_SIZE); memcpy(Loco[i], Loco[j], LOCO_SIZE); memcpy(Loco[j], &temp, LOCO_SIZE); } } else if (buf[0] == 'B') { if (strcmp(Loco[i]->loco_mfr, Loco[j]->loco_mfr) < 0) { memcpy(&temp, Loco[i], LOCO_SIZE); memcpy(Loco[i], Loco[j], LOCO_SIZE); memcpy(Loco[j], &temp, LOCO_SIZE); } } else if (buf[0] == 'C') { if (Loco[i]->dcc_mfr < Loco[j]->dcc_mfr) { memcpy(&temp, Loco[i], LOCO_SIZE); memcpy(Loco[i], Loco[j], LOCO_SIZE); memcpy(Loco[j], &temp, LOCO_SIZE); } } else if (buf[0] == 'D') { if (strcmp(Loco[i]->loco_model, Loco[j]->loco_model) < 0) { memcpy(&temp, Loco[i], LOCO_SIZE); memcpy(Loco[i], Loco[j], LOCO_SIZE); memcpy(Loco[j], &temp, LOCO_SIZE); } } else if (buf[0] == 'E') { if (strcmp(Loco[i]->dcc_model, Loco[j]->dcc_model) < 0) { memcpy(&temp, Loco[i], LOCO_SIZE); memcpy(Loco[i], Loco[j], LOCO_SIZE); memcpy(Loco[j], &temp, LOCO_SIZE); } } } } printf("\n\nRoster sorted!\n\n"); printf("Press a key:"); GetText(buf, 1, TRUE); } } /*************************************************************************** Build an ops packet */ char *BuildOpsPacket(int l, int n1, int n2, int n3) { uns checksum = 0; static char buf[80]; if (Loco[l]->cv[29] & 0x20) { checksum = Loco[l]->cv[17] ^ Loco[l]->cv[18] ^ n1 ^ n2 ^ n3; sprintf ( buf, "%.2X %.2X %.2X %.2X %.2X %.2X\r", Loco[l]->cv[17], Loco[l]->cv[18], n1, n2, n3, checksum ); } else { checksum = Loco[l]->cv[1] ^ n1 ^ n2 ^ n3; sprintf ( buf, "%.2X %.2X %.2X %.2X %.2X\r", Loco[l]->cv[1], n1, n2, n3, checksum ); } return (buf); } /*************************************************************************** Send a CV programming packet */ void SendCVPacket(int p_track, int cv, int val, int loco) { uns cv1 = 0xEC; uns cv2; uns checksum = 0; char *packet; if (p_track) { sprintf(buf, "P%.3X%.2X\r", cv, val); } else { cv2 = cv - 1; packet = BuildOpsPacket(loco, cv1, cv2, val); sprintf(buf, "S 02 %s", packet); } WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1L); if ((p_track && buf[0] != 'P') || (!p_track && buf[0] != 'O')) { system("cls"); printf("Unable to write CV #%d\n", cv); printf("Press any key to continue: "); GetText(buf, 1, TRUE); } else { Loco[loco]->cv[cv] = val; } } /*************************************************************************** Send a register programming packet */ void SendRegPacket(int cv, int val, int loco) { int r; int p; p = ((cv - 1) / 4) + 1; r = cv - ((p - 1) * 4); printf("\nSetting Page Register to %d\n", p); sprintf(buf, "S 6 %.2X\r", p); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1L); if (buf[0] != 'P') { system("cls"); printf("Unable to set page register to #%d\n", p); printf("Press any key to continue: "); GetText(buf, 1, TRUE); ClearBuffer(); return; } Loco[loco]->reg[6] = p; printf("Setting Data Register #%d to %d\n", r, val); sprintf(buf, "S %d %.2X\r", r, val); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1L); if (buf[0] != 'P') { system("cls"); printf("Unable to set register #%d to #%d\n", r, val); printf("Press any key to continue: "); GetText(buf, 1, TRUE); ClearBuffer(); return; } Loco[loco]->reg[r] = val; Loco[loco]->cv[cv] = val; ClearBuffer(); } /*************************************************************************** Enter Programming Mode - Program CVs */ void ProgramCVs(void) { int r; int p; int loco; int i; int hex; int n; int cv; int result; int p_track; int byte; int done = FALSE; int regs = -1; char temp[5]; FILE *fp; system("cls"); printf("Use Programming track or Main track (P/M)? "); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'P' && buf[0] != 'M'); if (n == ESCAPE) { return; } if (buf[0] == 'P') { p_track = TRUE; printf("\n\nPlace locomotive on programming track now\n\n"); } else { p_track = FALSE; printf("\n\nPlace locomotive on main track now\n\n"); } printf("Press ENTER when ready or ESCAPE to cancel: "); do { n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return; } } while (n != ENTER); loco = Select_Loco(p_track); if (loco < 0) { return; } if (p_track) { WriteBuffer(port, "M\r", 2); ClearBuffer(); } Loco[loco]->reg[7] = 0; Loco[loco]->reg[8] = 0; while (!done) { if (Loco[loco]->rescan && p_track) { n = Rescan_Decoder(loco); if (n == -1) { return; } } system("cls"); printf ( "#%d %s %s (%s %s)\n\n", LocoAddr(loco), Loco[loco]->loco_mfr, Loco[loco]->loco_model, dcc_mfr[Loco[loco]->dcc_mfr].name, Loco[loco]->dcc_model ); if (!Loco[loco]->paged) { for (i = 1, n = 0; i != NUM_CVS; ++i) { if (Loco[loco]->cv[i] != -1) { printf("CV%03d: %03d ", i, Loco[loco]->cv[i]); ++n; if (n == 6) { printf("\n"); n = 0; } } } printf("\n\nEnter CV# to change, F to dump CV listing to file, or ESC to exit: "); result = GetText(buf, 3, FALSE); if (result == ESCAPE) { done = TRUE; } else if (buf[0] == 'F') { sprintf(buf, "LOCO%d.TXT", LocoAddr(loco)); fp = fopen(buf, "w"); fprintf ( fp, "#%d %s %s (%s %s)\n\n", LocoAddr(loco), Loco[loco]->loco_mfr, Loco[loco]->loco_model, dcc_mfr[Loco[loco]->dcc_mfr].name, Loco[loco]->dcc_model ); for (i = 1, n = 0; i != NUM_CVS; ++i) { if (Loco[loco]->cv[i] != -1) { fprintf(fp, "CV%03d: %03d ", i, Loco[loco]->cv[i]); ++n; if (n == 6) { fprintf(fp, "\n"); n = 0; } } } fclose(fp); system("cls"); printf("CV listing dumped to file: %s\n\n", buf); printf("Press a key: "); GetText(buf, 1, TRUE); system("cls"); } else if (atoi(buf) > 0 && atoi(buf) < 256) { i = atoi(buf); system("cls"); printf ( "CV #%d - Value: Decimal=%d Hex=%.2X Binary=%s\n\n", i, Loco[loco]->cv[i], Loco[loco]->cv[i], BinValue(Loco[loco]->cv[i]) ); CV_Text(i, Loco[loco]->dcc_mfr); n = EnterCV(i, Loco[loco]->dcc_mfr, loco); if (n != -1) { if (i == 17 || i == 18) { sprintf(temp, "%.4X", n); temp[2] = 0; byte = HexToInt(temp); byte |= 0x80; byte |= 0x40; SendCVPacket(p_track, 17, byte, loco); sprintf(temp, "%.4X", n); byte = HexToInt(&temp[2]); SendCVPacket(p_track, 18, byte, loco); } else { SendCVPacket(p_track, i, n, loco); } } } } else if (regs == -1) { if (!p_track) { regs = FALSE; } else { printf("Program CVs in Paged mode or Direct mode (P/D)? "); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'P' && buf[0] != 'D'); if (n == ESCAPE) { done = TRUE; } else if (buf[0] == 'P') { regs = TRUE; } else { regs = FALSE; } } } else if (regs) { printf(" Dec Hx Binary\n"); for (i = 1; i <= 8; ++i) { if (i < 7 || Loco[loco]->reg[i] <= 0) { sprintf(buf, "V%d\r", i); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 5, -1L); Strip(buf); if (port->count == 0 || buf[2] == '-') { Loco[loco]->reg[i] = -1; } else { temp[0] = buf[2]; temp[1] = buf[3]; temp[2] = 0; Loco[loco]->reg[i] = HexToInt(temp); } ClearBuffer(); } if (Loco[loco]->reg[i] != -1) { if (Loco[loco]->dcc_mfr != MRC) { if (i >= 1 && i <= 4) { printf ( "Reg %d- %-10s CV%03d: %03d %.2X %s\n", i, decoder2regs[i], ((Loco[loco]->reg[6] - 1) * 4) + i, Loco[loco]->reg[i], Loco[loco]->reg[i], BinValue(Loco[loco]->reg[i]) ); } else { printf ( "Reg %d- %-20s: %03d %.2X %s\n", i, decoder2regs[i], Loco[loco]->reg[i], Loco[loco]->reg[i], BinValue(Loco[loco]->reg[i]) ); } } else { printf ( "Reg %d- %-20s: %d\n", i, decoder1regs[i], Loco[loco]->reg[i] ); } } } printf("\nEnter register to change (1-6): "); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && (buf[0] < '1' || buf[0] > '6')); if (n == ESCAPE) { DumpLocoData(); done = TRUE; } else { n = atoi(buf); system("cls"); printf("Changing Register #%d", n); if (n <= 4) { cv = ((Loco[loco]->reg[6] - 1) * 4) + n; printf ( " - CV #%d - Value: Decimal=%d Hex=%.2X Binary=%s\n\n", cv, Loco[loco]->reg[n], Loco[loco]->reg[n], BinValue(Loco[loco]->reg[n]) ); CV_Text(cv, Loco[loco]->dcc_mfr); } else if (n == 5) { cv = 29; printf ( " - CV #%d - Value: Decimal=%d Hex=%.2X Binary=%s\n\n", cv, Loco[loco]->reg[n], Loco[loco]->reg[n], BinValue(Loco[loco]->reg[n]) ); CV_Text(cv, Loco[loco]->dcc_mfr); } else { cv = -1; printf(" - Page Register\n"); } i = EnterCV(cv, Loco[loco]->dcc_mfr, loco); if (i != -1) { if (cv != -1) { Loco[loco]->cv[cv] = i; } sprintf(buf, "S %d %.2X\r", n, i); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1L); if (buf[0] != 'P') { system("cls"); printf("Unable to set register #%d to #%d\n", n, i); printf("Press any key to continue: "); GetText(buf, 1, TRUE); } else { Loco[loco]->reg[n] = i; } } } } else { for (i = 1, n = 0; i != NUM_CVS; ++i) { if (Loco[loco]->cv[i] != -1) { printf("CV%03d: %03d ", i, Loco[loco]->cv[i]); ++n; if (n == 6) { printf("\n"); n = 0; } } } printf("\n\nEnter CV# to change, F to dump CV listing to file, or ESC to exit: "); result = GetText(buf, 3, FALSE); if (result == ESCAPE) { done = TRUE; } else if (buf[0] == 'F') { sprintf(buf, "LOCO%d.TXT", LocoAddr(loco)); fp = fopen(buf, "w"); fprintf ( fp, "#%d %s %s (%s %s)\n\n", LocoAddr(loco), Loco[loco]->loco_mfr, Loco[loco]->loco_model, dcc_mfr[Loco[loco]->dcc_mfr].name, Loco[loco]->dcc_model ); for (i = 1, n = 0; i != NUM_CVS; ++i) { if (Loco[loco]->cv[i] != -1) { fprintf(fp, "CV%03d: %03d ", i, Loco[loco]->cv[i]); ++n; if (n == 6) { fprintf(fp, "\n"); n = 0; } } } fclose(fp); system("cls"); printf("CV listing dumped to file: %s\n\n", buf); printf("Press a key: "); GetText(buf, 1, TRUE); system("cls"); } else if (atoi(buf) > 0 && atoi(buf) < 256) { i = atoi(buf); system("cls"); printf ( "CV #%d - Value: Decimal=%d Hex=%.2X Binary=%s\n\n", i, Loco[loco]->cv[i], Loco[loco]->cv[i], BinValue(Loco[loco]->cv[i]) ); CV_Text(i, Loco[loco]->dcc_mfr); n = EnterCV(i, Loco[loco]->dcc_mfr, loco); if (n != -1) { if (!p_track) { if (i == 17 || i == 18) { sprintf(temp, "%.4X", n); temp[2] = 0; byte = HexToInt(temp); byte |= 0x80; byte |= 0x40; SendCVPacket(p_track, 17, byte, loco); sprintf(temp, "%.4X", n); byte = HexToInt(&temp[2]); SendCVPacket(p_track, 18, byte, loco); } else { SendCVPacket(p_track, i, n, loco); } } else { if (i == 17 || i == 18) { sprintf(temp, "%.4X", n); temp[2] = 0; byte = HexToInt(temp); byte |= 0x80; byte |= 0x40; SendRegPacket(17, byte, loco); sprintf(temp, "%.4X", n); byte = HexToInt(&temp[2]); SendRegPacket(18, byte, loco); } else { SendRegPacket(i, n, loco); } } } } } } WriteBuffer(port, "X\r", 2); ClearBuffer(); return; } /*************************************************************************** Scan Command Station consist info */ void ScanConsists(void) { int i; int c; int locos; int mem; int n; int j; int x; int avail; int found_one = FALSE; uns addr; uns l; char temp[5]; char temp2[3]; system("cls"); printf("Load consist information from Command Station (y/n)? "); do { n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return; } } while (buf[0] != 'Y' && buf[0] != 'N'); if (buf[0] == 'N') { return; } consist_scan = TRUE; printf("\n\nScanning consists...\n"); for (i = 0; i != NUM_LOCOS; ++i) { if (Loco[i]->dcc_mfr == CONSIST) { Loco[i]->dcc_mfr = 0; } } for (i = 0; i != 10000; ++i) { LocoConsist[i] = 0; } for (i = 1; i != 100; ++i) { for (n = 0, avail = -1; n != NUM_LOCOS && avail < 0; ++n) { if (Loco[n]->dcc_mfr == 0) { avail = n; } } printf("%d: ", i); sprintf(buf, "GD %.2X\r", i); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 7, 1000L); if (port->count != 7) { FatalError(); } else if ( buf[3] == '0' && buf[4] == '0' && buf[5] == '0' && buf[6] == '0' ) { printf("\n"); ReadBufferTimed(port, buf, 3, -1L); } else if (buf[7] == '\r') { temp[0] = buf[1]; temp[1] = buf[2]; temp[2] = 0; Loco[avail]->cv[0] = HexToInt(temp); Loco[avail]->cv[1] = 0; Loco[avail]->dcc_mfr = CONSIST; ReadBufferTimed(port, buf, 1, -1L); printf("Consist #%3d\n", Loco[avail]->cv[0]); } else { found_one = TRUE; temp[0] = buf[1]; temp[1] = buf[2]; temp[2] = 0; Loco[avail]->cv[0] = HexToInt(temp); Loco[avail]->dcc_mfr = CONSIST; printf("Consist #%3d: ", Loco[avail]->cv[0]); temp[0] = buf[3]; temp[1] = buf[4]; temp[2] = buf[5]; temp[3] = buf[6]; temp[4] = 0; Loco[avail]->cv[1] = HexToInt(temp); if (Loco[avail]->cv[1] >= 0x8000) { Loco[avail]->cv[1] &= 0x7FFF; LocoConsist[Loco[avail]->cv[1]] = -Loco[avail]->cv[0]; } else { LocoConsist[Loco[avail]->cv[1]] = Loco[avail]->cv[0]; } printf("%4d", Loco[avail]->cv[1]); if (LocoConsist[Loco[avail]->cv[1]] > 0) { printf("N "); } else { printf("R "); } Loco[avail]->cv[2] = 0; n = 2; do { ReadBufferTimed(port, buf, 4, 1000L); if (port->count == 4 && buf[0] != '\r') { temp[0] = buf[0]; temp[1] = buf[1]; temp[2] = buf[2]; temp[3] = buf[3]; temp[4] = 0; Loco[avail]->cv[n] = HexToInt(temp); if (Loco[avail]->cv[n] >= 0x8000) { Loco[avail]->cv[n] &= 0x7FFF; LocoConsist[Loco[avail]->cv[n]] = -Loco[avail]->cv[0]; } else { LocoConsist[Loco[avail]->cv[n]] = Loco[avail]->cv[0]; } printf("%4d", Loco[avail]->cv[n]); if (LocoConsist[Loco[avail]->cv[n]] > 0) { printf("N "); } else { printf("R "); } ++n; Loco[avail]->cv[n] = 0; } } while (port->count == 4 && buf[0] != '\r'); printf("\n"); ClearBuffer(); } } } /*************************************************************************** Build consist pick list */ int BuildConsistPick(int *avail) { int i; int n; int num_locos = 0; char temp[5]; for (i = num_locos = 0, *avail = -1; i != NUM_LOCOS; ++i) { if (Loco[i]->dcc_mfr == 0 && *avail < 0) { *avail = i; } else if (Loco[i]->dcc_mfr == CONSIST) { if (Loco[i]->cv[1] == 0) { sprintf ( Pick[num_locos]->name, "%04d EMPTY MU", Loco[i]->cv[0] ); } else { sprintf ( Pick[num_locos]->name, "%04d ", Loco[i]->cv[0] ); for (n = 1; Loco[i]->cv[n]; ++n) { sprintf(temp, " %4d", Loco[i]->cv[n]); strcat(Pick[num_locos]->name, temp); if (LocoConsist[Loco[i]->cv[n]] < 0) { strcat(Pick[num_locos]->name, "R"); } else { strcat(Pick[num_locos]->name, "N"); } } } Pick[num_locos]->index = i; Pick[num_locos]->consist = TRUE; Pick[num_locos]->direction = -1; ++num_locos; } } if (*avail != -1) { Pick[num_locos]->index = *avail; strcpy(Pick[num_locos]->name, "Create new consist"); ++num_locos; } return (num_locos); } /*************************************************************************** Consist menu */ void ConsistMenu(void) { int i; int n; int add; int remove; int found; int c; int l_index; int l; int normal; int top = 0; int bot = 14; int cur = 0; int done = FALSE; int avail = -1; int num_locos = 0; char temp[5]; if (!consist_scan) { ScanConsists(); } do { num_locos = BuildConsistPick(&avail); system("cls"); printf("Use UP/DOWN Arrows to select, ENTER to modify, D to Delete or ESC when done\n"); for (i = 0; i != 15; ++i) { _settextposition(i + 3, 1); if (top + i >= num_locos) { printf("%-75s", " "); } else { if (top + i == cur) { printf("->"); } else { printf(" "); } printf("%s\n", Pick[i + top]->name); } } _settextposition((cur - top) + 3, 1); buf[0] = 0; n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return; } else if (n == ENTER) { system("cls"); if (cur == num_locos - 1 && avail != -1) { consist_scan = FALSE; add = TRUE; l_index = avail; printf("Enter consist ID# (1-99): "); n = GetText(buf, 2, FALSE); if (n == ESCAPE || atoi(buf) < 1 || atoi(buf) > 99) { add = FALSE; } else { c = atoi(buf); printf("\n\n"); for (i = 0; i < NUM_LOCOS; ++i) { if ( Loco[i]->dcc_mfr == CONSIST && (Loco[i]->cv[0] == c || Loco[i]->cv[0] - 100 == c) ) { printf("That consist # is already in use.\n"); printf("Press any key to continue: "); GetText(buf, 1, TRUE); add = FALSE; i = NUM_LOCOS; } } } if (add) { printf("Standard or Advanced consist (S/A)? "); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'S' && buf[0] != 'A'); if (n == ESCAPE) { add = FALSE; } else { printf("\n\n"); if (buf[0] == 'A') { c += 100; } Loco[avail]->cv[0] = c; Loco[avail]->cv[1] = 0; } } } else if (cur != num_locos - 1) { printf("%s\n", Pick[cur]->name); l_index = Pick[cur]->index; c = Loco[l_index]->cv[0]; printf ( "Add or Remove a locomotive from consist #%d (A/R)? ", c ); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'R' && buf[0] != 'A'); if (n == ESCAPE) { add = FALSE; } else if (buf[0] == 'A') { printf("\n\n"); add = TRUE; } else { printf("\n\n"); add = FALSE; remove = TRUE; if (Loco[l_index]->cv[2] == 0) { remove = FALSE; sprintf(buf, "GK%.2X\r", c); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); if (buf[0] == 'R') { system("cls"); printf("Packet rejected. Press a key: "); GetText(buf, 1, FALSE); } else { Loco[l_index]->dcc_mfr = 0; } } else { printf("Enter locomotive ID# to remove (1-9999): "); n = GetText(buf, 4, FALSE); if (n == ESCAPE || atoi(buf) < 1 || atoi(buf) > 9999) { remove = FALSE; } else { printf("\n\n"); l = atoi(buf); } } if (remove) { for (n = 1, found = 0; Loco[l_index]->cv[n]; ++n) { if (Loco[l_index]->cv[n] == l) { found = n; } } if (!found) { system("cls"); printf("That locomotive is not assigned to this consist\n"); printf("Press any key to continue: "); GetText(buf, 1, TRUE); remove = FALSE; } } if (remove) { sprintf(buf, "GS%.2X%.4X\r", c, l); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); if (buf[0] == 'R') { system("cls"); printf("Packet rejected. Press a key: "); GetText(buf, 1, FALSE); } else { Loco[l_index]->cv[found] = 0; for (i = found + 1; Loco[l_index]->cv[i]; ++i) { Loco[l_index]->cv[i - 1] = Loco[l_index]->cv[i]; } Loco[l_index]->cv[i - 1] = 0; } } } } else { add = FALSE; } if (add) { l = Select_Loco(-1); if (l < 0) { add = FALSE; } else { l = LocoAddr(l); num_locos = BuildConsistPick(&avail); system("cls"); for (i = 0; i < NUM_LOCOS; ++i) { if (Loco[i]->dcc_mfr == CONSIST) { for (n = 1; Loco[i]->cv[n]; ++n) { if (Loco[i]->cv[n] == l) { system("cls"); printf("That locomotive is already assigned to a consist\n"); printf("Press any key to continue: "); GetText(buf, 1, TRUE); add = FALSE; } } } } } } if (add) { printf("%s\n", Pick[cur]->name); printf("Reverse or Normal direction (R/N)? "); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'R' && buf[0] != 'N'); if (n == ESCAPE) { add = FALSE; } else if (buf[0] == 'N') { normal = TRUE; } else { normal = FALSE; } GetText(buf, 1, TRUE); if (add) { printf("\n\n"); if (normal) { sprintf(buf, "GN%.2X%.4X\r", c, l); } else { sprintf(buf, "GR%.2X%.4X\r", c, l); } WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); if (buf[0] == 'R') { system("cls"); printf("Packet rejected. Press a key: "); GetText(buf, 1, FALSE); } else { Loco[l_index]->dcc_mfr = CONSIST; for (i = 1; Loco[l_index]->cv[i]; ++i) { /* just advancing 'i' */ } Loco[l_index]->cv[i] = l; Loco[l_index]->cv[i + 1] = 0; if (normal) { LocoConsist[l] = c; } else { LocoConsist[l] = -c; } } } } } else if (buf[0] == 'D') { system("cls"); l_index = Pick[cur]->index; c = Loco[l_index]->cv[0]; printf("Really delete consist #%d (y/n)? ", c); do { n = GetText(buf, 1, TRUE); } while (n != ESCAPE && buf[0] != 'Y' && buf[0] != 'N'); if (buf[0] == 'Y') { cur = 0; top = 0; bot = 14; sprintf(buf, "GK%.2X\r", c); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); if (buf[0] == 'R') { system("cls"); printf("Packet rejected. Press a key: "); GetText(buf, 1, FALSE); } else { Loco[l_index]->dcc_mfr = 0; consist_scan = FALSE; } } } else if (n == UP_ARROW) { if (cur != 0) { --cur; if (top > cur) { top = cur; --bot; } } } else if (n == DOWN_ARROW) { if (cur != num_locos - 1) { ++cur; if (cur > bot) { bot = cur; ++top; } } } } while (!done); } /*************************************************************************** wait until xreceive buffer is empty */ int ClearBuffer(void) { int i; char buf[80]; ReadBufferTimed(port, buf, 2, 5000); if (port->count) { #if 0 printf("\nResponse:"); for (i = 0; i != port->count - 1; ++i) { printf("%c", buf[i]); } printf("\n"); #endif return (buf[0]); } return (0); } /*************************************************************************** bad craziness */ void FatalError(void) { system("cls"); printf("Communication failure - EasyDCC not responding on COM%d\n", com_port); printf("Please check the serial connection between your PC and the Command Station.\n"); if (com_port == 1) { printf("If your serial port is configured as COM2, type: EASYX COM2\n"); } #if 0 printf("Buf contents: %s\n", buf); printf("port->count : %d\n", port->count); #endif printf("Aborting EasyX\n"); PortClose(port); exit (0); } /*************************************************************************** Stop all main track clocks */ void KillMainTrack(void) { int n; system("cls"); printf("Kill all main track clocks (y/n)? "); do { n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return; } } while (buf[0] != 'Y' && buf[0] != 'N'); if (buf[0] == 'N') { return; } WriteBuffer(port, "K\r", 2); ClearBuffer(); system("cls"); printf("Main track killed! Press a key: "); GetText(buf, 1, TRUE); } /*************************************************************************** send a reset packet to a decoder */ void Send_Reset(uns l, int reset) { uns checksum = 0; static char buf[80]; if (Loco[l]->cv[29] & 0x20) { checksum = Loco[l]->cv[17] ^ Loco[l]->cv[18] ^ reset; sprintf ( buf, "%.2X %.2X %.2X %.2X\r", Loco[l]->cv[17], Loco[l]->cv[18], reset, checksum ); } else { checksum = Loco[l]->cv[1] ^ reset; sprintf ( buf, "%.2X %.2X %.2X\r", Loco[l]->cv[1], reset, checksum ); } sprintf(buf, "S 01 %s\r", buf); system("cls"); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); } /*************************************************************************** Ask Command Station which locomotives are assigned to throttles */ void ThrottleCheck(int pause) { int i; int j; int k; int t; int x; int consist; int got_one = FALSE; char temp[5]; if (throttle_scan) { return; } throttle_scan = TRUE; for (i = 0; i != 102; ++i) { Throttle[i] = 0; } system("cls"); printf("Checking throttles...\n"); sprintf(buf, "F D 1B00\r"); WriteBuffer(port, buf, strlen(buf)); for (i = t = 0; i < 13; ++i) { ReadBufferTimed(port, buf, 33, 1000); if (buf[0] == '?') { i = 13; } else if (port->count) { for (j = x = 0; j != port->count && t <= 101; ++j) { temp[x] = buf[j]; ++x; if (x == 4) { temp[x] = 0; if (strcmp(temp, "FFFF") == 0) { Throttle[t] = 0; } else { Throttle[t] = HexToInt(temp); } if (Throttle[t]) { got_one = TRUE; for (k = 1, consist = FALSE; k != 10000; ++k) { if (abs(LocoConsist[k]) == Throttle[t]) { consist = TRUE; printf ( "Consist #%d/Locomotive #%d is assigned to throttle #%d\n", abs(LocoConsist[k]), k, t ); } } if (!consist) { printf ( "Locomotive #%d is assigned to throttle ", Throttle[t] ); if (t == 100) { printf("A\n"); } else if (t == 101) { printf("B\n"); } else { printf("#%d\n", t); } } } x = 0; ++t; } } } } ClearBuffer(); if (got_one && pause) { printf("Press any key:"); GetText(buf, 1, TRUE); } } /************************************************************************** queue 128 step speed instruction */ int SendSpeed(uns net_l, int l, int speed, int direction, int steps, int f0) { int i; uns checksum; uns u; uns hi_l; uns lo_l; char temp[5]; sprintf(temp, "%.4X", net_l); lo_l = HexToInt(&temp[2]); temp[2] = 0; hi_l = HexToInt(temp); for (i = 0; i != 102; ++i) { if (Throttle[i] == l) { throttle_scan = FALSE; ThrottleCheck(FALSE); printf("\n"); printf("Warning! The locomotive you selected is currently assigned to one of your\n"); printf("EasyDCC throttles. Please deassign it before attempting to operate it\n"); printf("from EasyX.\n\n"); printf("Press any key: "); GetText(buf, 1, TRUE); return (FALSE); } } if (steps == 14) { if (speed > 14) { speed = 14; } u = speed; if (f0) { u |= 0x10; } if (direction == FORWARD) { u |= 0x60; } else { u |= 0x40; } if (l <= 99) { checksum = l ^ u; sprintf(buf, "Q%.2X %.2X %.2X\r", l, u, checksum); } else { checksum = hi_l ^ lo_l ^ u; sprintf(buf, "Q%.2X%.2X %.2X %.2X\r", hi_l, lo_l, u, checksum); } } else if (steps == 28) { if (speed > 28) { speed = 28; } u = Speed_Parms28[speed]; if (direction == FORWARD) { u |= 0x60; } else { u |= 0x40; } if (l <= 99) { checksum = l ^ u; sprintf(buf, "Q%.2X %.2X %.2X\r", l, u, checksum); } else { checksum = hi_l ^ lo_l ^ u; sprintf(buf, "Q%.2X%.2X %.2X %.2X\r", hi_l, lo_l, u, checksum); } } else if (steps == 128) { if (direction == FORWARD) { speed |= 0x80; } if (l <= 99) { checksum = l ^ 0x3F ^ speed; sprintf(buf, "Q%.2X %.2X %.2X %.2X\r", l, 0x3F, speed, checksum); } else { checksum = hi_l ^ lo_l ^ 0x3F ^ speed; sprintf ( buf, "Q%.2X%.2X %.2X %.2X %.2X\r", hi_l, lo_l, 0x3F, speed, checksum ); } } Queued[l] = TRUE; WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); return (TRUE); } /*************************************************************************** update locomotive settings */ void Dequeue_Packets(void) { int l; uns n; system("cls"); for (l = 1; l != 10000; ++l) { if (Queued[l]) { printf("Dequeuing packet for locomotive #%d\n", l); if (l < 100) { n = l; } else { n = l; n |= 0x8000; n |= 0x4000; } sprintf(buf, "D%.4X\r", n); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); if (buf[0] != 'O') { FatalError(); } /* pause so EasyDCC doesn't get overburdened */ ReadBufferTimed(port, buf, 2, 1000); } } } /*************************************************************************** update locomotive settings */ void Send_Settings ( uns net_l, int l, int cur, uns yy, uns zz, uns ddddd, uns dddd ) { uns speed; uns checksum; uns hi_l; uns lo_l; char temp[5]; sprintf(buf, "C%.4X%.2X%.2X\r", l, yy, zz); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 2, -1); if (buf[0] != 'O') { FatalError(); } sprintf(temp, "%.4X", net_l); lo_l = HexToInt(&temp[2]); temp[2] = 0; hi_l = HexToInt(temp); if (l <= 99) { checksum = l ^ ddddd; sprintf ( buf, "S 02 %.2X %.2X %.2X\r", l, ddddd, checksum ); } else { checksum = hi_l ^ lo_l ^ ddddd; sprintf ( buf, "S 02 %.2X %.2X %.2X %.2X\r", hi_l, lo_l, ddddd, checksum ); } WriteBuffer(port, buf, strlen(buf)); ClearBuffer(); Queued[l] = TRUE; if (l <= 99) { checksum = l ^ dddd; sprintf ( buf, "S 01 %.2X %.2X %.2X\r", l, dddd, checksum ); } else { checksum = hi_l ^ lo_l ^ dddd; sprintf ( buf, "S 01 %.2X%.2X %.2X %.2X\r", hi_l, lo_l, dddd, checksum ); } WriteBuffer(port, buf, strlen(buf)); ClearBuffer(); if (Pick[cur]->steps == 14) { if (Pick[cur]->local_dir == -1) { Pick[cur]->local_dir = Pick[cur]->direction; Pick[cur]->local_speed = Pick[cur]->speed; } SendSpeed ( net_l, l, Pick[cur]->local_speed, Pick[cur]->local_dir, Pick[cur]->steps, Pick[cur]->f[0] ); } } /*************************************************************************** manage/operate locomotives */ void Operations(void) { int n; int i; int avail; int reset; int top = 0; int bot = 14; int cur = 0; int num_locos = 0; int l; uns yy; uns zz; uns ddddd; uns dddd; int done = FALSE; int sent; char temp[5]; uns checksum; char c; uns parm; uns u; if (!consist_scan) { ScanConsists(); } ThrottleCheck(TRUE); for (i = 0; i != NUM_LOCOS; ++i) { Pick[i]->index = -1; if (Loco[i]->dcc_mfr == CONSIST) { if (Loco[i]->cv[1] == 0) { sprintf ( Pick[num_locos]->name, "%04d EMPTY MU", Loco[i]->cv[0] ); } else { sprintf ( Pick[num_locos]->name, "%04d MU %d", Loco[i]->cv[0], Loco[i]->cv[1] ); for (n = 2; Loco[i]->cv[n]; ++n) { sprintf(temp, "+%d", Loco[i]->cv[n]); strcat(Pick[num_locos]->name, temp); } } Pick[num_locos]->index = i; Pick[num_locos]->consist = TRUE; Pick[num_locos]->direction = -1; Pick[num_locos]->local_speed = 0; Pick[num_locos]->local_dir = -1; ++num_locos; } else if (Loco[i]->dcc_mfr != 0) { sprintf ( Pick[num_locos]->name, "%04d %s %s", LocoAddr(i), Loco[i]->loco_mfr, Loco[i]->loco_model ); Pick[num_locos]->index = i; Pick[num_locos]->consist = FALSE; Pick[num_locos]->direction = -1; Pick[num_locos]->local_speed = 0; Pick[num_locos]->local_dir = -1; ++num_locos; } } system("cls"); if (num_locos == 0) { printf("You have not entered any locomotive records yet.\n"); printf("Use main menu option 'C' to do so.\n"); printf("\nPress any key to continue: "); GetText(buf, 1, TRUE); return; } do { system("cls"); printf("Select: UP/DOWN Arrows Functions: 0-9 Steps: S Reset: R Hard Reset: H\n"); printf("Adjust Speed: -=_+ Stop: X Done: ESC"); printf("\n\n ADDR DESCRIPTION D SPEED FUNCTIONS\n"); for (i = 0; i != 15; ++i) { _settextposition(i + 5, 1); if (top + i >= num_locos) { printf("%-75s", " "); } else { if (top + i == cur) { printf("->"); } else { printf(" "); } printf("%-35s", Pick[i + top]->name); if (Pick[i + top]->consist) { l = Loco[Pick[i + top]->index]->cv[0]; } else { l = LocoAddr(Pick[i + top]->index); } if (Pick[i + top]->direction == -1) { if (l < 100 || !Pick[i + top]->consist) { sprintf(buf, "L %.4X\r", l); } else { sprintf(buf, "L %.4X\r", l - 100); } WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 12, 5000); if (port->count != 12) { FatalError(); } temp[0] = buf[5]; temp[1] = buf[6]; temp[2] = 0; Pick[i + top]->speed = HexToInt(temp); if (Pick[i + top]->speed & 0x80) { Pick[i + top]->direction = FORWARD; Pick[i + top]->speed -= 0x80; } else { Pick[i + top]->direction = REVERSE; } temp[0] = buf[7]; temp[1] = buf[8]; temp[2] = 0; Pick[i + top]->steps = HexToInt(temp); for (n = 0; n != 9; ++n) { Pick[i + top]->f[n] = FALSE; } if (Pick[i + top]->steps & 0x10) { Pick[i + top]->f[0] = TRUE; } if (Pick[i + top]->steps & 0x08) { Pick[i + top]->f[4] = TRUE; } if (Pick[i + top]->steps & 0x04) { Pick[i + top]->f[3] = TRUE; } if (Pick[i + top]->steps & 0x02) { Pick[i + top]->f[2] = TRUE; } if (Pick[i + top]->steps & 0x01) { Pick[i + top]->f[1] = TRUE; } if (Pick[i + top]->steps & 0x80) { Pick[i + top]->steps = 128; } else if (Pick[i + top]->steps & 0x40) { Pick[i + top]->steps = 28; } else { Pick[i + top]->steps = 14; } temp[0] = buf[9]; temp[1] = buf[10]; temp[2] = 0; n = HexToInt(temp); if (n & 0x01) { Pick[i + top]->f[5] = TRUE; } if (n & 0x02) { Pick[i + top]->f[6] = TRUE; } if (n & 0x04) { Pick[i + top]->f[7] = TRUE; } if (n & 0x08) { Pick[i + top]->f[8] = TRUE; } ReadBufferTimed(port, buf, 2, 500); } if (Pick[i + top]->local_dir == -1) { printf("%c", Directions[Pick[i + top]->direction][0]); printf("%3d ", Pick[i + top]->speed); } else { printf("%c", Directions[Pick[i + top]->local_dir][0]); printf("%3d ", Pick[i + top]->local_speed); } printf("%3d ", Pick[i + top]->steps); if (Pick[i + top]->local_dir == -1) { printf ( "%3d%% ", (Pick[i + top]->speed * 100) / Pick[i + top]->steps ); } else { printf ( "%3d%% ", (Pick[i + top]->local_speed * 100) / Pick[i + top]->steps ); } for (n = 0; n != 9; ++n) { printf("%d", n); if (Pick[i + top]->f[n]) { printf("+"); } else { printf("-"); } } } } _settextposition((cur - top) + 5, 1); buf[0] = 0; n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return; } else if (n == ENTER) { for (i = 0; i != NUM_LOCOS; ++i) { Pick[i]->direction = -1; } } else if (n == UP_ARROW) { if (cur != 0) { --cur; if (top > cur) { top = cur; --bot; } } } else if (n == DOWN_ARROW) { if (cur != num_locos - 1) { ++cur; if (cur > bot) { bot = cur; ++top; } } } else if ( buf[0] == '-' || buf[0] == '_' || buf[0] == '+' || buf[0] == '=' || buf[0] == 'X' ) { int speed = Pick[cur]->local_speed; int direction = Pick[cur]->local_dir; if (buf[0] == 'X') { speed = 0; direction = FORWARD; } else if (speed == 0) { if (buf[0] == '-' || buf[0] == '=') { speed = 1; } else { speed = 5; } if (buf[0] == '-' || buf[0] == '_') { direction = REVERSE; } else { direction = FORWARD; } } else if (direction == REVERSE) { if (buf[0] == '-') { if (speed < Pick[cur]->steps - 1) { ++speed; } } else if (buf[0] == '_') { if (speed <= Pick[cur]->steps - 6) { speed += 5; } else { speed = Pick[cur]->steps - 1; } } else if (buf[0] == '=') { --speed; } else if (buf[0] == '+') { if (speed >= 5) { speed -= 5; } else { speed = 0; } } } else { if (buf[0] == '=') { if (speed < Pick[cur]->steps - 1) { ++speed; } } else if (buf[0] == '+') { if (speed <= Pick[cur]->steps - 6) { speed += 5; } else { speed = Pick[cur]->steps - 1; } } else if (buf[0] == '-') { --speed; } else if (buf[0] == '_') { if (speed >= 5) { speed -= 5; } else { speed = 0; } } } if (Pick[cur]->consist) { l = Loco[Pick[cur]->index]->cv[0]; if (l > 100) { sent = SendSpeed ( l - 100, l - 100, speed, direction, Pick[cur]->steps, Pick[cur]->f[0] ); } else { int standard_dir; l = Pick[cur]->index; for (n = 1; Loco[l]->cv[n]; ++n) { for (i = 0; i != NUM_LOCOS; ++i) { if ( Pick[i]->index >= 0 && !Pick[i]->consist && LocoAddr(Pick[i]->index) == Loco[l]->cv[n] ) { standard_dir = direction; if (LocoConsist[Loco[l]->cv[n]] < 0) { if (direction == FORWARD) { standard_dir = REVERSE; } else { standard_dir = FORWARD; } } sent = SendSpeed ( NetAddr(Pick[i]->index), LocoAddr(Pick[i]->index), speed, standard_dir, Pick[cur]->steps, Pick[cur]->f[0] ); } } } } } else { sent = SendSpeed ( NetAddr(Pick[cur]->index), LocoAddr(Pick[cur]->index), speed, direction, Pick[cur]->steps, Pick[cur]->f[0] ); } if (sent) { Pick[cur]->direction = -1; Pick[cur]->local_dir = direction; Pick[cur]->local_speed = speed; } } else if (buf[0] == 'R' || buf[0] == 'H') { if (buf[0] == 'R') { reset = 0; } else { reset = 1; } if (Pick[cur]->consist) { l = Pick[cur]->index; for (n = 1; Loco[l]->cv[n]; ++n) { for (i = 0; i != NUM_LOCOS; ++i) { if (LocoAddr(Pick[i]->index) == Loco[l]->cv[n]) { Pick[i]->direction = -1; } } Send_Reset(Loco[l]->cv[n], reset); } } else { Send_Reset(NetAddr(Pick[cur]->index), reset); } } else if ( buf[0] == '0' || buf[0] == '1' || buf[0] == '2' || buf[0] == '3' || buf[0] == '4' || buf[0] == '5' || buf[0] == '6' || buf[0] == '7' || buf[0] == '8' || buf[0] == 'S' ) { Pick[cur]->direction = -1; if (buf[0] == 'S') { if (Pick[cur]->steps == 128) { Pick[cur]->steps = 14; } else if (Pick[cur]->steps == 28) { Pick[cur]->steps = 128; } else { Pick[cur]->steps = 28; } } else { n = buf[0] - '0'; if (Pick[cur]->f[n] == TRUE) { Pick[cur]->f[n] = FALSE; } else { Pick[cur]->f[n] = TRUE; } } yy = 0; zz = 0; ddddd = 0x80; dddd = 0x80 | 0x20 | 0x10; if (Pick[cur]->f[5]) { zz |= 0x01; dddd |= 0x01; } if (Pick[cur]->f[6]) { zz |= 0x02; dddd |= 0x02; } if (Pick[cur]->f[7]) { zz |= 0x04; dddd |= 0x04; } if (Pick[cur]->f[8]) { zz |= 0x08; dddd |= 0x08; } if (Pick[cur]->f[1]) { yy |= 0x01; ddddd |= 0x01; } if (Pick[cur]->f[2]) { yy |= 0x02; ddddd |= 0x02; } if (Pick[cur]->f[3]) { yy |= 0x04; ddddd |= 0x04; } if (Pick[cur]->f[4]) { yy |= 0x08; ddddd |= 0x08; } if (Pick[cur]->f[0]) { yy |= 0x10; ddddd |= 0x10; } if (Pick[cur]->steps == 128) { yy |= 0x80; } else if (Pick[cur]->steps == 28) { yy |= 0x40; } else { yy |= 0x20; } if (Pick[cur]->consist) { int advanced = FALSE; system("cls"); l = Pick[cur]->index; l = Loco[l]->cv[0]; if (l > 100) { advanced = TRUE; l -= 100; } Send_Settings(l, l, cur, yy, zz, ddddd, dddd); l = Pick[cur]->index; for (n = 1; Loco[l]->cv[n]; ++n) { for (i = 0; i != NUM_LOCOS; ++i) { if ( Pick[i]->index >= 0 && !Pick[i]->consist && LocoAddr(Pick[i]->index) == Loco[l]->cv[n] ) { Pick[i]->direction = -1; if (!advanced) { Send_Settings ( NetAddr(Pick[i]->index), LocoAddr(Pick[i]->index), cur, yy, zz, ddddd, dddd ); } } } } } else { Send_Settings ( NetAddr(Pick[cur]->index), LocoAddr(Pick[cur]->index), cur, yy, zz, ddddd, dddd ); } } } while (!done); } /*************************************************************************** match one speed table to another */ void TableMatch(int l1, int l2) { int n; int i; int l = 1; int top = 0; int bot = 14; int cur = 0; int done = FALSE; int col; uns cv2; do { system("cls"); SendSpeed ( NetAddr(l1), LocoAddr(l1), cur + 1, FORWARD, 28, TRUE ); SendSpeed ( NetAddr(l2), LocoAddr(l2), cur + 1, FORWARD, 28, TRUE ); printf("Select Step: UP/DOWN Arrows Select Loco: RIGHT/LEFT Arrows\n"); printf("Change Step Value: -_=+ Quick Stop: X Done: ESC\n"); printf(" Loco1 Loco2\n"); printf("Step CV Value Value\n"); for (i = 0; i != 15; ++i) { _settextposition(i + 5, 1); if (top + i >= 28) { printf("%-75s", " "); } else { printf("%4d %2d", top + i + 1, top + i + 67); if (top + i == cur) { if (l == 1) { printf(" ->"); col = 10; } else { printf(" "); } } else { printf(" "); } printf("%3d", Loco[l1]->cv[top + i + 67]); if (top + i == cur) { if (l == 2) { printf(" ->"); col = 17; } else { printf(" "); } } else { printf(" "); } printf("%3d", Loco[l2]->cv[top + i + 67]); } } _settextposition((cur - top) + 5, col); buf[0] = 0; n = GetText(buf, 1, TRUE); if (n == ESCAPE) { SendSpeed ( NetAddr(l1), LocoAddr(l1), 0, FORWARD, 28, TRUE ); SendSpeed ( NetAddr(l2), LocoAddr(l2), 0, FORWARD, 28, TRUE ); return; } else if (n == UP_ARROW) { if (cur != 0) { --cur; if (top > cur) { top = cur; --bot; } } } else if (n == DOWN_ARROW) { if (cur != 27) { ++cur; if (cur > bot) { bot = cur; ++top; } } } else if (n == RIGHT_ARROW) { if (l == 1) { l = 2; } } else if (n == LEFT_ARROW) { if (l == 2) { l = 1; } } else if (buf[0] == 'X') { cur = 0; top = 0; bot = 14; } else if ( buf[0] == '-' || buf[0] == '_' || buf[0] == '+' || buf[0] == '=' ) { cv2 = cur + 67; if (l == 1) { n = Loco[l1]->cv[cur + 67]; } else { n = Loco[l2]->cv[cur + 67]; } if (buf[0] == '-' && n > 0) { --n; } else if (buf[0] == '_') { if (n >= 5) { n -= 5; } else { n = 0; } } else { if (buf[0] == '=') { ++n; } else { n += 5; } if (n > 255) { n = 255; } } if (l == 1) { SendCVPacket(FALSE, cv2, n, l1); Loco[l1]->cv[cur + 67] = n; } else { SendCVPacket(FALSE, cv2, n, l2); Loco[l2]->cv[cur + 67] = n; } /* pause so EasyDCC doesn't get overburdened */ ReadBufferTimed(port, buf, 2, 1000); } } while (!done); } /*************************************************************************** manipulate locomotive speed tables */ void SpeedTables(void) { int n; int i; int avail; int top = 0; int bot = 14; int cur = 0; int num_locos = 0; uns l; char temp[5]; int done = FALSE; int step; int lo_speed; int hi_speed; int sent; uns cv1; uns cv2; uns checksum; for (i = 0; i != NUM_LOCOS; ++i) { if (Loco[i]->dcc_mfr == CONSIST) { /* consists don't have speed tables */ } else if (Loco[i]->dcc_mfr != 0) { sprintf ( Pick[num_locos]->name, "%04d %s %s", LocoAddr(i), Loco[i]->loco_mfr, Loco[i]->loco_model ); Pick[num_locos]->index = i; Pick[num_locos]->consist = FALSE; Pick[num_locos]->direction = -1; Pick[num_locos]->local_speed = 0; Pick[num_locos]->local_dir = -1; ++num_locos; } } system("cls"); if (num_locos == 0) { printf("You have not entered any locomotive records yet.\n"); printf("Use main menu option 'C' to do so.\n"); printf("\nPress any key to continue: "); GetText(buf, 1, TRUE); return; } do { system("cls"); printf("Select: UP/DOWN Arrows Enable/Disable Custom Speed Table: C Done: ESC\n"); printf("Import Table: I Match Two Tables: M Create Straight-Line Table: S"); printf("\n\n ADDR DESCRIPTION D SPEED CUSTOM TABLE\n"); for (i = 0; i != 15; ++i) { _settextposition(i + 5, 1); if (top + i >= num_locos) { printf("%-75s", " "); } else { if (top + i == cur) { printf("->"); } else { printf(" "); } printf("%-35s", Pick[i + top]->name); l = LocoAddr(Pick[i + top]->index); if (Pick[i + top]->direction == -1) { sprintf(buf, "L %.4X\r", l); WriteBuffer(port, buf, strlen(buf)); ReadBufferTimed(port, buf, 12, 5000); if (port->count != 12) { FatalError(); } temp[0] = buf[5]; temp[1] = buf[6]; temp[2] = 0; Pick[i + top]->speed = HexToInt(temp); if (Pick[i + top]->speed & 0x80) { Pick[i + top]->direction = FORWARD; Pick[i + top]->speed -= 0x80; } else { Pick[i + top]->direction = REVERSE; } temp[0] = buf[7]; temp[1] = buf[8]; temp[2] = 0; Pick[i + top]->steps = HexToInt(temp); if (Pick[i + top]->steps & 0x80) { Pick[i + top]->steps = 128; } else if (Pick[i + top]->steps & 0x40) { Pick[i + top]->steps = 28; } else { Pick[i + top]->steps = 14; } ReadBufferTimed(port, buf, 2, 500); } if (Pick[i + top]->local_dir == -1) { printf("%c", Directions[Pick[i + top]->direction][0]); printf("%3d ", Pick[i + top]->speed); } else { printf("%c", Directions[Pick[i + top]->local_dir][0]); printf("%3d ", Pick[i + top]->local_speed); } printf("%3d ", Pick[i + top]->steps); if (Pick[i + top]->local_dir == -1) { printf ( "%3d%% ", (Pick[i + top]->speed * 100) / Pick[i + top]->steps ); } else { printf ( "%3d%% ", (Pick[i + top]->local_speed * 100) / Pick[i + top]->steps ); } if (Loco[Pick[i + top]->index]->cv[29] & 0x10) { printf(" *ENABLED*"); } else { printf(" *DISABLED*"); } } } _settextposition((cur - top) + 5, 1); buf[0] = 0; n = GetText(buf, 1, TRUE); if (n == ESCAPE) { return; } else if (n == ENTER) { for (i = 0; i != NUM_LOCOS; ++i) { Pick[i]->direction = -1; } } else if (n == UP_ARROW) { if (cur != 0) { --cur; if (top > cur) { top = cur; --bot; } } } else if (n == DOWN_ARROW) { if (cur != num_locos - 1) { ++cur; if (cur > bot) { bot = cur; ++top; } } } else if (buf[0] == 'C') { int i = Pick[cur]->index; n = Loco[i]->cv[29]; if (n & 0x10) { n -= 0x10; } else { n += 0x10; } SendCVPacket(FALSE, 29, n, i); } else if (buf[0] == 'I') { int i = Pick[cur]->index; int loco; system("cls"); printf("On the next screen you will select the locomotive\n"); printf("from which you want to import the speed table\n\n"); printf("Press a key:"); GetText(buf, 1, TRUE); loco = Select_Loco(-1); if (loco >= 0) { system("cls"); printf("Importing speed table...\n"); for (step = 1; step <= 28; ++step) { cv2 = step + 66; n = Loco[loco]->cv[step + 66]; SendCVPacket(FALSE, cv2, n, i); printf("CV%03d: %03d\n", cv2, n); /* pause so EasyDCC doesn't get overburdened */ ReadBufferTimed(port, buf, 2, 1000); } } } else if (buf[0] == 'S') { int ok = TRUE; int i = Pick[cur]->index; system("cls"); printf("Speed steps are represented by an arbitrary number between\n"); printf("0 and 255, with 0 being dead-stopped and 255 being full speed.\n"); printf("This process generates a straight-line speed table, as determined\n"); printf("by the values you enter for speed step 1 and speed step 28\n\n"); printf("Enter speed step 1 (default: %d): ", Loco[i]->cv[67]); n = GetText(buf, 3, FALSE); if (n == ESCAPE || atoi(buf) < 0 || atoi(buf) > 255) { ok = FALSE; } else { printf("\n"); if (buf[0] == 0) { lo_speed = Loco[i]->cv[67]; } else { lo_speed = atoi(buf); } } if (ok) { printf("Enter speed step 28 (default: %d): ", Loco[i]->cv[94]); n = GetText(buf, 3, FALSE); if (n == ESCAPE || atoi(buf) < 0 || atoi(buf) > 255) { ok = FALSE; } else { if (buf[0] == 0) { hi_speed = Loco[i]->cv[94]; } else { hi_speed = atoi(buf); } } } if (hi_speed < lo_speed) { hi_speed = lo_speed; } if (ok) { system("cls"); printf("Updating speed table...\n"); for (step = 1; step <= 28; ++step) { float inc; cv2 = step + 66; inc = (float) hi_speed - (float) lo_speed; inc = inc / 27.0; inc = inc * (step - 1); inc += 0.5; n = lo_speed + (int) inc; SendCVPacket(FALSE, cv2, n, i); printf("CV%03d: %03d\n", cv2, n); /* pause so EasyDCC doesn't get overburdened */ ReadBufferTimed(port, buf, 2, 1000); } } } else if (buf[0] == 'M') { int ok = FALSE; int loco; int i = Pick[cur]->index; if (Loco[i]->cv[29] & 0x10) { ok = TRUE; } else { system("cls"); printf("You have to enable the custom speed table before\n"); printf("attempting to match another loco's table\n\n"); printf("Press a key: "); GetText(buf, 1, TRUE); } if (ok) { if (Pick[cur]->steps != 28) { ok = FALSE; system("cls"); printf("Please set the number of steps for this locomotive to 28\n"); printf("This is the best way to match two custom speed tables\n\n"); printf("Press a key: "); GetText(buf, 1, TRUE); } } if (ok) { system("cls"); printf("On the next screen you will select the locomotive\n"); printf("you want to match speed tables with\n\n"); printf("Press a key:"); GetText(buf, 1, TRUE); loco = Select_Loco(-1); if (loco < 0 || loco == i) { ok = FALSE; } } if (ok) { ThrottleCheck(TRUE); TableMatch(i, loco); } } } while (!done); } /*************************************************************************** Resume main track clocks */ void EnableMainTrack(void) { WriteBuffer(port, "E\r", 2); ClearBuffer(); system("cls"); printf("Main track enabled! Press a key: "); GetText(buf, 1, TRUE); } /*************************************************************************** Display a section of memory */ void DisplayMemory(void) { int result; int lines; int first = TRUE; int i; int j; int x; unsl a; char addr[5]; system("cls"); printf("Memory Display\n\n"); printf("RAM Start Address (hex): "); result = GetText(buf, 4, FALSE); if (result == ESCAPE || strlen(buf) == 0) { return; } if (strlen(buf) == 1) { sprintf(addr, "000%s", buf); } else if (strlen(buf) == 2) { sprintf(addr, "00%s", buf); } else if (strlen(buf) == 3) { sprintf(addr, "0%s", buf); } else { strcpy(addr, buf); } printf("\nNumber of lines to display (decimal): "); result = GetText(buf, 2, FALSE); if (result == ESCAPE || atoi(buf) < 1) { return; } lines = atoi(buf); if (lines >= 16) { lines = 16; sprintf(buf, "F 0 %s\r", addr); } else { sprintf(buf, "F %X %s\r", lines, addr); } system("cls"); printf("Reading..."); a = HexToInt(addr); ClearBuffer(); WriteBuffer(port, buf, strlen(buf)); for (i = 0; i < lines; ++i) { ReadBufferTimed(port, buf, 33, 1000); if (first) { first = FALSE; printf("\n"); } printf("%.4X: ", a); if (buf[0] == '?') { i = lines; printf("End of data"); } else if (port->count) { for (j = x = 0; j != port->count; ++j) { printf("%c", buf[j]); ++x; if (x == 2) { printf(" "); x = 0; } } } printf("\n"); a += 0x10; } ClearBuffer(); printf("Press a key: "); GetText(buf, 1, TRUE); } /*************************************************************************** Who we are and what this is */ void About(void) { system("cls"); printf("EasyX is a freeware utility written by Mark Peterson for the\n"); printf("EasyDCC RS-232 interface. EasyX is Copyright (C) 2000 by\n"); printf("Mark Peterson, almost all rights reserved.\n\n"); printf("Mark Peterson and EasyX are in no way affiliated with CVP, EasyDCC\n"); printf("or any of their other products. They may tolerate his existance,\n"); printf("but no more than that.\n\n"); printf("Mark Peterson grants to all and sundry the rights to use and\n"); printf("distribute this program any way they see fit, so long as it is\n"); printf("not for profit.\n\n"); printf("This program is presented as is with no guarantees of any kind as\n"); printf("to it's utility, usability or performance.\n\n"); printf("Send comments to spookshow@uswest.net or mark@nbs-inc.com\n"); printf("Copies of EASYX may be downloaded from my website:\n"); printf("www.users.uswest.net/~spookshow\n"); printf("\n\nPress any key to continue:"); GetText(buf, 1, TRUE); } /*************************************************************************** main menu */ void Main_Menu(void) { int result; int done = FALSE; system("cls"); while (!done) { _settextposition(0, 0); printf ( "EasyX V1.4 - EasyDCC %-4.4s %-2.2s/%-2.2s/%s\n\n", version, version + 4, version + 6, version + 8 ); printf("A: Kill Main Track\n"); printf("B: Enable Main Track\n"); printf("C: Add New Locomotive/Program Decoder CVs\n"); printf("D: Display Command Station Memory\n"); printf("E: Manage Consists\n"); printf("F: Locomotive Operations\n"); printf("G: Custom Speed Tables\n"); printf("H: Sort Locomotive Roster\n"); printf("I: About EasyX\n\n"); printf("Selection (A-I,ESC=EXIT): "); result = GetText(buf, 1, TRUE); if (result == ESCAPE) { done = TRUE; } else if (buf[0] == 'A') { KillMainTrack(); system("cls"); } else if (buf[0] == 'B') { EnableMainTrack(); system("cls"); } else if (buf[0] == 'C') { ProgramCVs(); system("cls"); } else if (buf[0] == 'D') { DisplayMemory(); system("cls"); } else if (buf[0] == 'E') { ConsistMenu(); system("cls"); } else if (buf[0] == 'F') { Operations(); system("cls"); } else if (buf[0] == 'G') { SpeedTables(); system("cls"); } else if (buf[0] == 'H') { RosterSort(); system("cls"); } else if (buf[0] == 'I') { About(); system("cls"); } } } /*************************************************************************** get text from user */ int GetText(char *buf, int len, int hot) { int done = FALSE; int i = 0; uns u; uns x; while (!done) { u = _bios_keybrd(_KEYBRD_READ); x = u << 0xFF; u &= 0xFF; if (u == ESCAPE) { return (u); } if (u == ENTER) { done = TRUE; } else if (u == 0 && x == UP_ARROW) { u = UP_ARROW; done = TRUE; } else if (u == 0 && x == RIGHT_ARROW) { u = RIGHT_ARROW; done = TRUE; } else if (u == 0 && x == LEFT_ARROW) { u = LEFT_ARROW; done = TRUE; } else if (u == 0 && x == DOWN_ARROW) { u = DOWN_ARROW; done = TRUE; } else if (u == BACKSPACE) { if (i != 0) { --i; buf[i] = 0; printf("\b \b"); } } else if (u >= 32 && u <= 126) { if (i != len) { buf[i] = u; buf[i] = toupper(buf[i]); printf("%c", buf[i]); ++i; if (i == len && hot) { done = TRUE; } } } } buf[i] = 0; return (u); }