/* parse the input wheel pattern file to create a flash image    */
/* save this image to the output file and send it to the JimStim */

/* (c) 2009 Jean Bélanger                                        */

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <string.h>

main(int argc, char *argv[]) {

    FILE *file_in, *file_out;   
    unsigned int l=1, cc=1;
    unsigned char line[1024], c, buf[1], wheel_num, out, new_wheel, cksum;
	unsigned short wheel_addr[256], buf_pos;
	HANDLE hSerial;
	DCB dcbSerialParams = {0};
	COMMTIMEOUTS timeouts = {0};
	DWORD dwBytesTrans = 0;

    if (argc != 5) {
        fprintf(stderr, "Command usage is %s <jsw_input_file> <jsr_output_file> <COMx> <baud_rate>\n", argv[0]);
        exit(1);
    }
 
	hSerial = CreateFile(argv[3],
						 GENERIC_READ | GENERIC_WRITE,
						 0,
						 0,
						 OPEN_EXISTING,
						 FILE_ATTRIBUTE_NORMAL,
						 0);

	if (hSerial == INVALID_HANDLE_VALUE) {
		if (GetLastError() == ERROR_FILE_NOT_FOUND) {
			printf("Serial port does not exist.\n");
		} else {
			printf("Other error.\n");
		}
		exit(1);
	}

	dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

	if (!GetCommState(hSerial, &dcbSerialParams)) {
		printf("Error getting serial port state.\n");
	}

	if (strncmp(argv[4], "9600", 4) == 0) {
		dcbSerialParams.BaudRate = CBR_9600;
	} else if (strncmp(argv[4], "19200", 5) == 0) {
		dcbSerialParams.BaudRate = CBR_19200;
	} else if (strncmp(argv[4], "38400", 5) == 0) {
		dcbSerialParams.BaudRate = CBR_38400;
	} else if (strncmp(argv[4], "57600", 5) == 0) {
		dcbSerialParams.BaudRate = CBR_57600;
	} else {
		printf("Invalid baud rate. Must be 9600, 19200, 38400 or 57600.\n");
		exit(1);
	}
	dcbSerialParams.ByteSize = 8;
	dcbSerialParams.StopBits = ONESTOPBIT;
	dcbSerialParams.Parity = NOPARITY;

	if (!SetCommState(hSerial, &dcbSerialParams)) {
		printf("Error setting serial port state.\n");
	}

	timeouts.ReadIntervalTimeout = 0;
	timeouts.ReadTotalTimeoutConstant = 250;
	timeouts.ReadTotalTimeoutMultiplier = 1;
	timeouts.WriteTotalTimeoutConstant = 25;
	timeouts.WriteTotalTimeoutMultiplier = 1;

	if (!SetCommTimeouts(hSerial, &timeouts)) {
		printf("Error setting timeouts.\n");
	}

	line[0] = 'Q';
	line[1] = 0;
	line[31] = 0;
	if (!WriteFile(hSerial, line, 1, &dwBytesTrans, NULL)) {
		printf("Error sending request for the signature.\n");
	}

	if (!ReadFile(hSerial, line, 32, &dwBytesTrans, NULL)) {
		printf("Error reading the signature.\n");
	} else {
		printf("Signature: %s\n", line);
	}

	if (strncmp(line, "JimStim format V2.0.", 20) != 0) {
		printf("Signature mismatch.\n");
		exit(1);
	}

    if ((file_in = fopen(argv[1], "r")) == 0) {
        fprintf(stderr, "Failed to open %s, exiting\n", argv[1]);
        exit(1);
    }

    if ((file_out = fopen(argv[2], "wb")) == 0) {
        fprintf(stderr, "Failed to open/create %s, exiting\n", argv[2]);
        fclose(file_in);
        exit(1);
    }

	for (wheel_num = 0; wheel_num < 255; wheel_num++)
		wheel_addr[wheel_num] = 0xE200;
	wheel_addr[255] = 0xE200;
	wheel_num = 0;
	buf_pos = 0xE200;
	new_wheel = 0;
	cksum = 0;

	// Send the command to burn table 1 (wheel patterns)
	line[0] = 't';
	line[1] = 1;
	line[2] = 0;
	if (!WriteFile(hSerial, line, 2, &dwBytesTrans, NULL)) {
		printf("Error sending table 1 burning command.\n");
	}
	//printf("wait:\n");
	//getc(stdin);
	Sleep(200);

	while (!feof(file_in)) {
        c=1;
        cc = 0;
		// Read line
        while (c != 10) { //while not CR
            if (fread(buf, 1, 1, file_in) == 0) {
                 c = 10;
            } else {
//                c = (unsigned char)*buf;
                c = buf[0];
                if (c == 10) {
                    line[cc] = 0;
                } else {
//                    line[cc] = *buf; // copy to buffer
                    line[cc] = buf[0]; // copy to buffer
                }
                cc++;
            }
        }
        // now parse it
		if (cc <= 2 || line[0] == ';' || line[0] == '/') {
			// ignore line
		} else if (line[1] == 'x') {
			// Next Wheel
			wheel_num++;
			new_wheel = 1;
			buf[0] = 0xff;
			fwrite(buf, 1, 1, file_out);
			cksum += 0xff;

			// Send the data to table 1 (wheel patterns)
			if (!WriteFile(hSerial, buf, 1, &dwBytesTrans, NULL)) {
				printf("Error sending wheel pattern data 1.\n");
			}

			buf_pos++;
			if ((wheel_num & 0xF) == 15) {
				// Invalid wheel numbers 15, 31, ...
				wheel_addr[wheel_num++] = 0xE200;
			}
		} else {
			if (new_wheel) {
				wheel_addr[wheel_num] = buf_pos;
				printf("wheel address %d: %x\n", wheel_num, wheel_addr[wheel_num]);
				new_wheel = 0;
			}
			// Read tooth and write it to file
			out = 128 * (line[0] - 48) + 64 * (line[1] - 48);
			line[cc] = 0;
			out += atoi(&(line[3]));
			buf_pos++;
			fwrite(&out, 1, 1, file_out);
			cksum += out;

			// Send the data to table 1 (wheel patterns)
			if (!WriteFile(hSerial, &out, 1, &dwBytesTrans, NULL)) {
				printf("Error sending wheel pattern data 2.\n");
			}

		}
    }

    fclose(file_in);

	// Fill out the rest of the output file
	printf("buf_pos: %x\n", buf_pos);
	buf[0] = 0xff;
	for (;buf_pos < 0xF200; buf_pos++) {
		fwrite(buf, 1, 1, file_out);
		cksum += 0xff;

		// Send the data to table 1 (wheel patterns)
		if (!WriteFile(hSerial, buf, 1, &dwBytesTrans, NULL)) {
			printf("Error sending wheel pattern data 3.\n");
		}

	}
	// Get the checksum
	line[0] = 'k';
	line[1] = 0;
	if (!WriteFile(hSerial, line, 1, &dwBytesTrans, NULL)) {
		printf("Error requesting checksum.\n");
	}

	if (!ReadFile(hSerial, line, 1, &dwBytesTrans, NULL)) {
		printf("Error reading the checksum.\n");
	} else {
		printf("checksum : %d   received : %d        %d\n", cksum, line[0], dwBytesTrans);
	}

	// Send the command to burn table 2 (wheel addresses)
	cksum = 0;
	line[0] = 't';
	line[1] = 2;
	line[2] = 0;
	if (!WriteFile(hSerial, line, 2, &dwBytesTrans, NULL)) {
		printf("Error sending table 2 burning command.\n");
	}
	Sleep(100);

	// Send the wheel addresses (table 2)
	for (wheel_num = 0; wheel_num < 255; wheel_num++) {
		fwrite((unsigned char *)(wheel_addr+wheel_num)+1, 1, 1, file_out);
		fwrite(wheel_addr+wheel_num, 1, 1, file_out);
		cksum += *(unsigned char *)(wheel_addr+wheel_num) + *((unsigned char *)(wheel_addr+wheel_num)+1);

		// Send the data (MSB) to table 2 (wheel addresses)
		if (!WriteFile(hSerial, (unsigned char *)(wheel_addr+wheel_num)+1, 1, &dwBytesTrans, NULL)) {
			printf("Error sending wheel address data MSB.\n");
		}
		// Send the data (LSB) to table 2 (wheel addresses)
		if (!WriteFile(hSerial, wheel_addr+wheel_num, 1, &dwBytesTrans, NULL)) {
			printf("Error sending wheel address data MSB.\n");
		}

	}
	fwrite((unsigned char *)(wheel_addr+255)+1, 1, 1, file_out);
	fwrite(wheel_addr+255, 1, 1, file_out);
	cksum += *(unsigned char *)(wheel_addr+255) + *((unsigned char *)(wheel_addr+255)+1);
	// Send the data (MSB) to table 2 (wheel addresses)
	if (!WriteFile(hSerial, (unsigned char *)(wheel_addr+255)+1, 1, &dwBytesTrans, NULL)) {
		printf("Error sending wheel address data MSB.\n");
	}
	// Send the data (LSB) to table 2 (wheel addresses)
	if (!WriteFile(hSerial, wheel_addr+255, 1, &dwBytesTrans, NULL)) {
		printf("Error sending wheel address data MSB.\n");
		}

	// Get the checksum
	line[0] = 'k';
	line[1] = 0;
	if (!WriteFile(hSerial, line, 1, &dwBytesTrans, NULL)) {
		printf("Error requesting checksum.\n");
	}
	if (!ReadFile(hSerial, line, 1, &dwBytesTrans, NULL)) {
		printf("Error reading the checksum.\n");
	} else {
		printf("checksum : %d   received : %d        %d\n", cksum, line[0], dwBytesTrans);
	}

	fclose(file_out);

	CloseHandle(hSerial);
}


/* end of main */
