/* 
 * W2000A Firmware Upload Tool
 */

#include <stdio.h>
#include <windows.h>

#include "ComTools.h"

OPENFILENAME ofn;
char firmwfn[512];

int
find_and_select_comport(void)
{
	HANDLE comport;
	HWND hwnd;
	MSG msg;
	int portlist[20];
	char *ports[20];
	char portfn[16];
	int i, j, r;

	(void)printf(" * Searching for COM ports...\n");

	j = 0;
	for (i = 1; i < 21; i++) {
		(void)snprintf(portfn, sizeof(portfn), "\\\\.\\COM%d", i);
		if ((comport = CreateFile(portfn, GENERIC_READ | GENERIC_WRITE,
				0, 0, OPEN_EXISTING, 0, 0))
		    == INVALID_HANDLE_VALUE) {
			/* 
			 * The COM-Port might exist but is already in use.
			 */
			if (GetLastError() == ERROR_ACCESS_DENIED) {
				(void)printf("    - COM%d (in use/access denied)\n", i);
				portlist[j] = i;
				ports[j] = (char *)malloc(32);
				(void)snprintf(ports[j], 32, "COM%d (in use/access denied)", i);
				j++;
			}
		} else {
			(void)printf("    - COM%d\n", i);
			(void)CloseHandle(comport);
			portlist[j] = i;
			ports[j] = (char *)malloc(8);
			(void)snprintf(ports[j], 8, "COM%d", i);
			j++;
		}
	}
	portlist[j] = 0;

	(void)printf(" * Found %d COM-Port(s)\n", j);

	if (j < 1) {
		(void)fprintf(stderr, "ERROR:  Not a single COM port found, exiting.\n");
		(void)MessageBox(NULL, "Not a single COM port found!",
				"Error, Cannot Continue",
				MB_OK | MB_ICONERROR);
		exit(1);
	}

	(void)printf(" * Asking the user to select COM port...\n");

	if (!(hwnd = CreateWindow("listbox", "Select COM port",
				LBS_SORT,
				CW_USEDEFAULT, CW_USEDEFAULT,
				300, 300,
				NULL, NULL,  NULL, NULL)))  {
		(void)fprintf(stderr, "ERROR:  CreateWindow() failed.\n");
		exit(1);
	}

	for (i = 0; i < j; i++)
		(void)SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)ports[i]);

	(void)ShowWindow(hwnd, SW_SHOW);
	(void)UpdateWindow(hwnd);

	while ((r = GetMessage(&msg, hwnd, 0, 0)) != 0) {
		if (r == -1) {
			;
		} else {
			(void)TranslateMessage(&msg);
			(void)DispatchMessage(&msg);

			if ((r = SendMessage(hwnd, LB_GETCURSEL, 0, 0)) != -1)
				break;
		}
	}

	(void)DestroyWindow(hwnd);

	(void)printf(" * User selected: \"%s\"\n", ports[r]);

	for (i = 0; i < j; i++)
		(void)free(ports[i]);

	return portlist[r];
}

void
ask_for_firmware()
{

	(void)printf(" * Asking the user to select firmware file...\n");

	*firmwfn = '\0';
	(void)memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = NULL;
	ofn.hInstance = NULL;
	ofn.lpstrFile = firmwfn;
	ofn.nMaxFile = sizeof(firmwfn);
	ofn.lpstrTitle = "Select Firmware to Upload to DSO";
	ofn.lpstrFilter = "Firmware Files *.flash, *.ram\0*.flash;*.ram\0"
			  "All Files *.*\0*.*\0\0";
	ofn.nFilterIndex = 1;
	ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

	if (GetOpenFileName(&ofn) == TRUE) {
		(void)printf(" * User selected: \"%s\"\n", firmwfn);
	} else {
		(void)fprintf(stderr, "ERROR:  Nothing selected, exiting.\n");
		(void)MessageBox(NULL, "Nothing selected!",
			"Error, Cannot Continue",
			MB_OK | MB_ICONERROR);
		exit(1);
	}

}

int
comreadc(int port)
{

	while (ComGetReadCount(port - 1) < 1)
		;
	return ComRead(port - 1);
}

void
upload_firmware(int port)
{
	FILE *fp;
	char fbuf[256];
	char pbuf[256];
	char *p;
	int line, c;
	size_t i;

	(void)printf(" * Uploading firmware to DSO\n");

	if ((fp = fopen(firmwfn, "r")) == NULL) {
		(void)ComClose(port - 1);
		(void)fprintf(stderr, "ERROR:  Unable to read firmware file, exiting.\n");
		(void)MessageBox(NULL, "Unable to read firmware file!",
			"Error, Cannot Continue",
			MB_OK | MB_ICONERROR);
		exit(1);
	}

	line = 0;
	while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
		line++;
		(void)printf("\r   - @line %d", line);
		(void)fflush(stdout);

		if (*fbuf == '\n' || *fbuf == '\r' || *fbuf == '#')
			continue;
		
		if ((p = strchr(fbuf, '\r')) != NULL)
			*p = '\0';
		if ((p = strchr(fbuf, '\n')) != NULL)
			*p = '\0';

		(void)printf(" |writing to DSO| ");
		(void)fflush(stdout);

		ComWrite(port - 1, fbuf, strlen(fbuf));
		ComWrite(port - 1, '\r');

		(void)printf(" |reading response| ");
		(void)fflush(stdout);
		
		i = 0;
		while ((c = comreadc(port)) != '+' && i < sizeof(pbuf)-1) {
			pbuf[i] = c;
			i++;
		}
		pbuf[i] = '\0';

		if (strncmp(fbuf, pbuf, strlen(fbuf) - 1) != 0) {
			(void)ComClose(port - 1);
			(void)fprintf(stderr, "TRANSMISSION ERROR!\n");
			(void)fprintf(stderr, "DEBUG:  Input was:\n%s\n", fbuf);
			(void)fprintf(stderr, "DEBUG:  DSO's response was:\n%s\n", pbuf);
			(void)MessageBox(NULL, "Transmission error while uploading firmware to DSO!",
				"Error, Operation Failed",
				MB_OK | MB_ICONERROR);
			exit(1);
		}

		if (*fbuf == 'S'
		    && (fbuf[1] == '7' || fbuf[1] == '8' || fbuf[1] == '9')) {
			(void)printf("\n * S[789] command detected, end of GERMS transmission\n");
			break;
		}
	}

}

int
main(void)
{
	int p;

	(void)printf("w2000a-fwupload for win32 v0.1\n");

	p = find_and_select_comport();
	ask_for_firmware();

	(void)printf(" * Opening COM%d (115200,8,N,1)...", p);
	(void)fflush(stdout);
	if (!ComOpen(p - 1, 115200, P_NONE, S_1BIT, D_8BIT)) {
		(void)fprintf(stderr, "ERROR:  Unable to open COM port.\n");
		(void)MessageBox(NULL, "Unable to open COM port!",
			"Error, Cannot Continue",
			MB_OK | MB_ICONERROR);
		exit(1);
	}
	(void)printf(" success\n");
	
	(void)printf(" * Asking the user to put the DSO into GERMS loader, if not already done...\n");
	(void)MessageBox(NULL, "Please make sure the DSO is in GERMS loader mode:\nPress and hold first soft button while pressing and releasing second soft button.  Then release first soft button.\nThe DSO's screen should have shortly become white and then stay black.",
		"Ready to Load Firmware",
		MB_OK | MB_ICONEXCLAMATION);

	upload_firmware(p);

	(void)ComClose(p - 1);

	(void)MessageBox(NULL, "All done!  (Soft)Reboot DSO if screen stays black.",
		"Success",
		MB_OK | MB_ICONINFORMATION);

	return 0;
}
