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

/*
 *      cfgwin32.c  --  Windows (registry) configuration IO.
 *
 *      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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#include "trx.h"

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

#define REGHKEY      HKEY_LOCAL_MACHINE

static char configfile[256] = "SOFTWARE\\FlexNet\\BaycomUSB";

#define FALSE 0
#define TRUE 1

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

int config_load(const char *name)
{
	if (name)
		strncpy(configfile, name, sizeof(configfile));
	return 0;
}

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

int config_save(void)
{
	return 0;
}

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

static unsigned long long strtoull(const char *nptr, char **endptr, int base)
{
	unsigned long long v = 0;

	while (nptr && *nptr >= '0' && *nptr <= '9')
		v = (v * 10) + *nptr++ - '0';
	if (endptr)
		*endptr = nptr;
	return v;
}

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

static HKEY getsectionnode(const char *serial, const char *secname)
{
	HKEY hkey;
	char name[256];
	DWORD disp;

	snprintf(name, sizeof(name), "%s\\%s\\%s", configfile, serial, secname);
	if (RegCreateKeyEx(REGHKEY, name, 0, "", 0, KEY_ALL_ACCESS, NULL, &hkey, &disp) != ERROR_SUCCESS)
		return NULL;
	return hkey;
}

static int getprop(HKEY key, const char *name, char *buf, unsigned int sz)
{
	DWORD t, s;

	s = sz-1;
	if (RegQueryValueEx(key, name, NULL, &t, buf, &s) != ERROR_SUCCESS) {
		buf[0] = 0;
		return 0;
	}
	if (t != REG_SZ) {
		buf[0] = 0;
		return 0;
	}
	buf[s] = 0;
	return 1;
}

static void setprop(HKEY key, const char *name, const char *val)
{
	DWORD err;

	err = RegSetValueEx(key, name, 0, REG_SZ, val, strlen(val)+1);
	if (err != ERROR_SUCCESS)
		lprintf(2, "RegSetValueEx(%s,%s) error %lu\n", name, val, err);
}

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

void config_loaddevice(struct trx_thread_state *state)
{
	HKEY hkey;
	char buf[128];

	/* set default */
	state->cfg.adapt.mode = trxapi_baycomusb_mode_fsk;
	state->cfg.adapt.fclk = 19666600;
	state->cfg.adapt.bitraterx = state->cfg.adapt.bitratetx = 9600;
	state->cfg.adapt.loopback = trxapi_baycomusb_loopback_off;
	state->cfg.adapt.pttmute = TRUE;
	state->cfg.adapt.filtmode = 0;
	state->cfg.adapt.samplerate = 8000;
	state->cfg.adapt.gain = 1;
	state->cfg.adapt.audiodevin[0] = state->cfg.adapt.audiodevout[0] = 0;
	state->cfg.adapt.rfsquelch = RSSI_MIN;
	state->cfg.adapt.audiosquelch = FALSE;
	state->cfg.chacc.txdelay = 100;
	state->cfg.chacc.fulldup = 0;
	state->cfg.mdisc.output = 0;
	state->cfg.mdisc.direction = 0xff;
	state->cfg.mdisc.rxc = trxapi_modem_disconnect_rxc_normal;
	state->cfg.mdisc.txc = trxapi_modem_disconnect_txc_normal;
	state->cfg.mdisc.txd = trxapi_modem_disconnect_txd_normal;
	if ((hkey = getsectionnode(state->serial, "adapter"))) {
		if (getprop(hkey, "mode", buf, sizeof(buf))) {
			if (!strcmp(buf, "fsk")) {
				state->cfg.adapt.mode = trxapi_baycomusb_mode_fsk;
			} else if (!strcmp(buf, "external")) {
				state->cfg.adapt.mode = trxapi_baycomusb_mode_external;
			} else if (!strcmp(buf, "afsk")) {
				state->cfg.adapt.mode = trxapi_baycomusb_mode_afsk;
			} else if (!strcmp(buf, "audio")) {
				state->cfg.adapt.mode = trxapi_baycomusb_mode_audio;
			}
		}
		if (getprop(hkey, "fclk", buf, sizeof(buf)))
			state->cfg.adapt.fclk = strtoul(buf, NULL, 0);
		if (getprop(hkey, "bitrate", buf, sizeof(buf)))
			state->cfg.adapt.bitraterx = state->cfg.adapt.bitratetx = strtoul(buf, NULL, 0);
		if (getprop(hkey, "bitraterx", buf, sizeof(buf)))
			state->cfg.adapt.bitraterx = strtoul(buf, NULL, 0);
		if (getprop(hkey, "bitratetx", buf, sizeof(buf)))
			state->cfg.adapt.bitratetx = strtoul(buf, NULL, 0);
		if (getprop(hkey, "loopback", buf, sizeof(buf)))
			state->cfg.adapt.loopback = strtoul(buf, NULL, 0);
		if (getprop(hkey, "pttmute", buf, sizeof(buf)))
			state->cfg.adapt.pttmute = (buf[0] == '0' || buf[0] == 'n' || buf[0] == 'N') ? FALSE : TRUE;
		if (getprop(hkey, "filtmode", buf, sizeof(buf)))
			state->cfg.adapt.filtmode = strtoul(buf, NULL, 0);
		if (getprop(hkey, "samplerate", buf, sizeof(buf)))
			state->cfg.adapt.samplerate = strtoul(buf, NULL, 0);
		if (getprop(hkey, "gain", buf, sizeof(buf)))
			state->cfg.adapt.gain = strtod(buf, NULL);
		if (getprop(hkey, "audiodevin", buf, sizeof(buf)))
			strncpy(state->cfg.adapt.audiodevin, buf, sizeof(state->cfg.adapt.audiodevin));
		if (getprop(hkey, "audiodevout", buf, sizeof(buf)))
			strncpy(state->cfg.adapt.audiodevout, buf, sizeof(state->cfg.adapt.audiodevout));
		if (getprop(hkey, "rfsquelch", buf, sizeof(buf)))
			state->cfg.adapt.rfsquelch = strtod(buf, NULL);
		if (getprop(hkey, "audiosquelch", buf, sizeof(buf)))
			state->cfg.adapt.audiosquelch = (buf[0] == '0' || buf[0] == 'n' || buf[0] == 'N') ? FALSE : TRUE;
	}
	if ((hkey = getsectionnode(state->serial, "chacc"))) {
		if (getprop(hkey, "txdelay", buf, sizeof(buf)))
			state->cfg.chacc.txdelay = strtoul(buf, NULL, 0);
		if (getprop(hkey, "fulldup", buf, sizeof(buf)))
			state->cfg.chacc.fulldup = strtoul(buf, NULL, 0);
	}
	if ((hkey = getsectionnode(state->serial, "modemdisc"))) {
		if (getprop(hkey, "output", buf, sizeof(buf)))
			state->cfg.mdisc.output = strtoul(buf, NULL, 0);
		if (getprop(hkey, "direction", buf, sizeof(buf)))
			state->cfg.mdisc.direction = strtoul(buf, NULL, 0);
		if (getprop(hkey, "rxc", buf, sizeof(buf)))
			state->cfg.mdisc.rxc = strtoul(buf, NULL, 0);
		if (getprop(hkey, "txc", buf, sizeof(buf)))
			state->cfg.mdisc.txc = strtoul(buf, NULL, 0);
		if (getprop(hkey, "txd", buf, sizeof(buf)))
			state->cfg.mdisc.txd = strtoul(buf, NULL, 0);
	}
	if ((hkey = getsectionnode(state->serial, "frequency"))) {
		if (getprop(hkey, "rx", buf, sizeof(buf)))
			state->cfg.freq.rx = strtoull(buf, NULL, 0);
		if (getprop(hkey, "tx", buf, sizeof(buf)))
			state->cfg.freq.tx = strtoull(buf, NULL, 0);
	}
}

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

void config_savedevice(struct trx_thread_state *state)
{
	HKEY hkey;
	char buf[128];

        if (!state->serial[0])
                return;
	if ((hkey = getsectionnode(state->serial, "adapter"))) {
		setprop(hkey, "mode", 
			(state->cfg.adapt.mode == trxapi_baycomusb_mode_external) ? "external" :
			(state->cfg.adapt.mode == trxapi_baycomusb_mode_afsk) ? "afsk" :
			(state->cfg.adapt.mode == trxapi_baycomusb_mode_audio) ? "audio" : "fsk");
		snprintf(buf, sizeof(buf), "%ld", state->cfg.adapt.fclk);
		setprop(hkey, "fclk", buf);
		snprintf(buf, sizeof(buf), "%ld", state->cfg.adapt.bitraterx);
		setprop(hkey, "bitraterx", buf);
		snprintf(buf, sizeof(buf), "%ld", state->cfg.adapt.bitratetx);
		setprop(hkey, "bitratetx", buf);
		snprintf(buf, sizeof(buf), "%d", state->cfg.adapt.loopback);
		setprop(hkey, "loopback", buf);
		snprintf(buf, sizeof(buf), "%d", !!state->cfg.adapt.pttmute);
		setprop(hkey, "pttmute", buf);
		snprintf(buf, sizeof(buf), "%ld", state->cfg.adapt.filtmode);
		setprop(hkey, "filtmode", buf);
		snprintf(buf, sizeof(buf), "%ld", state->cfg.adapt.samplerate);
		setprop(hkey, "samplerate", buf);
		snprintf(buf, sizeof(buf), "%f", state->cfg.adapt.gain);
		setprop(hkey, "gain", buf);
		setprop(hkey, "audiodevin", state->cfg.adapt.audiodevin);
		setprop(hkey, "audiodevout", state->cfg.adapt.audiodevout);
		snprintf(buf, sizeof(buf), "%f", state->cfg.adapt.rfsquelch);
		setprop(hkey, "rfsquelch", buf);
		snprintf(buf, sizeof(buf), "%d", !!state->cfg.adapt.audiosquelch);
		setprop(hkey, "audiosquelch", buf);		
	} else
		lprintf(1, "Config %s node adapter out of memory\n", state->serial);
	if ((hkey = getsectionnode(state->serial, "chacc"))) {
		snprintf(buf, sizeof(buf), "%lu", state->cfg.chacc.txdelay);
		setprop(hkey, "txdelay", buf);
		snprintf(buf, sizeof(buf), "%u", state->cfg.chacc.fulldup);
		setprop(hkey, "fulldup", buf);
	} else
		lprintf(1, "Config %s node channel access out of memory\n", state->serial);	
	if ((hkey = getsectionnode(state->serial, "modemdisc"))) {
		snprintf(buf, sizeof(buf), "0x%02lx", state->cfg.mdisc.output & 0xff);
		setprop(hkey, "output", buf);
		snprintf(buf, sizeof(buf), "0x%02lx", state->cfg.mdisc.direction & 0xff);
		setprop(hkey, "direction", buf);
		snprintf(buf, sizeof(buf), "%u", state->cfg.mdisc.rxc);
		setprop(hkey, "rxc", buf);
		snprintf(buf, sizeof(buf), "%u", state->cfg.mdisc.txc);
		setprop(hkey, "txc", buf);
		snprintf(buf, sizeof(buf), "%u", state->cfg.mdisc.txd);
		setprop(hkey, "txd", buf);
	} else
		lprintf(1, "Config %s node modemdisc out of memory\n", state->serial);	
	if ((hkey = getsectionnode(state->serial, "frequency"))) {
		snprintf(buf, sizeof(buf), "%llu", state->cfg.freq.rx);
		setprop(hkey, "rx", buf);
		snprintf(buf, sizeof(buf), "%llu", state->cfg.freq.tx);
		setprop(hkey, "tx", buf);
	} else
		lprintf(1, "Config %s node frequency out of memory\n", state->serial);
}

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