/* (c) 2006 by Marcin Wiacek */

#include "../../gsmstate.h"

#if defined(GSM_ENABLE_BLUEGNAPBUS) || defined(GSM_ENABLE_IRDAGNAPBUS)

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

#include "../../gsmcomon.h"
#include "gnapbus.h"

static GSM_Error GNAPBUS_WriteMessage (GSM_StateMachine *s, unsigned const char *MsgBuffer,
				    int MsgLength, unsigned char MsgType)
{
	unsigned char		*buffer2;
	int			sent,len;
	unsigned char checksum;
	int i;

	GSM_DumpMessageLevel3(s, MsgBuffer, MsgLength, MsgType);

	buffer2 = (unsigned char *)malloc(MsgLength + 10);

	buffer2[0] = GNAPBUS_FRAME_ID,
	buffer2[1] = 0x00;
	buffer2[2] = MsgLength / 256;
	buffer2[3] = MsgLength % 256;
	buffer2[4] = MsgType;
	buffer2[5] = 0x00;
	memcpy(buffer2 + 6, MsgBuffer, MsgLength);
	len = 	MsgLength+6;

	if (MsgLength & 1) buffer2[len++] = 0x00;
	/* Odd messages require additional 0x00 byte */
/* 	if (MsgLength % 2) buffer2[len++] = 0x00; */

	checksum 	= 0;
	for (i = 0; i < len; i+=2) checksum ^= buffer2[i];
	buffer2[len++] 	= checksum;

	checksum 	= 0;
	for (i = 1; i < len; i+=2) checksum ^= buffer2[i];
	buffer2[len++] 	= checksum;

/* 	GSM_DumpMessageLevel2(s, buffer2, len, MsgType); */
	GSM_DumpMessageLevel2(s, MsgBuffer, MsgLength, MsgType);

	/* Sending to phone */
	sent = s->Device.Functions->WriteDevice(s,buffer2,len);

	free(buffer2);

	if (sent!=len) return ERR_DEVICEWRITEERROR;
	return ERR_NONE;
}

static GSM_Error GNAPBUS_StateMachine(GSM_StateMachine *s, unsigned char rx_char)
{
	GSM_Protocol_GNAPBUSData *d = &s->Protocol.Data.GNAPBUS;

/* printf("%02x ",rx_char); */
/* fflush(stdout); */
	/* XOR the byte with the earlier checksum */
	d->Msg.CheckSum[d->Msg.Count & 1] ^= rx_char;

	switch (d->MsgRXState) {
	case RX_Sync:
		if (rx_char == GNAPBUS_FRAME_ID) {
			d->MsgRXState = RX_GetDestination;
			d->Msg.Count = 0;
			d->Msg.Length = 0;
			d->Msg.CheckSum[0] = rx_char;
			d->Msg.CheckSum[1] = 0;
		} else smprintf(s,"Sync error: %02x\n",rx_char);
		break;
	case RX_GetDestination:
		d->MsgRXState = RX_GetLength1;
		break;
	case RX_GetLength1:
		d->MsgRXState = RX_GetLength2;
		d->Msg.Length = rx_char << 8;
		break;
	case RX_GetLength2:
		d->MsgRXState = RX_GetType;
		d->Msg.Length += rx_char;
		d->Msg.Buffer 	= (unsigned char *)malloc(d->Msg.Length+3);
		break;
	case RX_GetType:
		d->MsgRXState = RX_GetSource;
		d->Msg.Type = rx_char;
		break;
	case RX_GetSource:
		d->MsgRXState = RX_GetMessage;
		break;
	case RX_GetMessage:
		d->Msg.Buffer[d->Msg.Count] = rx_char;
		d->Msg.Count++;

		if (d->Msg.Count != ((d->Msg.Length+3)& ~1)) return ERR_NONE;

/* 	GSM_DumpMessageLevel2(s, d->Msg.Buffer, d->Msg.Count, d->Msg.Type); */
/* printf("\n%02x %02x\n",d->Msg.CheckSum[0],d->Msg.CheckSum[1]); */
		/* Checksum is incorrect */
		if (d->Msg.CheckSum[0] != d->Msg.CheckSum[1]) {
			if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL || s->di.dl==DL_TEXTERROR ||
			    s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE || s->di.dl==DL_TEXTERRORDATE) {
				smprintf(s,"[ERROR: checksum]\n");
			}
			free(d->Msg.Buffer);
			d->Msg.Length 		= 0;
			d->Msg.Buffer 		= NULL;

			d->MsgRXState 		= RX_Sync;
			return ERR_NONE;
		}

		s->Phone.Data.RequestMsg	= &d->Msg;
		s->Phone.Data.DispatchError	= s->Phone.Functions->DispatchMessage(s);

		free(d->Msg.Buffer);
		d->Msg.Length 			= 0;
		d->Msg.Buffer 			= NULL;

		d->MsgRXState 			= RX_Sync;
		return ERR_NONE;
	}

	return ERR_NONE;
}

static GSM_Error GNAPBUS_Initialise(GSM_StateMachine *s)
{
	GSM_Protocol_GNAPBUSData *d = &s->Protocol.Data.GNAPBUS;

	d->Msg.BufferUsed	= 0;
	d->Msg.Buffer 		= NULL;
	d->Msg.Length		= 0;

	d->MsgRXState 		= RX_Sync;

	return ERR_NONE;
}

static GSM_Error GNAPBUS_Terminate(GSM_StateMachine *s)
{
	free(s->Protocol.Data.GNAPBUS.Msg.Buffer);
	return ERR_NONE;
}

GSM_Protocol_Functions GNAPBUSProtocol = {
	GNAPBUS_WriteMessage,
	GNAPBUS_StateMachine,
	GNAPBUS_Initialise,
	GNAPBUS_Terminate
};

#endif

/* How should editor hadle tabs in this file? Add editor commands here.
 * vim: noexpandtab sw=8 ts=8 sts=8:
 */
