/*****************************************************************************/

/*
 *      eppdiag.c  -- HDLC packet radio modem for EPP using FPGA GUI tool.
 *
 *      Copyright (C) 1998, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Please note that the GPL allows you to use the driver, NOT the radio.
 *  In order to use the radio, you need a license from the communications
 *  authority of your country.
 *
 */

/*****************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif

#include "fpga.h"

#include <gtk/gtk.h>
#include <glib.h>
#include "gladesrc.h"
#include "gladesig.h"

/* ---------------------------------------------------------------------- */

static unsigned verboselevel = 0;
static int quit = 0;
static GtkWidget *diag;

/* ---------------------------------------------------------------------- */

int lprintf(unsigned vl, const char *format, ...)
{
	char buf[256];
        va_list ap;
        int r;
	char *cp;

#if 0
        if (vl > verboselevel)
                return 0;
#endif
	va_start(ap, format);
	r = vsnprintf(buf, sizeof(buf), format, ap);
	va_end(ap);
	while (cp = strchr(buf, '\r'))
		*cp = '\n';
	gtk_text_insert(GTK_TEXT(gtk_object_get_data(GTK_OBJECT(diag), "textl")), NULL, NULL, NULL, buf, r);
        return r;
}

int tprintf(const char *format, ...)
{
	char buf[256];
	va_list ap;
	int r;
	char *cp;

        va_start(ap, format);
	r = vsnprintf(buf, sizeof(buf), format, ap);
        va_end(ap);
	while (cp = strchr(buf, '\r'))
		*cp = '\n';
	gtk_text_insert(GTK_TEXT(gtk_object_get_data(GTK_OBJECT(diag), "textt")), NULL, NULL, NULL, buf, r);
	return r;
}

int idle_callback(unsigned us_delay)
{
	while (gtk_events_pending())
		gtk_main_iteration();
	if (us_delay)
		usleep(us_delay);
	return quit;
}

void epp_error(const char *msg)
{
	lprintf(0, msg);
	reset_modem();
	exit(1);
}

/* ---------------------------------------------------------------------- */

void on_bquit_clicked(GtkButton *button, gpointer user_data)
{
	quit = 1;
	gtk_main_quit();
}

void on_btest_clicked(GtkButton *button, gpointer user_data)
{
	static int test_run = 0;
	const struct eppfpgatests *tst;
	struct adapter_config cfg;
	gchar *cp;

	if (test_run) {
		quit = 1;
		return;
	}
	cp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(diag), "partest"))->entry));
	for (tst = eppfpgatests; tst->name && strcmp(cp, tst->name); tst++);
	if (!tst->name) {
		g_error("Internal Error: test %s not found\n", cp);
		return;
	}
	/*iobase = strtoul(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(diag), "paraddress"))->entry)), NULL, 0);*/
	cfg.intclk = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(diag), "parclk"))->active;
	cfg.bitrate = strtoul(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(diag), "parbitrate"))), NULL, 0);
	cfg.fclk = strtoul(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(diag), "parfclk"))), NULL, 0);
	cfg.extmodem = !GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(diag), "parmodem"))->active;
	cfg.loopback = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(diag), "parloopback"))->active;
	cfg.extstat = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(diag), "parstat"))->active;
	cp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(diag), "parfilter"))->entry));
	switch(cp[0]) {
	default:
		cfg.filtmode = 0;
		break;
	case 'A':
		cfg.filtmode = 1;
		break;
	case 'L':
		cfg.filtmode = 2;
		break;
	}
	cfg.gain = 1;
	test_run = 1;
	quit = 0;
	tst->func(&cfg);
	test_run = 0;
}

/* ---------------------------------------------------------------------- */

static void initdiag(void)
{
	GList *items = NULL;
	const struct eppfpgatests *tst;

	diag = create_diag();
	for (tst = eppfpgatests; tst->name; tst++)
		items = g_list_append(items, tst->name);
	gtk_combo_set_popdown_strings(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(diag), "partest")), items);
	g_list_free(items);

	gtk_widget_show(diag);
}

/* ---------------------------------------------------------------------- */

int main(int argc, char *argv[])
{
        static const struct option long_options[] = {
#ifdef HAVE_PPUSER
                { "ppuser", 1, 0, 0x400 },
                { "ppdev", 1, 0, 0x402 },
#endif
#ifdef HAVE_PPKDRV
                { "ppkdrv", 1, 0, 0x401 },
#endif
#ifdef WIN32
                { "ppgenport", 0, 0, 0x403 },
                { "ppwin", 1, 0, 0x404 },
                { "pplpt", 1, 0, 0x404 },
                { "ppring0", 0, 0, 0x405 },
#endif
		{ "ppforcehwepp", 0, 0, 0x410 },
		{ "ppswemulepp", 0, 0, 0x411 },
		{ "ppswemulecp", 0, 0, 0x412 },
		{ 0, 0, 0, 0 }
        };
	int c, err = 0;
	unsigned int iobase = 0x378, ntddkgenport = 0, ntdrv = 0, w9xring0 = 0, ppflags = 0;
	const char *ppuser = NULL, *ppkdrv = NULL, *ppdev = NULL;

	gtk_set_locale();
	gtk_init(&argc, &argv);
	while ((c = getopt_long(argc, argv, "vp:", long_options, NULL)) != EOF) {
		switch (c) {
		case 0x400:
			ppuser = optarg;
			ppkdrv = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 0;
			break;

		case 0x401:
			ppkdrv = optarg;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 0;
			break;

		case 0x402:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = optarg;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 0;
			break;

		case 0x403:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 1;
                        ntdrv = 0;
                        w9xring0 = 0;
                        break;

		case 0x404:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = strtoul(optarg, NULL, 0);
                        w9xring0 = 0;
			break;

		case 0x405:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 1;
			break;

		case 0x410:
			ppflags |= PPFLAG_FORCEHWEPP;
			break;

		case 0x411:
			ppflags |= PPFLAG_SWEMULEPP;
			break;

		case 0x412:
			ppflags |= PPFLAG_SWEMULECP;
			break;

		case 'v':
			verboselevel++;
			break;

		case 'p': 
			iobase = strtoul(optarg, NULL, 0);
			if (iobase <= 0 || iobase >= 0x3f8)
				err++;
			break;

		default:
			err++;
			break;
		}
	}
	if (err) {
		lprintf(0, "usage: %s [-v] [-p <portaddr>]\n", argv[0]);
		exit(1);
	}
#ifdef HAVE_PPUSER
	if (ppkdrv) {
		if (parport_init_ppkdrv(ppkdrv)) {
			fprintf(stderr, "no kernel interface %s driver found\n", ppkdrv);
			exit(1);
		}
	} else
#endif
#ifdef HAVE_PPUSER
		if (ppdev) {
			if (parport_init_ppdev(ppdev)) {
				fprintf(stderr, "no ppdev driver found at %s\n", ppdev);
				exit(1);
			}
		} else if (ppuser) {
			if (parport_init_ppuser(ppuser)) {
				fprintf(stderr, "no ppuser driver found at %s\n", ppuser);
				exit(1);
			}
		} else
#endif
#ifdef WIN32
                        if (ntdrv) {
                                if (parport_init_win_flags(ntdrv-1, ppflags)) {
                                        fprintf(stderr, "no eppflex.sys/vxd driver found\n");
                                        exit(1);
                                }
                        } else if (ntddkgenport) {
                                if (parport_init_ntddkgenport()) {
                                        fprintf(stderr, "no NTDDK genport.sys driver found\n");
                                        exit(1);
                                }
                        } else if (w9xring0) {
                                if (parport_init_w9xring0_flags(iobase, ppflags)) {
                                        fprintf(stderr, "no parport found at 0x%x\n", iobase);
                                        exit(1);
                                }
                        } else
#endif
                                if (parport_init_direct_flags(iobase, ppflags)) {
                                        fprintf(stderr, "no parport found at 0x%x\n", iobase);
                                        exit(1);
                                }
	initdiag();
	gtk_main();
	exit(0);
}
