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

/*
 *      client.c  --  Transceiver control client (UNIX only).
 *
 *      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.
 *
 *  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.
 *
 *  History:
 *   0.1  19.09.2000  Created
 *
 */

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

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

#include "trxapi.h"

#include <sys/types.h>
#include <stdio.h>

#if defined(WIN32)
#include <windows.h>
#else
#include <dirent.h>
#endif

#include "trxctrl.h"
#include "trx.h"

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

struct trxapi {
	struct trxapi_description *desc;
	struct trxapi_baycomusb_adapter_audio_devs *audiodevs;
	Trx_Control obj;
};

#define VERBOSE

#ifdef VERBOSE
#define verbose(x) x
#else
#define verbose(x)
#endif

static CORBA_ORB trx_orb;

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

static int printexception(const char *routine, CORBA_Environment *ev)
{
	if (!ev || ev->_major == CORBA_NO_EXCEPTION)
		return 0;
	if (ev->_major == CORBA_USER_EXCEPTION && !strcmp(CORBA_exception_id(ev), ex_Trx_TrxError)) {
                lprintf(10, "CORBA exception in %s: %s (%s)\n", routine, CORBA_exception_id(ev), ((Trx_TrxError *)CORBA_exception_value(ev))->reason);
		CORBA_exception_free(ev);
                return -1;
        }
        lprintf(10, "CORBA exception in %s: %s\n", routine, CORBA_exception_id(ev));
	CORBA_exception_free(ev);
	return -1;
}

static inline Trx_Control ior_to_obj(const char *ior)
{
	CORBA_Environment ev;
	Trx_Control obj;
	Trx_TrxDescription *desc;

	CORBA_exception_init(&ev);
	obj = CORBA_ORB_string_to_object(trx_orb, (char *)ior, &ev);
	if (ev._major != CORBA_NO_EXCEPTION) {
		verbose(lprintf(0, "Error: trx_resolve_byindex: %s %s\n", ior, CORBA_exception_id(&ev)));
		CORBA_exception_free(&ev);
		return NULL;
	}
	Trx_Control_GetDescription(obj, &desc, &ev);
	if (ev._major != CORBA_NO_EXCEPTION) {
		verbose(lprintf(0, "Error: trx_resolve_byindex: (GetDescription) %s %s\n", ior, CORBA_exception_id(&ev)));
		CORBA_exception_free(&ev);
		CORBA_Object_release(obj, &ev);
		return NULL;
	}
	verbose(lprintf(0, "trx_resolve_byindex: %s mfg %s model %s instid %s\n", 
			ior, desc->manufacturer, desc->model, desc->instid));
	CORBA_free(desc);
	CORBA_exception_free(&ev);
	return obj;
}

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

#if defined(WIN32)

extern void win32shmem_runserver(void);

static Trx_Control trx_resolve_byindex(unsigned int index)
{
	Trx_Control obj;
	HKEY key, key2;
        DWORD err, i, bufsz, dt;
	CORBA_Environment ev;
	char buf[512];

	win32shmem_runserver();
	if ((err = RegOpenKeyEx(IORREGHKEY, IORREGPATH, 0, KEY_ENUMERATE_SUB_KEYS, &key)) != ERROR_SUCCESS) {
                lprintf(0, "RegOpenKeyEx(" IORREGPATH ") returned 0x%lx\n", err);
                return CORBA_OBJECT_NIL;
        }
	for (i = 0;; i++) {
		bufsz = sizeof(buf);
		err =  RegEnumKeyEx(key, i, buf, &bufsz, NULL, NULL, NULL, NULL);
		if (err != ERROR_SUCCESS) {
			RegCloseKey(key);
			return NULL;
		}
		if (RegOpenKeyEx(key, buf, 0, KEY_ALL_ACCESS, &key2) != ERROR_SUCCESS)
			continue;
		bufsz = sizeof(buf);
		if (RegQueryValueEx(key2, "IOR", NULL, &dt, buf, &bufsz) != ERROR_SUCCESS) {
			RegCloseKey(key2);
			continue;
		}
                RegCloseKey(key2);
		if (dt != REG_SZ) {
			continue;
		}
		if ((obj = ior_to_obj(buf))) {
                        if (index) {
                                index--;
                                CORBA_exception_init(&ev);
                                CORBA_Object_release(obj, &ev);
                                CORBA_exception_free(&ev);
                                continue;
                        }
			RegCloseKey(key);
			return obj;
		}
	}
}

#else

static Trx_Control trx_resolve_byindex(unsigned int index)
{
	CORBA_Environment ev;
	DIR *dir;
	struct dirent *de;
	Trx_Control obj;
	char buf[1024];
	char buf2[1024];
	FILE *f;
	char *cp;

	if (!(dir = opendir(IORIDPATH)))
		return NULL;
	for (;;) {
		if (!(de = readdir(dir))) {
			closedir(dir);
			return NULL;
		}
		snprintf(buf, sizeof(buf), "%s/%s", IORIDPATH, de->d_name);
		if (!(f = fopen(buf, "r")))
			continue;
		if (!fgets(buf2, sizeof(buf2), f)) {
			fclose(f);
			continue;
		}
		fclose(f);
		if (strncmp(buf2, "IOR", 3))
			continue;
		if ((cp = strchr(buf2, '\n')))
			*cp = 0;
		printf("IOR: %s\n", buf2);
		if ((obj = ior_to_obj(buf2))) {
                        if (index) {
                                index--;
                                CORBA_exception_init(&ev);
                                CORBA_Object_release(obj, &ev);
                                CORBA_exception_free(&ev);
                                continue;
                        }
			closedir(dir);
			return obj;
		}
	}
}

#endif

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

int trxapi_init(int *argc, char **argv)
{
	CORBA_Environment ev;

        CORBA_exception_init(&ev);
	trx_orb = CORBA_ORB_init(argc, argv, "orbit-local-orb", &ev);
	if (ev._major != CORBA_NO_EXCEPTION) {
		verbose(lprintf(0, "Error: trx_initorb: %s\n", CORBA_exception_id(&ev)));
		CORBA_exception_free(&ev);
		return -1;
	}
	return 0;
}

struct trxapi *trxapi_open_byindex(unsigned int index)
{
	CORBA_Environment ev;
	Trx_TrxDescription *desc;
        Trx_BaycomUSBAdapterAudioDevs *audiodevs;
	struct trxapi_description *d;
	struct trxapi_baycomusb_adapter_audio_devs *ad;
	struct trxapi *api;
	unsigned int i;

	if (!(api = calloc(1, sizeof(struct trxapi))))
		return api;
	if (!(api->obj = trx_resolve_byindex(index))) {
		free(api);
		return NULL;
	}
	/* retrieve description */
	CORBA_exception_init(&ev);
	Trx_Control_GetDescription(api->obj, &desc, &ev);
	if (printexception("Trx_Control_GetDescription", &ev))
		goto errdesc;
	if (!(d = calloc(1, sizeof(struct trxapi_description) + 
				 (desc->rxbands._length + desc->txbands._length) * sizeof(struct trxapi_banddescription)))) {
		CORBA_free(desc);
		goto errdesc;
	}
	api->desc = d;
	d->rxbands = (struct trxapi_banddescription *)(d + 1);
	d->txbands = &d->rxbands[desc->rxbands._length];
	strncpy(d->manufacturer, desc->manufacturer, sizeof(d->manufacturer));
	d->manufacturer[sizeof(d->manufacturer)-1] = 0;
	strncpy(d->model, desc->model, sizeof(d->model));
	d->model[sizeof(d->model)-1] = 0;
	strncpy(d->copyright, desc->copyright, sizeof(d->copyright));
	d->copyright[sizeof(d->copyright)-1] = 0;
	strncpy(d->instid, desc->instid, sizeof(d->instid));
	d->instid[sizeof(d->instid)-1] = 0;
	d->nrrxbands = desc->rxbands._length;
	d->nrtxbands = desc->txbands._length;
	d->rssimin = desc->rssimin;
	d->rssimax = desc->rssimax;
	for (i = 0; i < d->nrrxbands; i++) {
		d->rxbands[i].low = desc->rxbands._buffer[i].low;
		d->rxbands[i].high = desc->rxbands._buffer[i].high;
		d->rxbands[i].step = desc->rxbands._buffer[i].step;
	}
	for (i = 0; i < d->nrtxbands; i++) {
		d->txbands[i].low = desc->txbands._buffer[i].low;
		d->txbands[i].high = desc->txbands._buffer[i].high;
		d->txbands[i].step = desc->txbands._buffer[i].step;
	}
	CORBA_free(desc);
  errdesc:
	/* retrieve audio devs */
	CORBA_exception_init(&ev);
        Trx_Control_BaycomUSBAdapterGetAudioDevices(api->obj, &audiodevs, &ev);
	if (printexception("Trx_Control_BaycomUSBAdapterGetAudioDevices", &ev))
		goto erraudiodevs;
	if (!(ad = calloc(1, sizeof(struct trxapi_baycomusb_adapter_audio_devs) + 
			  audiodevs->audiodevsin._length * sizeof(trxapi_audiodevice_t) + 
			  audiodevs->audiodevsout._length * sizeof(trxapi_audiodevice_t)))) {
		CORBA_free(desc);
		goto erraudiodevs;
	}
	api->audiodevs = ad;
	ad->audiodevsin = (void *)(ad + 1);
	ad->nraudiodevsin = audiodevs->audiodevsin._length;
	ad->audiodevsout = &ad->audiodevsin[ad->nraudiodevsin];
	ad->nraudiodevsout = audiodevs->audiodevsout._length;
	for (i = 0; i < ad->nraudiodevsin; i++) {
		strncpy(ad->audiodevsin[i], audiodevs->audiodevsin._buffer[i], sizeof(ad->audiodevsin[i]));
		ad->audiodevsin[i][sizeof(ad->audiodevsin[i])-1] = 0;
	}
	for (i = 0; i < ad->nraudiodevsout; i++) {
		strncpy(ad->audiodevsout[i], audiodevs->audiodevsout._buffer[i], sizeof(ad->audiodevsout[i]));
		ad->audiodevsout[i][sizeof(ad->audiodevsout[i])-1] = 0;
	}
	CORBA_free(audiodevs);
  erraudiodevs:
	return api;

  err:
	trxapi_close(api);
	return NULL;
}

void trxapi_close(struct trxapi *api)
{
        CORBA_Environment ev;

	if (!api)
		return;
	if (api->desc)
		free(api->desc);
	if (api->audiodevs)
		free(api->audiodevs);
        CORBA_exception_init(&ev);
	CORBA_Object_release(api->obj, &ev);
        CORBA_exception_free(&ev);
	free(api);
}

const struct trxapi_description *trxapi_get_description(struct trxapi *api)
{
	if (!api)
		return NULL;
	return api->desc;
}

int trxapi_get_state(struct trxapi *api, struct trxapi_state *state)
{
        CORBA_Environment ev;
        Trx_TrxState status;
	
	if (!state || !api)
		return -1;
        CORBA_exception_init(&ev);
        Trx_Control_GetState(api->obj, &status, &ev);
	if (printexception("Trx_Control_GetState", &ev))
		return -1;
	switch (status.mode) {
	case Trx_trxpacket:
		state->mode = trxapi_mode_packet;
		break;

	case Trx_trxaudio:
		state->mode = trxapi_mode_audio;
		break;

	default:
		state->mode = trxapi_mode_unspec;
	};
	state->rxfreq = status.rxfreq;
	state->txfreq = status.txfreq;
	state->ptt = status.ptt;
	state->manualptt = status.manualptt;
	state->dcd = status.dcd;
	state->rssi = status.rssi;
	return 0;
}

int trxapi_set_ptt(struct trxapi *api, unsigned int ptt)
{
        CORBA_Environment ev;
	
	if (!api)
		return -1;
        CORBA_exception_init(&ev);
        Trx_Control_SetPTT(api->obj, !!ptt, &ev);
	return printexception("Trx_Control_SetPTT", &ev);
}

int trxapi_set_frequency(struct trxapi *api, trxapi_frequency_t rx, trxapi_frequency_t tx)
{
        CORBA_Environment ev;
	
	if (!api)
		return -1;
        CORBA_exception_init(&ev);
        Trx_Control_SetFrequency(api->obj, rx, tx, &ev);
	return printexception("Trx_Control_SetFrequency", &ev);
}

/* Raw UART */
int trxapi_uart_send(struct trxapi *api, const char *str)
{
        CORBA_Environment ev;
	
	if (!api || !str)
		return -1;
        CORBA_exception_init(&ev);
	Trx_Control_UartSend(api->obj, str, &ev);
	return printexception("Trx_Control_UartSend", &ev);
}

int trxapi_uart_receive(struct trxapi *api, unsigned long *ptr, char *str, unsigned int strsz)
{
        CORBA_char *uartstr;
	CORBA_unsigned_long rxuartptr;
        CORBA_Environment ev;
	unsigned int len;

	if (!api || !str || !ptr || strsz < 2)
		return -1;
	str[0] = 0;
	rxuartptr = *ptr;
        CORBA_exception_init(&ev);
	Trx_Control_UartReceive(api->obj, &rxuartptr, &uartstr, &ev);
	if (printexception("Trx_Control_UartReceive", &ev))
		return -1;
	len = strlen(uartstr);
	if (len >= strsz) {
		rxuartptr -= (len - strsz + 1);
		len = strsz - 1;
	}
	*ptr = rxuartptr;
	memcpy(str, uartstr, len);
	str[len] = 0;
	CORBA_free(uartstr);
	return 0;
}

/* Configuration stuff */
int trxapi_baycomusb_adapter_get_config(struct trxapi *api, struct trxapi_baycomusb_adapter_config *cfg)
{
	Trx_BaycomUSBAdapterConfig adaptcfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
        CORBA_exception_init(&ev);
	Trx_Control_BaycomUSBAdapterGetConfig(api->obj, &adaptcfg, &ev);
	if (printexception("Trx_Control_BaycomUSBAdapterGetConfig", &ev))
		return -1;
	switch (adaptcfg.mode) {
	default:
		cfg->mode = trxapi_baycomusb_mode_fsk;
		break;

	case Trx_external:
		cfg->mode = trxapi_baycomusb_mode_external;
		break;

	case Trx_afsk:
		cfg->mode = trxapi_baycomusb_mode_afsk;
		break;

	case Trx_audio:
		cfg->mode = trxapi_baycomusb_mode_audio;
		break;
	}
	cfg->fclk = adaptcfg.fclk;
	cfg->bitraterx = adaptcfg.bitraterx;
	cfg->bitratetx = adaptcfg.bitratetx;
	switch (adaptcfg.loopback) {
	default:
		cfg->loopback = trxapi_baycomusb_loopback_off;
		break;

	case Trx_loopback_scrambler:
		cfg->loopback = trxapi_baycomusb_loopback_scrambler;
		break;

	case Trx_loopback_modem:
		cfg->loopback = trxapi_baycomusb_loopback_modem;
		break;
	}
	cfg->pttmute = adaptcfg.pttmute;
	cfg->filtmode = adaptcfg.filtmode;
	/* audio stuff */
	cfg->samplerate = adaptcfg.samplerate;
	cfg->gain = adaptcfg.gain;
	strncpy(cfg->audiodevin, adaptcfg.audiodevin, sizeof(cfg->audiodevin));
	cfg->audiodevin[sizeof(cfg->audiodevin)-1] = 0;
	strncpy(cfg->audiodevout, adaptcfg.audiodevout, sizeof(cfg->audiodevout));
	cfg->audiodevout[sizeof(cfg->audiodevout)-1] = 0;
	cfg->rfsquelch = adaptcfg.rfsquelch;
	cfg->audiosquelch = adaptcfg.audiosquelch;
	return 0;
}

int trxapi_baycomusb_adapter_set_config(struct trxapi *api, const struct trxapi_baycomusb_adapter_config *cfg)
{
	Trx_BaycomUSBAdapterConfig adaptcfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
	switch (cfg->mode) {
	default:
		adaptcfg.mode = Trx_fsk;
		break;

	case trxapi_baycomusb_mode_external:
		adaptcfg.mode = Trx_external;
		break;

	case trxapi_baycomusb_mode_afsk:
		adaptcfg.mode = Trx_afsk;
		break;

	case trxapi_baycomusb_mode_audio:
		adaptcfg.mode = Trx_audio;
		break;
	}
	adaptcfg.fclk = cfg->fclk;
	adaptcfg.bitraterx = cfg->bitraterx;
	adaptcfg.bitratetx = cfg->bitratetx;
	switch (cfg->loopback) {
	default:
		adaptcfg.loopback = Trx_loopback_off;
		break;

	case trxapi_baycomusb_loopback_scrambler:
		adaptcfg.loopback = Trx_loopback_scrambler;
		break;

	case trxapi_baycomusb_loopback_modem:
		adaptcfg.loopback = Trx_loopback_modem;
		break;
	}
	adaptcfg.pttmute = cfg->pttmute ? CORBA_TRUE : CORBA_FALSE;
	adaptcfg.filtmode = cfg->filtmode;
	/* audio stuff */
	adaptcfg.samplerate = cfg->samplerate;
	adaptcfg.gain = cfg->gain;
	strncpy(adaptcfg.audiodevin, cfg->audiodevin, sizeof(adaptcfg.audiodevin));
	adaptcfg.audiodevin[sizeof(adaptcfg.audiodevin)-1] = 0;
	strncpy(adaptcfg.audiodevout, cfg->audiodevout, sizeof(adaptcfg.audiodevout));
	adaptcfg.audiodevout[sizeof(adaptcfg.audiodevout)-1] = 0;
	adaptcfg.rfsquelch = cfg->rfsquelch;
	adaptcfg.audiosquelch = cfg->audiosquelch;
        CORBA_exception_init(&ev);
	Trx_Control_BaycomUSBAdapterSetConfig(api->obj, &adaptcfg, &ev);
	return printexception("Trx_Control_BaycomUSBAdapterSetConfig", &ev);
}

const struct trxapi_baycomusb_adapter_audio_devs *trxapi_baycomusb_adapter_get_audiodevices(struct trxapi *api)
{
	if (!api)
		return NULL;
	return api->audiodevs;
}


int trxapi_channel_access_get_config(struct trxapi *api, struct trxapi_channel_access_config *cfg)
{
        Trx_ChannelAccessConfig chacccfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
        CORBA_exception_init(&ev);
        Trx_Control_ChannelAccessGetConfig(api->obj, &chacccfg, &ev);
	if (printexception("Trx_Control_ChannelAccessGetConfig", &ev))
		return -1;
	cfg->txdelay = chacccfg.txdelay;
	cfg->slottime = chacccfg.slottime;
	cfg->ppersistence = chacccfg.ppersistence;
	cfg->txtail = chacccfg.txtail;
	cfg->fullduplex = chacccfg.fullduplex;
	return 0;
}

int trxapi_channel_access_set_config(struct trxapi *api, const struct trxapi_channel_access_config *cfg)
{
        Trx_ChannelAccessConfig chacccfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
	chacccfg.txdelay = cfg->txdelay;
	chacccfg.slottime = cfg->slottime;
	chacccfg.ppersistence = cfg->ppersistence;
	chacccfg.txtail = cfg->txtail;
	chacccfg.fullduplex = cfg->fullduplex ? CORBA_TRUE : CORBA_FALSE;
        CORBA_exception_init(&ev);
        Trx_Control_ChannelAccessSetConfig(api->obj, &chacccfg, &ev);
	if (printexception("Trx_Control_ChannelAccessSetConfig", &ev))
		return -1;
	return 0;
}


int trxapi_interface_get_config(struct trxapi *api, struct trxapi_interface_config *cfg)
{
        Trx_InterfaceConfig ifcfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
        CORBA_exception_init(&ev);
        Trx_Control_InterfaceGetConfig(api->obj, &ifcfg, &ev);
	if (printexception("Trx_Control_InterfaceGetConfig", &ev))
		return -1;
	strncpy(cfg->ifname, ifcfg.ifname, sizeof(cfg->ifname));
	cfg->ifname[sizeof(cfg->ifname)-1] = 0;
	strncpy(cfg->hwaddr, ifcfg.hwaddr, sizeof(cfg->hwaddr));
	cfg->hwaddr[sizeof(cfg->hwaddr)-1] = 0;
	cfg->ipaddr[0] = ifcfg.ipaddr[0];
	cfg->ipaddr[1] = ifcfg.ipaddr[1];
	cfg->ipaddr[2] = ifcfg.ipaddr[2];
	cfg->ipaddr[3] = ifcfg.ipaddr[3];
	cfg->netmask[0] = ifcfg.netmask[0];
	cfg->netmask[1] = ifcfg.netmask[1];
	cfg->netmask[2] = ifcfg.netmask[2];
	cfg->netmask[3] = ifcfg.netmask[3];
	cfg->broadcast[0] = ifcfg.broadcast[0];
	cfg->broadcast[1] = ifcfg.broadcast[1];
	cfg->broadcast[2] = ifcfg.broadcast[2];
	cfg->broadcast[3] = ifcfg.broadcast[3];
	strncpy(cfg->gwhwaddr, ifcfg.gwhwaddr, sizeof(cfg->gwhwaddr));
	cfg->gwhwaddr[sizeof(cfg->gwhwaddr)-1] = 0;
	cfg->gwipaddr[0] = ifcfg.gwipaddr[0];
	cfg->gwipaddr[1] = ifcfg.gwipaddr[1];
	cfg->gwipaddr[2] = ifcfg.gwipaddr[2];
	cfg->gwipaddr[3] = ifcfg.gwipaddr[3];
	cfg->gwnetmask[0] = ifcfg.gwnetmask[0];
	cfg->gwnetmask[1] = ifcfg.gwnetmask[1];
	cfg->gwnetmask[2] = ifcfg.gwnetmask[2];
	cfg->gwnetmask[3] = ifcfg.gwnetmask[3];
	cfg->gwipmode = ifcfg.gwipmode;
	return 0;
}

int trxapi_interface_set_config(struct trxapi *api, const struct trxapi_interface_config *cfg)
{
        Trx_InterfaceConfig ifcfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
	strncpy(ifcfg.ifname, cfg->ifname, sizeof(ifcfg.ifname));
	ifcfg.ifname[sizeof(ifcfg.ifname)-1] = 0;
	strncpy(ifcfg.hwaddr, cfg->hwaddr, sizeof(ifcfg.hwaddr));
	ifcfg.hwaddr[sizeof(ifcfg.hwaddr)-1] = 0;
	ifcfg.ipaddr[0] = cfg->ipaddr[0];
	ifcfg.ipaddr[1] = cfg->ipaddr[1];
	ifcfg.ipaddr[2] = cfg->ipaddr[2];
	ifcfg.ipaddr[3] = cfg->ipaddr[3];
	ifcfg.netmask[0] = cfg->netmask[0];
	ifcfg.netmask[1] = cfg->netmask[1];
	ifcfg.netmask[2] = cfg->netmask[2];
	ifcfg.netmask[3] = cfg->netmask[3];
	ifcfg.broadcast[0] = cfg->broadcast[0];
	ifcfg.broadcast[1] = cfg->broadcast[1];
	ifcfg.broadcast[2] = cfg->broadcast[2];
	ifcfg.broadcast[3] = cfg->broadcast[3];
	strncpy(ifcfg.gwhwaddr, cfg->gwhwaddr, sizeof(ifcfg.gwhwaddr));
	ifcfg.gwhwaddr[sizeof(ifcfg.gwhwaddr)-1] = 0;
	ifcfg.gwipaddr[0] = cfg->gwipaddr[0];
	ifcfg.gwipaddr[1] = cfg->gwipaddr[1];
	ifcfg.gwipaddr[2] = cfg->gwipaddr[2];
	ifcfg.gwipaddr[3] = cfg->gwipaddr[3];
	ifcfg.gwnetmask[0] = cfg->gwnetmask[0];
	ifcfg.gwnetmask[1] = cfg->gwnetmask[1];
	ifcfg.gwnetmask[2] = cfg->gwnetmask[2];
	ifcfg.gwnetmask[3] = cfg->gwnetmask[3];
	ifcfg.gwipmode = cfg->gwipmode;
        CORBA_exception_init(&ev);
        Trx_Control_InterfaceSetConfig(api->obj, &ifcfg, &ev);
	return printexception("Trx_Control_InterfaceSetConfig", &ev);
}

int trxapi_modem_disconnect_get_config(struct trxapi *api, struct trxapi_modem_disconnect_config *cfg)
{
	Trx_ModemDisconnectConfig mdisccfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
        CORBA_exception_init(&ev);
        Trx_Control_ModemDisconnectGetConfig(api->obj, &mdisccfg, &ev);
	if (printexception("Trx_Control_ModemDisconnectGetConfig", &ev))
		return -1;
	cfg->output = mdisccfg.output;
	cfg->direction = mdisccfg.direction;
	switch (mdisccfg.rxc) {
	default:
		cfg->rxc = trxapi_modem_disconnect_rxc_normal;
		break;

	case Trx_mdisc_rxc_rxclock:
		cfg->rxc = trxapi_modem_disconnect_rxc_rxclock;
		break;
	}
	switch (mdisccfg.txc) {
	default:
		cfg->txc = trxapi_modem_disconnect_txc_normal;
		break;

	case Trx_mdisc_txc_txclock:
		cfg->txc = trxapi_modem_disconnect_txc_txclock;
		break;
	}
	switch (mdisccfg.txd) {
	default:
		cfg->txd = trxapi_modem_disconnect_txd_normal;
		break;

	case Trx_mdisc_txd_txdata:
		cfg->txd = trxapi_modem_disconnect_txd_txdata;
		break;
	}
	return 0;
}

int trxapi_modem_disconnect_set_config(struct trxapi *api, const struct trxapi_modem_disconnect_config *cfg)
{
	Trx_ModemDisconnectConfig mdisccfg;
        CORBA_Environment ev;

	if (!api || !cfg)
		return -1;
	mdisccfg.output = cfg->output;
	mdisccfg.direction = cfg->direction;
	switch (cfg->rxc) {
	default:
		mdisccfg.rxc = Trx_mdisc_rxc_normal;
		break;

	case trxapi_modem_disconnect_rxc_rxclock:
		mdisccfg.rxc = Trx_mdisc_rxc_rxclock;
		break;
	}
	switch (cfg->txc) {
	default:
		mdisccfg.txc = Trx_mdisc_txc_normal;
		break;

	case trxapi_modem_disconnect_txc_txclock:
		mdisccfg.txc = Trx_mdisc_txc_txclock;
		break;
	}
	switch (cfg->txd) {
	default:
		mdisccfg.txd = Trx_mdisc_txd_normal;
		break;

	case trxapi_modem_disconnect_txd_txdata:
		mdisccfg.txd = Trx_mdisc_txd_txdata;
		break;
	}
        CORBA_exception_init(&ev);
        Trx_Control_ModemDisconnectSetConfig(api->obj, &mdisccfg, &ev);
	return printexception("Trx_Control_ModemDisconnectSetConfig", &ev);
}

/* Audio Stuff */

int trxapi_get_audio_state(struct trxapi *api, struct trxapi_audio_state *state)
{
        CORBA_Environment ev;
        Trx_TrxAudioState audiostate;
	
	if (!state || !api)
		return -1;
        CORBA_exception_init(&ev);
	Trx_Control_GetAudioState(api->obj, &audiostate, &ev);
	if (printexception("Trx_Control_GetAudioState", &ev))
		return -1;
	state->samplerate = audiostate.samplerate;
	state->micbufsz = audiostate.micbufsz;
	state->micbufptr = audiostate.micbufptr;
	state->spkbufsz = audiostate.spkbufsz;
	state->spkbufptr = audiostate.spkbufptr;
	state->micsigpwr = audiostate.micsigpwr;
	state->spksigpwr = audiostate.spksigpwr;
	state->spknoisepwr = audiostate.spknoisepwr;
	return 0;
}

int trxapi_get_audio_mic_samples(struct trxapi *api, unsigned long ptr, unsigned long len, unsigned char *samples)
{
        CORBA_Environment ev;
	Trx_TrxAudioSamples *audiosamples;

	if (!samples || !api || !len)
		return -1;
        CORBA_exception_init(&ev);
	Trx_Control_GetAudioMicSamples(api->obj, ptr, len, &audiosamples, &ev);
 	if (printexception("Trx_Control_GetAudioMicSamples", &ev))
		return -1;
	if (audiosamples->_length != len) {
		CORBA_free(audiosamples);
		return -1;
	}
	memcpy(samples, audiosamples->_buffer, len);
	CORBA_free(audiosamples);
	return 0;
}

int trxapi_get_audio_spk_samples(struct trxapi *api, unsigned long ptr, unsigned long len, unsigned char *samples)
{
        CORBA_Environment ev;
	Trx_TrxAudioSamples *audiosamples;

	if (!samples || !api || !len)
		return -1;
        CORBA_exception_init(&ev);
	Trx_Control_GetAudioSpkSamples(api->obj, ptr, len, &audiosamples, &ev);
 	if (printexception("Trx_Control_GetAudioSpkSamples", &ev))
		return -1;
	if (audiosamples->_length != len) {
		CORBA_free(audiosamples);
		return -1;
	}
	memcpy(samples, audiosamples->_buffer, len);
	CORBA_free(audiosamples);
	return 0;
}

int trxapi_set_audio_dtmf(struct trxapi *api, long ch)
{
        CORBA_Environment ev;
	
	if (!api)
		return -1;
        CORBA_exception_init(&ev);
	Trx_Control_SetAudioDTMF(api->obj, ch, &ev);
	return printexception("Trx_Control_SetAudioDTMF", &ev);
}

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