#include <stdio.h>
#include "isdn_net.h"
#include "tone.h"
#include "bchannel.h"

/* 
 * These are 10 periods (24 ms) of the 425 Hz tone used by most inband
 * signals.
 * Its quiet not exacly 425 Hz, but 416,66667, which fit very well
 * the 15% tolerance
 */

const unsigned char tone_425[TONE_425_SIZE] = {
 0xd5, 0x81, 0xb6, 0xbf, 0xbb, 0xba, 0xb8, 0xb2,
 0x8a, 0x9d, 0x15, 0x0e, 0x33, 0x39, 0x3a, 0x3b,
 0x3e, 0x31, 0x0d, 0x65, 0x85, 0xb4, 0xbd, 0xb8,
 0xba, 0xb8, 0xbd, 0xb4, 0x85, 0x65, 0x0d, 0x31,
 0x3e, 0x3b, 0x3a, 0x39, 0x33, 0x0e, 0x15, 0x9d,
 0x8a, 0xb2, 0xb8, 0xba, 0xbb, 0xbf, 0xb6, 0x81,
 0xd5, 0x01, 0x36, 0x3f, 0x3b, 0x3a, 0x38, 0x32,
 0x0a, 0x1d, 0x95, 0x8e, 0xb3, 0xb9, 0xba, 0xbb,
 0xbe, 0xb1, 0x8d, 0xe5, 0x05, 0x34, 0x3d, 0x38,
 0x3a, 0x38, 0x3d, 0x34, 0x05, 0xe5, 0x8d, 0xb1,
 0xbe, 0xbb, 0xba, 0xb9, 0xb3, 0x8e, 0x95, 0x1d,
 0x0a, 0x32, 0x38, 0x3a, 0x3b, 0x3f, 0x36, 0x01,
 0xd5, 0x81, 0xb6, 0xbf, 0xbb, 0xba, 0xb8, 0xb2,
 0x8a, 0x9d, 0x15, 0x0e, 0x33, 0x39, 0x3a, 0x3b,
 0x3e, 0x31, 0x0d, 0x65, 0x85, 0xb4, 0xbd, 0xb8,
 0xba, 0xb8, 0xbd, 0xb4, 0x85, 0x65, 0x0d, 0x31,
 0x3e, 0x3b, 0x3a, 0x39, 0x33, 0x0e, 0x15, 0x9d,
 0x8a, 0xb2, 0xb8, 0xba, 0xbb, 0xbf, 0xb6, 0x81,
 0xd5, 0x01, 0x36, 0x3f, 0x3b, 0x3a, 0x38, 0x32,
 0x0a, 0x1d, 0x95, 0x8e, 0xb3, 0xb9, 0xba, 0xbb,
 0xbe, 0xb1, 0x8d, 0xe5, 0x05, 0x34, 0x3d, 0x38,
 0x3a, 0x38, 0x3d, 0x34, 0x05, 0xe5, 0x8d, 0xb1,
 0xbe, 0xbb, 0xba, 0xb9, 0xb3, 0x8e, 0x95, 0x1d,
 0x0a, 0x32, 0x38, 0x3a, 0x3b, 0x3f, 0x36, 0x01
};

/* 
 * These are 10 ms of silence
 */

const unsigned char tone_SILENCE[TONE_SILENCE_SIZE] = {
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5
};

int tone_handler(bchannel_t *bc) {
	const unsigned char	*tp;
	int			len;

	dprint(DBGM_TONE, "%s:ch%d Flags %x\n", __FUNCTION__,
		bc->channel, bc->Flags);
	if (bc->bstate != BC_BSTATE_ACTIV)
		return(1);
	if (bc->smsg)
		return(2);
	if (!(bc->Flags & FLG_BC_TONE))
		return(3);
	if (bc->Flags & FLG_BC_TONE_DIAL) {
		tp = tone_425;
		len = TONE_425_SIZE;
	} else if (bc->Flags & FLG_BC_TONE_ALERT) {
		if (bc->Flags & FLG_BC_TONE_SILENCE) {
			if (bc->ttime > TONE_ALERT_SILENCE_TIME) {
				bc->ttime = 0;
				tp = tone_425;
				len = TONE_425_SIZE;
				bc->Flags &= ~FLG_BC_TONE_SILENCE;
			} else {
				tp = tone_SILENCE;
				len = TONE_SILENCE_SIZE;
			}
		} else {
			if (bc->ttime > TONE_ALERT_TIME) {
				bc->ttime = 0;
				tp = tone_SILENCE;
				len = TONE_SILENCE_SIZE;
				bc->Flags |= FLG_BC_TONE_SILENCE;
			} else {
				tp = tone_425;
				len = TONE_425_SIZE;
			}
		}
	} else if (bc->Flags & FLG_BC_TONE_BUSY) {
		if (bc->Flags & FLG_BC_TONE_SILENCE) {
			if (bc->ttime > TONE_BUSY_SILENCE_TIME) {
				bc->ttime = 0;
				tp = tone_425;
				len = TONE_425_SIZE;
				bc->Flags &= ~FLG_BC_TONE_SILENCE;
			} else {
				tp = tone_SILENCE;
				len = TONE_SILENCE_SIZE;
			}
		} else {
			if (bc->ttime > TONE_BUSY_TIME) {
				bc->ttime = 0;
				tp = tone_SILENCE;
				len = TONE_SILENCE_SIZE;
				bc->Flags |= FLG_BC_TONE_SILENCE;
			} else {
				tp = tone_425;
				len = TONE_425_SIZE;
			}
		}
	} else if (bc->Flags & FLG_BC_TONE_SILENCE) {
		tp = tone_SILENCE;
		len = TONE_SILENCE_SIZE;
	} else
		return(4);
	if (len > ibuf_freecount(bc->sbuf)) {
		dprint(DBGM_TONE, "%s:ch%d not sbuf %d/%d\n", __FUNCTION__,
			bc->channel, len, ibuf_freecount(bc->sbuf));
		return(5);
	}
	if (bc->sbuf) {
		bc->ttime += len*125;
		ibuf_memcpy_w(bc->sbuf, (unsigned char *)tp, len);
		sem_post(bc->sbuf->rsem);
	}
	return(0);
}

int
set_tone(bchannel_t *bc, int tone)
{
	bc->Flags &= ~FLG_BC_TONE;
	bc->Flags |= tone;
	bc->ttime = 0;
	if (tone) {
		if (bc->sbuf) {
			bc->sbuf->rsem = &bc->work;
			bc->sbuf->wsem = &bc->work;
		}
	}
	return(bc->Flags & FLG_BC_TONE);
}
