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

/*
 *      main.c  --  Trx Control Application.
 *
 *      Copyright (C) 2000-2001
 *        Thomas Sailer (t.sailer@alumni.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.
 */

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

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>

#include <glib.h>

#include "interface.h"
#include "support.h"
#include "signalhist.h"
#include "callbacks.h"

#ifndef WIN32
#include <sys/socket.h>
#include <sys/ioctl.h>
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

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

#include "trxapp.h"
#include "trxapi.h"
#include "widgets.h"

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

#include "option1.xpm"
#include "option2.xpm"

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

static GtkWidget *mainwindow, *terminalwindow, *chmemorywindow, *chprogwindow, *freqlistwindow, *newstnwindow;
static GtkWidget *modemselectwindow, *configwindow, *dtmfwindow, *spkscopewindow, *spkspectrumwindow;
static GtkWidget *micscopewindow, *micspectrumwindow, *paramwindow, *audiopwrwindow;
static unsigned int ledstatus = 0;

static struct {
	struct trxapi *trx;
        const struct trxapi_description *desc;
	trxapi_mode_t mode;
	float rssimul;
} trx = { NULL, NULL, trxapi_mode_unspec };

static struct {
	trxapi_frequency_t rx, tx;
	guint fchginhibit;
} freq = { 0, 0, 0 };

static struct {
	int sel;
	int del;
} freql = { -1, -1 };

static int selectmodem_sel = -1;
static unsigned int notebook_pagemask = 0;
static unsigned long rxuartptr = 0;
static unsigned int pttmask = 0;
#define PTTMASK_MANUAL 1
#define PTTMASK_1750   2
#define PTTMASK_DTMF   4

static struct {
	unsigned char enaptt;
} params = { 0 };

static struct {
        unsigned int lptr;
        unsigned char rxline[256];
} uartline = { 0, };

static struct {
        int rx, tx;
} chmem[10];

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

static void updatechmemwindow(void);

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

static void paramstodialog(void)
{
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(paramwindow), "paramenablepttpkt")), params.enaptt);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "buttonptt")), trx.mode == trxapi_mode_audio || (trx.mode == trxapi_mode_packet && params.enaptt));
}

static void trxnewmode(trxapi_mode_t newmode)
{
	if (trx.mode != newmode) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "audio")), newmode == trxapi_mode_audio);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "buttonptt")), newmode == trxapi_mode_audio || (newmode == trxapi_mode_packet && params.enaptt));
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "button1750")), newmode == trxapi_mode_audio);
	}
	trx.mode = newmode;
}

static void updatepttmask(void)
{
	if (trx.trx == NULL)
		return;
	if (trxapi_set_ptt(trx.trx, !!pttmask))
		lprintf(1, "trxapi_set_ptt error\n");
}

static void closetrx(void)
{
	if (trx.trx)
		trxapi_close(trx.trx);
	trx.trx = NULL;
	trx.desc = NULL;
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "modemconfig")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "audio")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "expert")), FALSE);
	trxnewmode(trxapi_mode_unspec);
	pttmask = 0;
	updatepttmask();
}

static void newtrx(struct trxapi *api, const struct trxapi_description *desc)
{
	const struct trxapi_baycomusb_adapter_audio_devs *audiodevs;
	float f;
	unsigned int i;
	char buf[1024];
	GtkSpinButton *rxqrg, *txqrg;
	trxapi_frequency_t fmin, fmax, fstep;

	closetrx();
	trx.trx = api;
	trx.desc = desc;
	/* set RSSI limits */
	f = desc->rssimax - desc->rssimin;
	if (f < 0.0001)
		trx.rssimul = 0;
	else
		trx.rssimul = 255.0 / f;
	gtk_progress_configure(GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(mainwindow), "rssi")), 
			       desc->rssimin, desc->rssimin, desc->rssimax);
	/* set rxuart pointer to current value */
	rxuartptr = 0;
	trxapi_uart_receive(trx.trx, &rxuartptr, buf, sizeof(buf));
	/* clear UART received line */
	uartline.lptr = 0;
	/* clear T7F memory */
	for (i = 0; i < 10; i++)
		chmem[i].rx = chmem[i].tx = -1;
	updatechmemwindow();
	/* cause T7F to transmit channel memory */
	if (trxapi_uart_send(trx.trx, "\rE\r"))
		lprintf(1, "trxapi_uart_send error\n");
	/* set frequency limits */	
	rxqrg = GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "rxqrg"));
	txqrg = GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "txqrg"));
	fmin = ~0ULL;
	fmax = 0ULL;
	fstep = 1000000ULL;
	for (i = 0; i < desc->nrrxbands; i++) {
		if (desc->rxbands[i].low < fmin)
			fmin = desc->rxbands[i].low;
		if (desc->rxbands[i].high > fmax)
			fmax = desc->rxbands[i].high;
		if (fstep > desc->rxbands[i].step)
			fstep = desc->rxbands[i].step;
	}
	gtk_spin_button_set_adjustment(rxqrg, GTK_ADJUSTMENT(gtk_adjustment_new(fmin * (1.0 / 1000000.0), fmin * (1.0 / 1000000.0),
										fmax * (1.0 / 1000000.0), fstep * (1.0 / 1000000.0), 1, 1)));
	fmin = ~0ULL;
	fmax = 0ULL;
	fstep = 1000000ULL;
	for (i = 0; i < desc->nrtxbands; i++) {
		if (desc->txbands[i].low < fmin)
			fmin = desc->txbands[i].low;
		if (desc->txbands[i].high > fmax)
			fmax = desc->txbands[i].high;
		if (fstep > desc->txbands[i].step)
			fstep = desc->txbands[i].step;
	}
	gtk_spin_button_set_adjustment(txqrg, GTK_ADJUSTMENT(gtk_adjustment_new(fmin * (1.0 / 1000000.0), fmin * (1.0 / 1000000.0),
										fmax * (1.0 / 1000000.0), fstep * (1.0 / 1000000.0), 1, 1)));
	gtk_widget_set_sensitive(GTK_WIDGET(rxqrg), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(txqrg), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "stnname")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "modemconfig")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "expert")), TRUE);
	freq.rx = freq.tx = 0;
	paramstodialog();
	pttmask = 0;
	updatepttmask();
	/* Update dialog with list of audio devices */
	audiodevs = trxapi_baycomusb_adapter_get_audiodevices(trx.trx);
	if (audiodevs) {
		GList *list;
		list = NULL;
		for (i = 0; i < audiodevs->nraudiodevsin; i++)
			list = g_list_append(list, audiodevs->audiodevsin[i]);
		if (list) {
			gtk_combo_set_popdown_strings(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiodevin")), list);
			g_list_free(list);
		}
		list = NULL;
		for (i = 0; i < audiodevs->nraudiodevsout; i++)
			list = g_list_append(list, audiodevs->audiodevsout[i]);
		if (list) {
			gtk_combo_set_popdown_strings(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiodevout")), list);
			g_list_free(list);
		}
	}
}

static void trxopenbyindex(unsigned int index)
{
	struct trxapi *api;
        const struct trxapi_description *desc;

        if (!(api = trxapi_open_byindex(index)))
                return;
	if (!(desc = trxapi_get_description(api))) {
                trxapi_close(api);
		return;
	}
	newtrx(api, desc);
}

static void trxopenbymfgmodelserial(const char *mfg, const char *model, const char *serial)
{
	struct trxapi *api;
        const struct trxapi_description *desc;
	unsigned int i;

	for (i = 0; ; i++) {
		if (!(api = trxapi_open_byindex(i)))
			return;
		if (!(desc = trxapi_get_description(api))) {
			trxapi_close(api);
			continue;
		}
		if (!strcmp(desc->manufacturer, mfg) && !strcmp(desc->model, model) && !strcmp(desc->instid, serial)) {
			newtrx(api, desc);
			return;
		}
		trxapi_close(api);
	}
}

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

static void setled(GtkPixmap *pixmap, int on)
{
	GdkColormap *colormap;
	GdkPixmap *gdkpixmap;
	GdkBitmap *mask;

	colormap = gtk_widget_get_colormap(mainwindow);
	gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL, on ? option2_xpm : option1_xpm);
	gtk_pixmap_set(pixmap, gdkpixmap, mask);
	gdk_pixmap_unref(gdkpixmap);
	gdk_bitmap_unref(mask);
}

GtkWidget* create_led_pixmap(gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2)
{
	GtkWidget *pixmap, *wnd;
	GdkColormap *colormap;
	GdkPixmap *gdkpixmap;
	GdkBitmap *mask;

	wnd = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_widget_ref(wnd);
	colormap = gtk_widget_get_colormap(wnd);
	gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL, option1_xpm);
	pixmap = gtk_pixmap_new(gdkpixmap, mask);
	gdk_pixmap_unref(gdkpixmap);
	gdk_bitmap_unref(mask);
	gtk_widget_unref(wnd);
	return pixmap;
}

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

static void updatechmemwindow(void)
{
        char buf[8] = "ch0a";
        char buf2[32];
        unsigned int i;

        for (i = 0; i < 10; i++) {
                buf[2] = '0'+i;
                buf[3] = 'a';
                if (chmem[i].rx == -1)
                        snprintf(buf2, sizeof(buf2), "-");
                else
                        snprintf(buf2, sizeof(buf2), "%8.4fMHz", 430+chmem[i].rx * 0.0125);
                gtk_label_set_text(GTK_LABEL(gtk_object_get_data(GTK_OBJECT(chmemorywindow), buf)), buf2);
                buf[3] = 'b';
                if (chmem[i].tx == -1)
                        snprintf(buf2, sizeof(buf2), "-");
                else
                        snprintf(buf2, sizeof(buf2), "%8.4fMHz", 430+chmem[i].tx * 0.0125);
                gtk_label_set_text(GTK_LABEL(gtk_object_get_data(GTK_OBJECT(chmemorywindow), buf)), buf2);
                buf[3] = 'c';
                if (chmem[i].rx == -1)
                        snprintf(buf2, sizeof(buf2), "-");
                else
                        snprintf(buf2, sizeof(buf2), "%8.4fMHz", 430+chmem[i].rx * 0.025);
                gtk_label_set_text(GTK_LABEL(gtk_object_get_data(GTK_OBJECT(chmemorywindow), buf)), buf2);
                buf[3] = 'd';
                if (chmem[i].tx == -1)
                        snprintf(buf2, sizeof(buf2), "-");
                else
                        snprintf(buf2, sizeof(buf2), "%8.4fMHz", 430+chmem[i].tx * 0.025);
                gtk_label_set_text(GTK_LABEL(gtk_object_get_data(GTK_OBJECT(chmemorywindow), buf)), buf2);
        }
}

static void setstns(void)
{
	GList *list = NULL;

	list = g_list_append(list, "-");
	list = stndb_list(list);
	gtk_combo_set_popdown_strings(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(mainwindow), "stnname")), list);
	g_list_free(list);
	stndb_clist(GTK_CLIST(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "freqlist")));
}

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

static void processuart(char *str)
{
        static int chparse = -1;
        unsigned int tx, rx;

        printf("Processuart: \"%s\"\n", str);
        if (!strcmp(str, "E")) {
                chparse = 0;
                return;
        }
        if (chparse >= 0 && sscanf(str, " %x %x", &tx, &rx) == 2) {
                chmem[chparse].rx = rx;
                chmem[chparse].tx = tx;
                chparse++;
                if (chparse > 9)
                        chparse = -1;
                updatechmemwindow();
                return;
        }
        chparse = -1;
}

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

static void on_aboutok_clicked(GtkButton *button, gpointer user_data)
{
        gtk_widget_hide(GTK_WIDGET(user_data));
        gtk_widget_destroy(GTK_WIDGET(user_data));
}

void on_about_activate(GtkMenuItem *menuitem, gpointer user_data)
{
        GtkWidget *dlg = create_aboutwindow();

        gtk_signal_connect(GTK_OBJECT(gtk_object_get_data(GTK_OBJECT(dlg), "aboutok")), 
                           "clicked", GTK_SIGNAL_FUNC(on_aboutok_clicked), dlg);
        gtk_widget_show(dlg);
}

static void on_errorok_clicked(GtkButton *button, gpointer user_data)
{
        gtk_widget_hide(GTK_WIDGET(user_data));
        gtk_widget_destroy(GTK_WIDGET(user_data));
}

void error_dialog(const gchar *text)
{
        GtkWidget *dlg = create_errordialog();

        gtk_signal_connect(GTK_OBJECT(gtk_object_get_data(GTK_OBJECT(dlg), "errorok")), 
                           "clicked", GTK_SIGNAL_FUNC(on_errorok_clicked), dlg);
        gtk_label_set_text(GTK_LABEL(gtk_object_get_data(GTK_OBJECT(dlg), "errorlabel")), text);
        gtk_widget_show(dlg);
}

gboolean on_mainwindow_destroy_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
        gtk_main_quit();
        return TRUE;
}

gboolean on_mainwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
        gtk_main_quit();
        return FALSE;
}

void on_quit_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_main_quit();
}

void on_terminal_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(terminalwindow);
}

gboolean on_terminalwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(terminalwindow);
	return TRUE;
}

void on_buttonptt_toggled(GtkToggleButton *togglebutton, gpointer user_data)
{
	if (trx.trx == NULL)
		return;
	if (gtk_toggle_button_get_active(togglebutton))
		pttmask |= PTTMASK_MANUAL;
	else
		pttmask &= ~PTTMASK_MANUAL;
	updatepttmask();
}

void on_button1750_pressed(GtkButton *button, gpointer user_data)
{
	if (trx.trx == NULL)
		return;
	pttmask |= PTTMASK_1750;
	updatepttmask();
	if (trx.mode == trxapi_mode_audio) {
		if (trxapi_set_audio_dtmf(trx.trx, 16))
			lprintf(1, "trxapi_set_audio_dtmf error\n");
	}
}


void on_button1750_released(GtkButton *button, gpointer user_data)
{
	if (trx.trx == NULL)
		return;
	pttmask &= ~PTTMASK_1750;
	updatepttmask();
	if (trx.mode == trxapi_mode_audio) {
		if (trxapi_set_audio_dtmf(trx.trx, -1))
			lprintf(1, "trxapi_set_audio_dtmf error\n");
	}
}

gboolean on_text_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
        GtkText *txt;
        char c = event->keyval;
	char buf[2];

	buf[0] = c;
	buf[1] = 0;
        printf("on_text_keypress_event: 0x%x %c  state %u\n", event->keyval, (c >= ' ' && c <= 0x7f) ? c : '.', event->state);
	if (trx.trx == NULL)
		return FALSE;
        txt = GTK_TEXT(gtk_object_get_data(GTK_OBJECT(terminalwindow), "text"));
        if (event->keyval == GDK_Return) {
		buf[0] = '\r';
		c = '\n';
		if (!trxapi_uart_send(trx.trx, buf))
			gtk_text_insert(txt, NULL, &(GTK_WIDGET(txt)->style->fg[GTK_WIDGET_STATE(GTK_WIDGET(txt))]), NULL, &c, 1);
		return TRUE;
        }
        if (event->keyval >= 32 && event->keyval < 128) {
		if (!trxapi_uart_send(trx.trx, buf))
			gtk_text_insert(txt, NULL, &(GTK_WIDGET(txt)->style->fg[GTK_WIDGET_STATE(GTK_WIDGET(txt))]), NULL, &c, 1);
                return TRUE;
        }
	return FALSE;
}

gboolean on_text_key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
        char c = event->keyval;

        printf("on_text_keyrelease_event: 0x%x %c  state %u\n", event->keyval, (c >= ' ' && c <= 0x7f) ? c : '.', event->state);
        return TRUE;
}

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

static void set_frequencies(trxapi_frequency_t rx, trxapi_frequency_t tx)
{
	GtkSpinButton *rxqrg, *txqrg;

	rxqrg = GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "rxqrg"));
	txqrg = GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "txqrg"));
	gtk_signal_disconnect_by_func(GTK_OBJECT(rxqrg), GTK_SIGNAL_FUNC(on_qrg_changed), NULL);
	gtk_signal_disconnect_by_func(GTK_OBJECT(txqrg), GTK_SIGNAL_FUNC(on_qrg_changed), NULL);
	gtk_spin_button_set_value(rxqrg, rx * (1.0 / 1000000.0));
      	gtk_spin_button_set_value(txqrg, tx * (1.0 / 1000000.0));
	gtk_signal_connect(GTK_OBJECT(rxqrg), "changed", GTK_SIGNAL_FUNC(on_qrg_changed), NULL);
	gtk_signal_connect(GTK_OBJECT(txqrg), "changed", GTK_SIGNAL_FUNC(on_qrg_changed), NULL);
}

static void set_stnname(const char *name)
{
	GtkEntry *entry;

	entry = GTK_ENTRY(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(mainwindow), "stnname"))->entry);
	gtk_signal_disconnect_by_func(GTK_OBJECT(entry), GTK_SIGNAL_FUNC(on_stn_changed), NULL);
	gtk_entry_set_text(entry, name);
	gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(on_stn_changed), NULL);
}

static gint fchgtimeout(gpointer user_data)
{
	freq.fchginhibit = 0;
	return FALSE;
}

static void set_station(const char *name)
{
	struct stndb_entry stnent;
	struct trxapi_baycomusb_adapter_config adaptcfg;

	if (!name)
		return;
	memset(&stnent, 0, sizeof(stnent));
	stnent.mode = -1;
	strncpy(stnent.name, name, sizeof(stnent.name));
	if (stndb_retrieve(&stnent)) {
		printf("Station \"%s\" not found in database\n", stnent.name);
		return;
	}
	if (trx.trx != NULL) {
		if (stnent.mode == trxapi_baycomusb_mode_fsk ||
		    stnent.mode == trxapi_baycomusb_mode_afsk ||
		    stnent.mode == trxapi_baycomusb_mode_external ||
		    stnent.mode == trxapi_baycomusb_mode_audio) {
			if (trxapi_baycomusb_adapter_get_config(trx.trx, &adaptcfg)) {
				lprintf(1, "trxapi_baycomusb_adapter_get_config error\n");
			} else {
				adaptcfg.mode = stnent.mode;
				if (stnent.mode == trxapi_baycomusb_mode_fsk) {
					adaptcfg.bitraterx = stnent.bitraterx;
					adaptcfg.bitratetx = stnent.bitratetx;
				}
				if (trxapi_baycomusb_adapter_set_config(trx.trx, &adaptcfg))
					lprintf(1, "trxapi_baycomusb_adapter_set_config error\n");
			}
		}
		if (trxapi_set_frequency(trx.trx, stnent.rx, stnent.tx)) {
			lprintf(1, "trxapi_set_frequency error\n");
			return;
		}
	}
	set_frequencies(stnent.rx, stnent.tx);
	//set_stnname(stnent.name);
	freq.rx = stnent.rx;
	freq.tx = stnent.tx;
	if (freq.fchginhibit)
		gtk_timeout_remove(freq.fchginhibit);
	freq.fchginhibit = gtk_timeout_add(3000, fchgtimeout, NULL);
}

void on_qrg_changed(GtkEditable *editable, gpointer user_data)
{
	gfloat rxqrg, txqrg;
	struct stndb_entry stnent;

	printf("on_qrg_changed\n");
	memset(&stnent, 0, sizeof(stnent));
	rxqrg = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "rxqrg")));
	txqrg = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "txqrg")));
	stnent.rx = rxqrg * 1000000;
	stnent.tx = txqrg * 1000000;
	stnent.rx = (stnent.rx + 50) / 100 * 100;
	stnent.tx = (stnent.tx + 50) / 100 * 100;
	if (trx.trx != NULL) {
		if (trxapi_set_frequency(trx.trx, stnent.rx, stnent.tx)) {
			lprintf(1, "trxapi_set_frequency error\n");
			return;
		}
	}
	freq.rx = stnent.rx;
	freq.tx = stnent.tx;
	if (freq.fchginhibit)
		gtk_timeout_remove(freq.fchginhibit);
	freq.fchginhibit = gtk_timeout_add(3000, fchgtimeout, NULL);
	stnent.mode = -1;
	if (trx.trx != NULL) {
		struct trxapi_baycomusb_adapter_config adaptcfg;

		if (trxapi_baycomusb_adapter_get_config(trx.trx, &adaptcfg)) {
			lprintf(1, "trxapi_baycomusb_adapter_get_config error\n");
		} else {
   		        stnent.mode = adaptcfg.mode;
			stnent.bitraterx = adaptcfg.bitraterx;
			stnent.bitratetx = adaptcfg.bitratetx;
		}
	}
	if (stndb_retrieve(&stnent) || !stnent.name[0])
		strncpy(stnent.name, "-", sizeof(stnent.name));
	set_stnname(stnent.name);
}

void on_stn_changed(GtkEditable *editable, gpointer user_data)
{
	gchar *stnname = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(gtk_object_get_data(GTK_OBJECT(mainwindow), "stnname"))->entry));

	printf("Station Name Change: %s\n", stnname);
	if (!strcmp(stnname, "-"))
		return;
	set_station(stnname);
}

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

void on_chprog_raster_toggled(GtkToggleButton *togglebutton, gpointer user_data)
{
	unsigned int raster, rx, tx;
	GtkSpinButton *rxqrg, *txqrg;
	gfloat rxv, txv;

	raster = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "raster")));
	rxqrg = GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "rxqrg"));
	txqrg = GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "txqrg"));
	rxv = gtk_spin_button_get_value_as_float(rxqrg);
	txv = gtk_spin_button_get_value_as_float(txqrg);
	if (raster) {
		rx = (rxv + (0.0125 / 2 - 430)) * (1.0 / 0.0125);
		tx = (txv + (0.0125 / 2 - 430)) * (1.0 / 0.0125);
		if (rx >= 800)
			rx = 799;
		if (tx >= 800)
			tx = 799;
		rxv = 430 + rx * 0.0125;
		txv = 430 + tx * 0.0125;
		gtk_spin_button_set_adjustment(rxqrg, GTK_ADJUSTMENT(gtk_adjustment_new(rxv, 430, 440, 0.0125, 1, 1)));
		gtk_spin_button_set_adjustment(txqrg, GTK_ADJUSTMENT(gtk_adjustment_new(txv, 430, 440, 0.0125, 1, 1)));
	} else {
		rx = (rxv + (0.025 / 2 - 430)) * (1.0 / 0.025);
		tx = (txv + (0.025 / 2 - 430)) * (1.0 / 0.025);
		if (rx >= 400)
			rx = 399;
		if (tx >= 400)
			tx = 399;
		rxv = 430 + rx * 0.025;
		txv = 430 + tx * 0.025;
		gtk_spin_button_set_adjustment(rxqrg, GTK_ADJUSTMENT(gtk_adjustment_new(rxv, 430, 440, 0.025, 1, 1)));
		gtk_spin_button_set_adjustment(txqrg, GTK_ADJUSTMENT(gtk_adjustment_new(txv, 430, 440, 0.025, 1, 1)));
	}
	gtk_spin_button_set_value(rxqrg, rxv);
	gtk_spin_button_set_value(txqrg, txv);
}

void on_chprog_channel_changed(GtkEditable *editable, gpointer user_data)
{
	unsigned int ch, raster, divmax;
	gfloat r;
	
	ch = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "channel")));
	raster = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "raster")));
	r = raster ? 0.0125 : 0.025;
	divmax = raster ? 800 : 400;
	if (ch < 10) {
		if (chmem[ch].rx >= 0 && chmem[ch].rx <= divmax)
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "rxqrg")), 430 + r * chmem[ch].rx);
		if (chmem[ch].tx >= 0 && chmem[ch].tx <= divmax)
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "txqrg")), 430 + r * chmem[ch].tx);
	}
}

void on_chprogok_clicked(GtkButton *button, gpointer user_data)
{
	unsigned int ch, raster, rx, tx, divmax;
	float rxqrg, txqrg, rst, rnd;
	char buf[256];

	gtk_widget_hide(chprogwindow);
	ch = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "channel")));
	raster = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "raster")));
	rxqrg = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "rxqrg")));
	txqrg = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(chprogwindow), "txqrg")));
	rnd = raster ? (0.0125 / 2 - 430) : (0.025 / 2 - 430);
	rst = raster ? (1.0 / 0.0125) : (1.0 / 0.025);
	divmax = raster ? 800 : 400;
	rx = (rxqrg - rnd) * rst;
	tx = (txqrg - rnd) * rst;
	if (rx > divmax)
		rx = divmax;
	if (tx > divmax)
		tx = divmax;
	snprintf(buf, sizeof(buf), "\rC%1d%03d%03d\rE\r", ch, tx, rx);
	if (trx.trx == NULL)
		return;
	if (trxapi_uart_send(trx.trx, buf))
		lprintf(1, "trxapi_uart_send error\n");
}

void on_chprogcancel_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_hide(chprogwindow);
}


void on_channelwindow_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(chmemorywindow);
}


void on_progchmem_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(chprogwindow);
}

gboolean on_chmemorywindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(chmemorywindow);
	return TRUE;
}

gboolean on_chprogwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(chprogwindow);
	return TRUE;
}

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

gboolean on_newstationwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(newstnwindow);
	return TRUE;
}

void on_newstnok_clicked(GtkButton *button, gpointer user_data)
{
	struct stndb_entry stnent;
	gfloat rxqrg, txqrg;
	gchar *text;
	GtkCList *clist;

	memset(&stnent, 0, sizeof(stnent));
	rxqrg = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "rxqrg")));
	txqrg = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "txqrg")));
	stnent.rx = rxqrg * 1000000;
	stnent.tx = txqrg * 1000000;
	stnent.rx = (stnent.rx + 50) / 100 * 100;
	stnent.tx = (stnent.tx + 50) / 100 * 100;
	text = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(newstnwindow), "stnname")));
	if (!text || !*text || !strcmp(text, "-")) {
		error_dialog("Invalid Name");
		return;
	}
	strncpy(stnent.name, text, sizeof(stnent.name));
	text = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(newstnwindow), "modeentry")));
	if (!text)
		stnent.mode = -1;
	else if (!strcmp(text, "fsk"))
		stnent.mode = trxapi_baycomusb_mode_fsk;
	else if (!strcmp(text, "afsk"))
		stnent.mode = trxapi_baycomusb_mode_afsk;
	else if (!strcmp(text, "external"))
		stnent.mode = trxapi_baycomusb_mode_external;
	else if (!strcmp(text, "audio"))
		stnent.mode = trxapi_baycomusb_mode_audio;
	else
		stnent.mode = -1;
	stnent.bitraterx = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "bitraterx")));
	stnent.bitratetx = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "bitratetx")));
	if (freql.del != -1) {
		clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "freqlist"));
		gtk_clist_get_text(clist, freql.del, 0, &text);
		stndb_delete(text);
	}
	freql.del = -1;
	if (stndb_write(&stnent)) {
		error_dialog("Cannot store station");
		return;
	}
	gtk_widget_hide(newstnwindow);
	setstns();
}

void on_newstncancel_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_hide(newstnwindow);
}

void on_newstnmodeentry_changed(GtkEditable *editable, gpointer user_data)
{
	gboolean sensitive = !strcmp(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(newstnwindow), "modeentry"))), "fsk");
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(newstnwindow), "bitraterx")), sensitive);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(newstnwindow), "bitratetx")), sensitive);
}

void on_freqlist_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(freqlistwindow);
}

gboolean on_freqlistwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(newstnwindow);
	gtk_widget_hide(freqlistwindow);
	return TRUE;
}

void on_freqlistset_clicked(GtkButton *button, gpointer user_data)
{
	gchar *text;
	GtkCList *clist;

	if (freql.sel == -1)
		return;
	clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "freqlist"));
	gtk_clist_get_text(clist, freql.sel, 0, &text);
	set_station(text);
	set_stnname(text);
}

void on_freqlistnew_clicked(GtkButton *button, gpointer user_data)
{
	freql.del = -1;
	gtk_widget_show(newstnwindow);
	gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(newstnwindow), "stnname")), "");
}

void on_freqlistupdate_clicked(GtkButton *button, gpointer user_data)
{
	struct stndb_entry stnent;
	gchar *text;
	GtkCList *clist;

	freql.del = freql.sel;
	gtk_widget_show(newstnwindow);
	if (freql.sel == -1)
		return;
	clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "freqlist"));
	gtk_clist_get_text(clist, freql.sel, 0, &text);
	memset(&stnent, 0, sizeof(stnent));
	stnent.mode = -1;
	strncpy(stnent.name, text, sizeof(stnent.name));
	if (stndb_retrieve(&stnent)) {
		printf("Cannot retrieve station \"%s\"\n", text);
		return;
	}
	gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(newstnwindow), "stnname")), stnent.name);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "rxqrg")), stnent.rx*1e-6);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "txqrg")), stnent.tx*1e-6);
	switch (stnent.mode) {
	case trxapi_baycomusb_mode_fsk:
		text = "fsk";
		break;

	case trxapi_baycomusb_mode_external:
		text = "external";
		break;

	case trxapi_baycomusb_mode_afsk:
		text = "afsk";
		break;

	case trxapi_baycomusb_mode_audio:
		text = "audio";
		break;

	default:
		text = "-";
		break;
	}
	gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(newstnwindow), "modeentry")), text);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "bitraterx")), stnent.bitraterx);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(newstnwindow), "bitratetx")), stnent.bitratetx);
}

void on_freqlistdelete_clicked(GtkButton *button, gpointer user_data)
{
	gchar *text;
	GtkCList *clist;

	if (freql.sel == -1)
		return;
	clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "freqlist"));
	gtk_clist_get_text(clist, freql.sel, 0, &text);
	stndb_delete(text);
	setstns();
	gtk_clist_select_row(clist, freql.sel, 0);
}

void on_freqlist_select_row(GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer user_data)
{
	printf("Select row: %d\n", row);
	freql.sel = row;
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttonset")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttonupdate")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttondelete")), TRUE);
}

void on_freqlist_unselect_row(GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer user_data)
{
	printf("Unselect row: %d\n", row);
	freql.sel = -1;
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttonset")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttonupdate")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttondelete")), FALSE);
}

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

void on_selectmodem_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	struct trxapi *api;
        const struct trxapi_description *desc;
	unsigned int i;
	GtkCList *clist;
	gchar *buf[3];

	clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(modemselectwindow), "modemlist"));
	gtk_clist_freeze(clist);
	gtk_clist_clear(clist);
	for (i = 0; ; i++) {
		if (!(api = trxapi_open_byindex(i)))
			break;
		if (!(desc = trxapi_get_description(api))) {
			trxapi_close(api);
			continue;
		}
		/* explicit conversion to discard const */
		buf[0] = (char *)desc->manufacturer;
		buf[1] = (char *)desc->model;
		buf[2] = (char *)desc->instid;
		gtk_clist_append(clist, buf);
		trxapi_close(api);
	}
	gtk_clist_thaw(clist);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(modemselectwindow), "modemselok")), FALSE);
	selectmodem_sel = -1;
	gtk_widget_show(modemselectwindow);
}

void on_modemlist_select_row(GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer user_data)
{
	selectmodem_sel = row;
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(modemselectwindow), "modemselok")), TRUE);
}

void on_modemlist_unselect_row(GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer user_data)
{
	selectmodem_sel = -1;
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(modemselectwindow), "modemselok")), FALSE);
}

void on_modemselok_clicked(GtkButton *button, gpointer user_data)
{
	GtkCList *clist;
	gchar *mfg, *model, *serial;

	if (selectmodem_sel != -1) {
		clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(modemselectwindow), "modemlist"));
		gtk_clist_get_text(clist, selectmodem_sel, 0, &mfg);
		gtk_clist_get_text(clist, selectmodem_sel, 1, &model);
		gtk_clist_get_text(clist, selectmodem_sel, 2, &serial);
		trxopenbymfgmodelserial(mfg, model, serial);
	}
	gtk_widget_hide(modemselectwindow);
}


void on_modemselcancel_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_hide(modemselectwindow);
}

gboolean on_modemselectwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(modemselectwindow);
	return TRUE;
}

static const char *filtmodestr[3] = {
        "0 - Default",
        "1 - Precomputed Filter",
        "2 - Ideal Lowpass Filter"
};

static const char *loopbackstr[3] = {
        "Off",
        "Scrambler",
        "Modem"
};

static const char *mdiscrxcstr[2] = {
	"Normal",
	"RxClock"
};

static const char *mdisctxcstr[2] = {
	"Normal",
	"TxClock"
};

static const char *mdisctxdstr[2] = {
	"Normal",
	"TxData"
};

void on_modemconfig_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	GtkNotebook *notebk;
	struct trxapi_baycomusb_adapter_config adaptcfg;
	struct trxapi_channel_access_config chacccfg;
	struct trxapi_interface_config ifcfg;
	struct trxapi_modem_disconnect_config mdisccfg;
	unsigned int i;
	char buf[16];
	char mbuf[8];

	notebk = GTK_NOTEBOOK(gtk_object_get_data(GTK_OBJECT(configwindow), "confignotebook"));
	notebook_pagemask = 0;
        gtk_widget_hide(gtk_notebook_get_nth_page(notebk, 0));
        gtk_widget_hide(gtk_notebook_get_nth_page(notebk, 1));
        gtk_widget_hide(gtk_notebook_get_nth_page(notebk, 2));
        gtk_widget_hide(gtk_notebook_get_nth_page(notebk, 3));
        gtk_widget_hide(gtk_notebook_get_nth_page(notebk, 4));
	if (!trx.trx) {
		gtk_widget_show(configwindow);
		return;
	}
	if (!trxapi_baycomusb_adapter_get_config(trx.trx, &adaptcfg)) {
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptmodeentry")),
				   (adaptcfg.mode == trxapi_baycomusb_mode_external) ? "external" :
				   (adaptcfg.mode == trxapi_baycomusb_mode_afsk) ? "afsk" :
				   (adaptcfg.mode == trxapi_baycomusb_mode_audio) ? "audio" : "fsk");
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptfclk")),
					  adaptcfg.fclk);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptbitraterx")),
					  adaptcfg.bitraterx);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptbitratetx")),
					  adaptcfg.bitratetx);
		if (adaptcfg.loopback > 2)
			adaptcfg.loopback = 2;
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptloopbackentry")),
				   loopbackstr[adaptcfg.loopback]);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptpttmute")),
					     adaptcfg.pttmute);
		if (adaptcfg.filtmode > 2)
			adaptcfg.filtmode = 2;
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptfiltmodeentry")),
				   filtmodestr[adaptcfg.filtmode]);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptsamplerate")),
					  adaptcfg.samplerate);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptgain")),
					  adaptcfg.gain);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiodevinentry")), adaptcfg.audiodevin);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiodevoutentry")), adaptcfg.audiodevout);
		//gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptrfsquelch"))),
		//			 adaptcfg.rfsquelch);
		gtk_range_set_adjustment(GTK_RANGE(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptrfsquelch")),
					 GTK_ADJUSTMENT(gtk_adjustment_new(adaptcfg.rfsquelch, trx.desc->rssimin, trx.desc->rssimax, 1, 1, 1)));
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiosquelch")),
					     adaptcfg.audiosquelch);
		notebook_pagemask |= (1 << 0) | (1 << 1);
		gtk_widget_show(gtk_notebook_get_nth_page(notebk, 0));
		gtk_widget_show(gtk_notebook_get_nth_page(notebk, 1));
	}
	if (!trxapi_channel_access_get_config(trx.trx, &chacccfg)) {
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chacctxdelay")),
					  chacccfg.txdelay);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chaccslottime")),
					  chacccfg.slottime);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chacctxtail")),
					  chacccfg.txtail);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chaccppersistence")),
					  chacccfg.ppersistence);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chaccfullduplex")),
					     chacccfg.fullduplex);
		notebook_pagemask |= 1 << 2;
		gtk_widget_show(gtk_notebook_get_nth_page(notebk, 2));
	}
	if (!trxapi_interface_get_config(trx.trx, &ifcfg)) {
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgifnameentry")), ifcfg.ifname);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfghwaddr")), ifcfg.hwaddr);
		snprintf(buf, sizeof(buf), "%u.%u.%u.%u", ifcfg.ipaddr[0], ifcfg.ipaddr[1], ifcfg.ipaddr[2], ifcfg.ipaddr[3]);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgipaddr")), buf);
		snprintf(buf, sizeof(buf), "%u.%u.%u.%u", ifcfg.netmask[0], ifcfg.netmask[1], ifcfg.netmask[2], ifcfg.netmask[3]);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgnetmask")), buf);
		snprintf(buf, sizeof(buf), "%u.%u.%u.%u", ifcfg.broadcast[0], ifcfg.broadcast[1], ifcfg.broadcast[2], ifcfg.broadcast[3]);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgbroadcast")), buf);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwhwaddr")), ifcfg.gwhwaddr);
		snprintf(buf, sizeof(buf), "%u.%u.%u.%u", ifcfg.gwipaddr[0], ifcfg.gwipaddr[1], ifcfg.gwipaddr[2], ifcfg.gwipaddr[3]);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwipaddr")), buf);
		snprintf(buf, sizeof(buf), "%u.%u.%u.%u", ifcfg.gwnetmask[0], ifcfg.gwnetmask[1], ifcfg.gwnetmask[2], ifcfg.gwnetmask[3]);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwnetmask")), buf);
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwipmodeentry")),
				   (ifcfg.gwipmode == 'V') ? _("Virtual Circuit") :
				   (ifcfg.gwipmode == 'D') ? _("Datagram") :
				   (ifcfg.gwipmode == 'C') ? _("Compressed") : _("Default"));
		notebook_pagemask |= 1 << 3;
		gtk_widget_show(gtk_notebook_get_nth_page(notebk, 3));
	}
	if (!trxapi_modem_disconnect_get_config(trx.trx, &mdisccfg)) {
		strncpy(mbuf, "mdisc0l", sizeof(mbuf));
		for (i = 0; i < 8; i++) {
			mbuf[5] = '0'+i;
			if (mdisccfg.direction & (1 << i))
				mbuf[6] = 't';
			else if (mdisccfg.output & (1 << i))
				mbuf[6] = 'h';
			else
				mbuf[6] = 'l';
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), mbuf)), TRUE);
		}
		if (mdisccfg.rxc > 1)
			mdisccfg.rxc = 1;
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "mdiscrxcentry")),
				   mdiscrxcstr[mdisccfg.rxc]);
		if (mdisccfg.txc > 1)
			mdisccfg.txc = 1;
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "mdisctxcentry")),
				   mdisctxcstr[mdisccfg.txc]);
		if (mdisccfg.txd > 1)
			mdisccfg.txd = 1;
		gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "mdisctxdentry")),
				   mdisctxdstr[mdisccfg.txd]);
 		notebook_pagemask |= 1 << 4;
		gtk_widget_show(gtk_notebook_get_nth_page(notebk, 4));
	}
	gtk_widget_show(configwindow);
}

static void parseip(trxapi_ip_address_t addr, const char *cp)
{
	unsigned int r1, r2, r3, r4;
	
	if (!cp || sscanf(cp, "%u.%u.%u.%u", &r1, &r2, &r3, &r4) != 4) {
		addr[0] = addr[1] = addr[2] = addr[3] = 0;
		return;
	}
	addr[0] = r1;
	addr[1] = r2;
	addr[2] = r3;
	addr[3] = r4;
}

void on_configwindowok_clicked(GtkButton *button, gpointer user_data)
{
	struct trxapi_baycomusb_adapter_config adaptcfg;
	struct trxapi_channel_access_config chacccfg;
	struct trxapi_interface_config ifcfg;
	struct trxapi_modem_disconnect_config mdisccfg;
	char *cp;
	unsigned int dir, out, i, j;
	char mbuf[8];

	if (notebook_pagemask & ((1 << 0)|(1 << 1))) {
		cp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptmodeentry")));
		if (!strcmp(cp, "fsk")) {
			adaptcfg.mode = trxapi_baycomusb_mode_fsk;
		} else if (!strcmp(cp, "external")) {
			adaptcfg.mode = trxapi_baycomusb_mode_external;
		} else if (!strcmp(cp, "afsk")) {
			adaptcfg.mode = trxapi_baycomusb_mode_afsk;
		} else if (!strcmp(cp, "audio")) {
			adaptcfg.mode = trxapi_baycomusb_mode_audio;
		} else
			adaptcfg.mode = trxapi_baycomusb_mode_fsk;
		adaptcfg.fclk = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptfclk")));
		adaptcfg.bitraterx = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptbitraterx")));
		adaptcfg.bitratetx = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptbitratetx")));
		cp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptloopbackentry")));
		for (i = j = 0; i < 3; i++)
			if (!strcmp(cp, loopbackstr[i]))
				j = i;
		adaptcfg.loopback = j;
		adaptcfg.pttmute = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptpttmute")));
		cp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptfiltmodeentry")));
		for (i = j = 0; i < 3; i++)
			if (!strcmp(cp, filtmodestr[i]))
				j = i;
		adaptcfg.filtmode = j;
		adaptcfg.samplerate = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptsamplerate")));
		adaptcfg.gain = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptgain")));
		strncpy(adaptcfg.audiodevin, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiodevinentry"))), sizeof(adaptcfg.audiodevin));
		strncpy(adaptcfg.audiodevout, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiodevoutentry"))), sizeof(adaptcfg.audiodevout));
		adaptcfg.rfsquelch = gtk_range_get_adjustment(GTK_RANGE(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptrfsquelch")))->value;
		adaptcfg.audiosquelch = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptaudiosquelch")));
		if (trx.trx != NULL) {
			if (adaptcfg.rfsquelch < trx.desc->rssimin)
				adaptcfg.rfsquelch = trx.desc->rssimin;
			if (adaptcfg.rfsquelch > trx.desc->rssimax)
				adaptcfg.rfsquelch = trx.desc->rssimax;
		}
		if (trxapi_baycomusb_adapter_set_config(trx.trx, &adaptcfg))
			lprintf(1, "Error setting adapter config\n");
	}
	if (notebook_pagemask & (1 << 2)) {
		chacccfg.txdelay = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chacctxdelay")));
		chacccfg.slottime = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chaccslottime")));
		chacccfg.txtail = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chacctxtail")));
		chacccfg.ppersistence = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chaccppersistence")));
		chacccfg.fullduplex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), "chaccfullduplex")));
		if (trxapi_channel_access_set_config(trx.trx, &chacccfg))
			lprintf(1, "Error setting channel access parameters\n");
	}
	if (notebook_pagemask & (1 << 3)) {
		strncpy(ifcfg.ifname, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgifnameentry"))), sizeof(ifcfg.ifname));
		strncpy(ifcfg.hwaddr, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfghwaddr"))), sizeof(ifcfg.hwaddr));
		parseip(ifcfg.ipaddr, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgipaddr"))));
		parseip(ifcfg.netmask, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgnetmask"))));
		parseip(ifcfg.broadcast, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfgbroadcast"))));
		strncpy(ifcfg.gwhwaddr, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwhwaddr"))), sizeof(ifcfg.gwhwaddr));
		parseip(ifcfg.gwipaddr, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwipaddr"))));
		parseip(ifcfg.gwnetmask, gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwnetmask"))));
		cp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "ifcfggwipmodeentry")));
		if (!strcmp(cp, _("Virtual Circuit")))
			ifcfg.gwipmode = 'V';
		else if (!strcmp(cp, _("Datagram")))
			ifcfg.gwipmode = 'D';
		else if (!strcmp(cp, _("Compressed")))
			ifcfg.gwipmode = 'C';
		else 
			ifcfg.gwipmode = ' ';
		if (trxapi_interface_set_config(trx.trx, &ifcfg))
			lprintf(1, "Error setting interface parameters\n");
	}
	if (notebook_pagemask & (1 << 4)) {
		strncpy(mbuf, "mdisc0l", sizeof(mbuf));
		for (dir = out = i = 0; i < 8; i++) {
			mbuf[5] = '0'+i;
			mbuf[6] = 't';
			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), mbuf))))
				dir |= (1 << i);
			mbuf[6] = 'h';
			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(configwindow), mbuf))))
				out |= (1 << i);
		}
		mdisccfg.output = out;
		mdisccfg.direction = dir;
		cp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "mdiscrxcentry")));
		for (i = j = 0; i < 2; i++)
			if (!strcmp(cp, mdiscrxcstr[i]))
				j = i;
		mdisccfg.rxc = j;
		cp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "mdisctxcentry")));
		for (i = j = 0; i < 2; i++)
			if (!strcmp(cp, mdisctxcstr[i]))
				j = i;
		mdisccfg.txc = j;
		cp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(configwindow), "mdisctxdentry")));
		for (i = j = 0; i < 2; i++)
			if (!strcmp(cp, mdisctxdstr[i]))
				j = i;
		mdisccfg.txd = j;
		if (trxapi_modem_disconnect_set_config(trx.trx, &mdisccfg))
			lprintf(1, "Error setting modem disconnect parameters\n");
	}
	gtk_widget_hide(configwindow);
}

void on_configwindowcancel_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_hide(configwindow);
}

gboolean on_configwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(configwindow);
	return TRUE;
}

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

static gint periodic(gpointer user_data)
{
	struct trxapi_state status;
	struct trxapi_audio_state audiostate;
	unsigned char audiosamples[1024];
	gint16 audiosamp[1024];
	char buf[256];
	unsigned int i;
	int rssi;
        GtkText *txt;
	unsigned char *cp1, *cp2;
	GtkToggleButton *manualptt;
	struct stndb_entry stnent;

	if (trx.trx == NULL) {
		/* should do reopen */
		return TRUE;
	}
	if (trxapi_get_state(trx.trx, &status)) {
		lprintf(1, "Error getting status\n");
		closetrx();
		/* should initialise reopening */
		return TRUE;
	}
	trxnewmode(status.mode);
	/* update PTT & DCD leds */
	i = (status.ptt ? 1 : 0) | (status.dcd ? 2 : 0);
	if ((ledstatus ^ i) & 2)
		setled(GTK_PIXMAP(gtk_object_get_data(GTK_OBJECT(mainwindow), "leddcd")), i & 2);
	if ((ledstatus ^ i) & 1)
		setled(GTK_PIXMAP(gtk_object_get_data(GTK_OBJECT(mainwindow), "ledptt")), i & 1);
	ledstatus = i;
	/* update RSSI */
	gtk_progress_set_value(GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(mainwindow), "rssi")), status.rssi);
	/* add RSSI to running display */
	rssi = (status.rssi - trx.desc->rssimin) * trx.rssimul;
	if (rssi < 0)
		rssi = 0;
	if (rssi > 255)
		rssi = 255;
	signalhistory_newdata(SIGNALHISTORY(gtk_object_get_data(GTK_OBJECT(mainwindow), "rssihistory")),
			      status.ptt ? 250 : rssi, status.ptt ? 2 : (status.dcd ? 1 : 0));
	/* check changes in rx/tx frequency */
	if (!freq.fchginhibit && (status.rxfreq != freq.rx || status.txfreq != freq.tx)) {
		memset(&stnent, 0, sizeof(stnent));
		stnent.rx = freq.rx = status.rxfreq;
		stnent.tx = freq.tx = status.txfreq;
		stnent.mode = -1;
		set_frequencies(freq.rx, freq.tx);
		if (trx.trx != NULL) {
		  	struct trxapi_baycomusb_adapter_config adaptcfg;

			if (!trxapi_baycomusb_adapter_get_config(trx.trx, &adaptcfg)) {
		  		stnent.mode = adaptcfg.mode;
		    		stnent.bitraterx = adaptcfg.bitraterx;
		    		stnent.bitratetx = adaptcfg.bitratetx;
		  	}
		}
		if (stndb_retrieve(&stnent) || !stnent.name[0])
			strncpy(stnent.name, "-", sizeof(stnent.name));
		set_stnname(stnent.name);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "rxqrg")), freq.rx != 0);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "txqrg")), freq.tx != 0);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "stnname")), freq.rx != 0 || freq.tx != 0);
	}
	/* check manual PTT */
	manualptt = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "buttonptt"));
	if ((!gtk_toggle_button_get_active(manualptt)) != (!status.manualptt)) {
		gtk_signal_disconnect_by_func(GTK_OBJECT(manualptt), GTK_SIGNAL_FUNC(on_buttonptt_toggled), NULL);
		gtk_toggle_button_set_active(manualptt, status.manualptt);
		gtk_signal_connect(GTK_OBJECT(manualptt), "toggled", GTK_SIGNAL_FUNC(on_buttonptt_toggled), NULL);
	}
	/* check if UART received chars */
	if (!trxapi_uart_receive(trx.trx, &rxuartptr, buf, sizeof(buf))) {
		/* process input for widget */
                for (cp1 = cp2 = buf; *cp2; cp2++) {
                        if (*cp2 == '\r') {
                                *cp1++ = '\n';
				uartline.rxline[uartline.lptr] = 0;
				processuart(uartline.rxline);
				uartline.lptr = 0;
                        } else if (*cp2 != '\n') {
                                *cp1++ = *cp2;
				if (*cp2 >= 32 && *cp2 <= 127 && uartline.lptr < sizeof(uartline.rxline)-1)
					uartline.rxline[uartline.lptr++] = *cp2;
			}
                }
		if (buf != (char *)cp1) {
			txt = GTK_TEXT(gtk_object_get_data(GTK_OBJECT(terminalwindow), "text"));
			gtk_text_insert(txt, NULL, NULL, NULL, buf, cp1-(unsigned char *)buf);
		}
	}
	/* scope/spectrum windows */
	if (trx.mode == trxapi_mode_audio) {
		if (trxapi_get_audio_state(trx.trx, &audiostate)) {
			lprintf(1, "trxapi_get_audio_state error\n");
		} else {
			/* update audio levels */
			gtk_progress_set_value(GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(audiopwrwindow), "audiomicsig")), audiostate.micsigpwr);
			gtk_progress_set_value(GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(audiopwrwindow), "audiospksig")), audiostate.spksigpwr);
			gtk_progress_set_value(GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(audiopwrwindow), "audiospknoise")), audiostate.spknoisepwr);
			/* send samples to scope and spectrum */
			if (GTK_WIDGET_DRAWABLE(micscopewindow) || GTK_WIDGET_DRAWABLE(micspectrumwindow)) {
				if (trxapi_get_audio_mic_samples(trx.trx, (audiostate.micbufptr + audiostate.micbufsz - 1024) % audiostate.micbufsz, 1024, audiosamples)) {
					lprintf(1, "trxapi_get_audio_mic_samples error\n");
				} else {
					for (i = 0; i < 1024; i++)
						audiosamp[i] = audiosamples[i] << 8;
					if (GTK_WIDGET_DRAWABLE(micscopewindow))
						scope_addvalues(SCOPE(gtk_object_get_data(GTK_OBJECT(micscopewindow), "scope")), 1024, NULL, audiosamp);
					if (GTK_WIDGET_DRAWABLE(micspectrumwindow))
						spectrum_addvalues(SPECTRUM(gtk_object_get_data(GTK_OBJECT(micspectrumwindow), "spec")), 1024, audiosamp);
				}
			}
			if (GTK_WIDGET_DRAWABLE(spkscopewindow) || GTK_WIDGET_DRAWABLE(spkspectrumwindow)) {
				if (trxapi_get_audio_spk_samples(trx.trx, (audiostate.spkbufptr + audiostate.spkbufsz - 1024) % audiostate.spkbufsz, 1024, audiosamples)) {
					lprintf(1, "trxapi_get_audio_spk_samples error\n");
				} else {
					for (i = 0; i < 1024; i++)
						audiosamp[i] = audiosamples[i] << 8;
					if (GTK_WIDGET_DRAWABLE(spkscopewindow))
						scope_addvalues(SCOPE(gtk_object_get_data(GTK_OBJECT(spkscopewindow), "scope")), 1024, NULL, audiosamp);
					if (GTK_WIDGET_DRAWABLE(spkspectrumwindow))
						spectrum_addvalues(SPECTRUM(gtk_object_get_data(GTK_OBJECT(spkspectrumwindow), "spec")), 1024, audiosamp);
				}
			}
		}
	}
	return TRUE;
}

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

void on_dtmfclear_clicked(GtkButton *button, gpointer user_data)
{
        GtkEntry *entry;
        
        entry = GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(dtmfwindow), "dtmfentry"));
        gtk_entry_set_text(entry, "");
}

static gint dtmfkeyfunc(gpointer data)
{
        return on_dtmfwindow_key_event(NULL, NULL, data);
}

gboolean on_dtmfwindow_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
        static const char dtmfkeys[] = "0123456789ABCD*#";
        static guint tmo = 0;
        static guint lastkey = -1;
        static guint currentkey = 0;
        GtkButton *but;
        gchar bname[6] = "dtmf0";
        char *cp, c;

        if (!event) {
                tmo = 0;
                lastkey = currentkey;
                bname[4] += lastkey & 15;
                if ((lastkey & 15) >= 10)
                        bname[4] += 'a'-'0'-10;
                but = GTK_BUTTON(gtk_object_get_data(GTK_OBJECT(dtmfwindow), bname));
                if (lastkey & 16)
                        gtk_button_pressed(but);
                else
                        gtk_button_released(but);
                return FALSE;  /* don't get called again */
        }
        c = event->keyval;
        if (c >= 'a' && c <= 'z')
                c += 'A'-'a';
        if (!(cp = strchr(dtmfkeys, c)))
                return FALSE;
        currentkey = cp - dtmfkeys + (event->type == GDK_KEY_PRESS ? 16 : 0);
        if (tmo)
                gtk_timeout_remove(tmo);
        if (currentkey != lastkey)
                tmo = gtk_timeout_add(10, dtmfkeyfunc, NULL);
        return TRUE;
}

void on_dtmf_key(GtkButton *button, gpointer user_data)
{
        static const char dtmfkeys[] = "0123456789ABCD*#";
        GtkEntry *entry;
        gchar txt[2];
        guint key = (guint)user_data;
	
        printf("DTMF key: %u\n", key);
	if (trx.trx == NULL)
		return;
        if (key & 16)
                pttmask |= PTTMASK_DTMF;
        else 
                pttmask &= ~PTTMASK_DTMF;
	updatepttmask();
	if (trx.mode == trxapi_mode_audio) {
		if (trxapi_set_audio_dtmf(trx.trx, (key & 16) ? (key & 15) : -1))
			lprintf(1, "trxapi_set_audio_dtmf error\n");
	}
        if (key < 0x10 || key > 0x1f)
                return;
        txt[0] = dtmfkeys[key & 0xf];
        txt[1] = 0;
        entry = GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(dtmfwindow), "dtmfentry"));
        gtk_entry_append_text(entry, txt);
}

gboolean on_dtmfwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
        gtk_widget_hide(dtmfwindow);
        return TRUE;
}

void on_audiopwrs_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(audiopwrwindow);
}

void on_audiodtmf_activate(GtkMenuItem *menuitem, gpointer user_data)
{
        gtk_widget_show(dtmfwindow);
}


void on_audioparams_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(paramwindow);
}

void on_spkscope_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(spkscopewindow);
}


void on_spkspectrum_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(spkspectrumwindow);
}

void on_micscope_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(micscopewindow);
}


void on_micspectrum_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(micspectrumwindow);
}

void on_paramwindowok_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_hide(paramwindow);
	params.enaptt = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(paramwindow), "paramenablepttpkt")));
	paramstodialog();
}

void on_paramwindowcancel_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_hide(paramwindow);
	paramstodialog();
}

gboolean on_paramwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(paramwindow);
	return TRUE;
}

gboolean on_spkscopewindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
        gtk_widget_hide(spkscopewindow);
        return TRUE;
}

gboolean on_spkspectrumwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
        gtk_widget_hide(spkspectrumwindow);
        return TRUE;
}

gboolean on_micscopewindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
        gtk_widget_hide(micscopewindow);
        return TRUE;
}

gboolean on_micspectrumwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
        gtk_widget_hide(micspectrumwindow);
        return TRUE;
}

gboolean on_audiopwrwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(audiopwrwindow);
        return TRUE;
}

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

static void init_popdown(void)
{
	static const char *modestr[] = { "fsk", "afsk", "external", "audio" };
	GList *items;
	GtkCombo *combo;
	unsigned int i;

	combo = GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptfiltmode"));
	items = NULL;
	for (i = 0; i < sizeof(filtmodestr)/sizeof(filtmodestr[0]); i++)
		items = g_list_append(items, (gpointer)filtmodestr[i]);
	gtk_combo_set_popdown_strings(combo, items);
	gtk_entry_set_text(GTK_ENTRY(combo->entry), items->data);
	g_list_free(items);
	combo = GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptloopback"));
	items = NULL;
	for (i = 0; i < sizeof(loopbackstr)/sizeof(loopbackstr[0]); i++)
		items = g_list_append(items, (gpointer)loopbackstr[i]);
	gtk_combo_set_popdown_strings(combo, items);
	gtk_entry_set_text(GTK_ENTRY(combo->entry), items->data);
	g_list_free(items);
	combo = GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "adaptmode"));
	items = NULL;
	for (i = 0; i < sizeof(modestr)/sizeof(modestr[0]); i++)
		items = g_list_append(items, (gpointer)modestr[i]);
	gtk_combo_set_popdown_strings(combo, items);
	gtk_entry_set_text(GTK_ENTRY(combo->entry), items->data);
	g_list_free(items);
	combo = GTK_COMBO(gtk_object_get_data(GTK_OBJECT(newstnwindow), "mode"));
	items = g_list_append(NULL, "-");
	for (i = 0; i < sizeof(modestr)/sizeof(modestr[0]); i++)
		items = g_list_append(items, (gpointer)modestr[i]);
	gtk_combo_set_popdown_strings(combo, items);
	gtk_entry_set_text(GTK_ENTRY(combo->entry), items->data);
	g_list_free(items);
	combo = GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "mdiscrxc"));
	items = NULL;
	for (i = 0; i < sizeof(mdiscrxcstr)/sizeof(mdiscrxcstr[0]); i++)
		items = g_list_append(items, (gpointer)mdiscrxcstr[i]);
	gtk_combo_set_popdown_strings(combo, items);
	gtk_entry_set_text(GTK_ENTRY(combo->entry), items->data);
	g_list_free(items);
	combo = GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "mdisctxc"));
	items = NULL;
	for (i = 0; i < sizeof(mdisctxcstr)/sizeof(mdisctxcstr[0]); i++)
		items = g_list_append(items, (gpointer)mdisctxcstr[i]);
	gtk_combo_set_popdown_strings(combo, items);
	gtk_entry_set_text(GTK_ENTRY(combo->entry), items->data);
	g_list_free(items);
	combo = GTK_COMBO(gtk_object_get_data(GTK_OBJECT(configwindow), "mdisctxd"));
	items = NULL;
	for (i = 0; i < sizeof(mdisctxdstr)/sizeof(mdisctxdstr[0]); i++)
		items = g_list_append(items, (gpointer)mdisctxdstr[i]);
	gtk_combo_set_popdown_strings(combo, items);
	gtk_entry_set_text(GTK_ENTRY(combo->entry), items->data);
	g_list_free(items);
}

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

int main(int argc, char *argv[])
{
	static const struct option long_options[] = {
		{ "--expert", 0, 0, 'e' },
                { 0, 0, 0, 0 }
        };
        int c, err = 0;
	unsigned int expert = 0;
	guint tmid;
 
	printf("Baycom USB Transceiver Controller v" VERSION "\n");
#ifdef ENABLE_NLS
	bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
	textdomain(PACKAGE);
#endif

	verboselevel = ~0;
	syslogmsg = 1;

	if (trxapi_init(&argc, argv))
		exit(1);

	gtk_set_locale();
	gtk_init(&argc, &argv);

	add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps");
	add_pixmap_directory(PACKAGE_SOURCE_DIR "/pixmaps");

        while ((c = getopt_long(argc, argv, "e", long_options, NULL)) != EOF) {
                switch (c) {
		case 'e':
			expert = 1;
			break;

                default:
                        err++;
                        break;
                }
        }
        if (err) {
                fprintf(stderr, "usage: %s [--expert]\n", argv[0]);
		exit(1);
	}
	stndb_open();
	/*
	 * The following code was added by Glade to create one of each component
	 * (except popup menus), just so that you see something after building
	 * the project. Delete any components that you don't want shown initially.
	 */
	mainwindow = create_mainwindow();
	gtk_progress_configure(GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(mainwindow), "rssi")), -120, -120, -35);
	terminalwindow = create_terminalwindow();
	chmemorywindow = create_chmemorywindow();
	chprogwindow = create_chprogwindow();
	freqlistwindow = create_freqlistwindow();
	newstnwindow = create_newstationwindow();
	modemselectwindow = create_modemselectwindow();
	configwindow = create_configwindow();
        dtmfwindow = create_dtmfwindow();
        spkscopewindow = create_spkscopewindow();
        spkspectrumwindow = create_spkspectrumwindow();
	micscopewindow = create_micscopewindow();
        micspectrumwindow = create_micspectrumwindow();
	paramwindow = create_paramwindow();
	audiopwrwindow = create_audiopwrwindow();
	init_popdown();
	updatechmemwindow();
	setstns();
	paramstodialog();
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttonset")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttonupdate")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(freqlistwindow), "buttondelete")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(modemselectwindow), "modemselok")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "rxqrg")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "txqrg")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "stnname")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "modemconfig")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "audio")), FALSE);
	if (!expert)
		gtk_widget_hide(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "expert")));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "buttonptt")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(mainwindow), "button1750")), FALSE);
	trx.mode = trxapi_mode_unspec;
	gtk_widget_show(mainwindow);
	trxopenbyindex(0);
        tmid = gtk_timeout_add(250, periodic, NULL);
	gtk_main();
	gtk_timeout_remove(tmid);
	stndb_close();
	if (trx.trx)
		trxapi_close(trx.trx);
	return 0;
}
