/*
 * libgsmat: An implementation of Primary Rate ISDN
 *
 * Written by Mark Spencer <markster@linux-support.net>
 *
 * Copyright (C) 2001, Linux Support Services, Inc.
 * All Rights Reserved.
 *
 * Parts taken from libpri-1.0.9
 * Written by Mark Spencer <markster@linux-support.net>
 *
 * Copyright (C) 2001, Linux Support Services, Inc.
 * All Rights Reserved.
 *
 * 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. 
 *
 */

/*
 * This program tests libpri call reception using a zaptel interface.
 * Its state machines are setup for RECEIVING CALLS ONLY, so if you
 * are trying to both place and receive calls you have to a bit more.
 */

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/time.h>
#if defined(__linux__)
#include <linux/zaptel.h>
#elif defined(__FreeBSD__)
#include <zaptel.h>
#endif
#include "libgsmat.h"

#define MAX_CHAN		1
#define	DCHANNEL_TIMESLOT	2


static int offset = 0;


static void handle_gsm_event(struct gsm_modul *gsm, gsm_event *e)
{
	switch(e->e) {
	case GSM_EVENT_DCHAN_UP:
		printf("-- D-Channel is now up!  :-)\n");
//		gsm_sms_send_text(gsm, "01607503372", "huhu2");
//		gsm_sms_send_pdu(gsm, "0011000C919461700533270000AA0CC8F71D14969741F977FD07", 25);
//		gsm_sms_send_pdu(gsm, "0011000C919471381763950000AA04F4F29C0E", 18);
// boo		gsm_sms_send_pdu(gsm, "0011000C919461700533270018AA0A00010042004F004F0021", 24);
		gsm_sms_send_pdu(gsm, "0011000D91947126146698F00018AA1E0001004B004100500045004A004F0044002000520055004C0045005A0021", 45);
//		gsm_request_status(gsm);
		break;
	case GSM_EVENT_DCHAN_DOWN:
		printf("-- D-Channel is now down! :-(\n");
		break;
	case GSM_EVENT_RING:
		printf("-- Ring on channel %d (from %s to %s), answering...\n", e->ring.channel, e->ring.callingnum, e->ring.callednum);
	//	start_channel(pri, e);
	//	gsm_answer(gsm);
		break;
	case GSM_EVENT_HANGUP:
		printf("-- Hanging up channel %d\n", e->hangup.channel);
		break;
	case GSM_EVENT_ANSWER:
		fprintf(stderr, "--!! What?  We shouldn't be making any calls...\n");
		break;
	case GSM_EVENT_PIN_REQUIRED:
		gsm_send_pin(gsm, "5665");
		break;
	default:
		fprintf(stderr, "--!! Unknown PRI event %d\n", e->e);
	}
}

static int run_gsm(int dfd, int modemtype)
{
	struct gsm_modul *gsm;
	gsm_event *e;
	struct timeval tv = {0,0}, *next;
	fd_set rfds, efds;
	int res,x;

	gsm = gsm_new(dfd, modemtype, "5665", 0);

	if (!gsm) {
		fprintf(stderr, "Unable to create gsm\n");
		return -1;
	}
	gsm_set_debug(gsm, 1);
	for (;;) {
		
		/* Run the D-Channel */
		FD_ZERO(&rfds);
		FD_ZERO(&efds);
		FD_SET(dfd, &rfds);
		FD_SET(dfd, &efds);

		if ((next = gsm_schedule_next(gsm))) {
			gettimeofday(&tv, NULL);
			tv.tv_sec = next->tv_sec - tv.tv_sec;
			tv.tv_usec = next->tv_usec - tv.tv_usec;
			if (tv.tv_usec < 0) {
				tv.tv_usec += 1000000;
				tv.tv_sec -= 1;
			}
			if (tv.tv_sec < 0) {
				tv.tv_sec = 0;
				tv.tv_usec = 0;
			}
		}
		res = select(dfd + 1, &rfds, NULL, &efds, next ? &tv : NULL);
		e = NULL;

		if (!res) {
			e = gsm_schedule_run(gsm);
		} else if (res > 0) {
			e = gsm_check_event(gsm, 1);
		} else if (errno == ELAST) {
			res = ioctl(dfd, ZT_GETEVENT, &x);
			printf("Got Zaptel event: %d\n", x);
		} else if (errno != EINTR) 
			fprintf(stderr, "Error (%d) on select: %s\n", ELAST, strerror(errno));

		if (!e) {
		    e = gsm_check_event(gsm, 0);
		}

		if (e) {
			handle_gsm_event(gsm, e);
		}

		res = ioctl(dfd, ZT_GETEVENT, &x);

		if (!res && x) {
			fprintf(stderr, "Got event on PRI interface: %d\n", x);
		}


	}
	return 0;
}

int main(int argc, char *argv[]) 
{
	int dfd;
	struct zt_params p;
	struct zt_bufferinfo bi;
	if (argc < 3) {
		fprintf(stderr, "Usage: gsm_sms <channel> <destination> <text>]\n");
		exit(1);
	}
	dfd = open(argv[1], O_RDWR);
	if (dfd < 0) {
		fprintf(stderr, "Failed to open dchannel '%s': %s\n", argv[1], strerror(errno));
		exit(1);
	}
	if (ioctl(dfd, ZT_GET_PARAMS, &p)) {
		fprintf(stderr, "Unable to get parameters on '%s': %s\n", argv[1], strerror(errno));
		exit(1);
	}
	if ((p.sigtype != ZT_SIG_HDLCRAW) && (p.sigtype != ZT_SIG_HDLCFCS)) {
		fprintf(stderr, "%s is in %d signalling, not FCS HDLC or RAW HDLC mode\n", argv[1], p.sigtype);
		exit(1);
	}

	bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
        bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
	bi.numbufs = 16;
	bi.bufsize = 1024;
	if (ioctl(dfd, ZT_SET_BUFINFO, &bi)) {
		fprintf(stderr, "Unable to set buffer info on '%s': %s\n", argv[1], strerror(errno));
		exit(1);
	}

	if (run_gsm(dfd, 1))
		exit(1);

//	signal(SIGCHLD, chan_ended);

	exit(0);

	return 0;
}
