#include "TCPIPConfig.h"

#include "TCPIP Stack/TCPIP.h"
#include "TCPIP Stack/StackTsk.h"


#include <stdlib.h>
#include <ctype.h>
#include "GenericTypeDefs.h"
#include "HardwareProfile.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "lcd.h"
#include "usb_config.h"
#include "USB/usb.h"
#include "USB/usb_host_generic.h"
#include "../include/USB/timer.h"
#include "../USB/usb_host_local.h"
#include "TCPIP Stack/Tick.h"
#include "TCPIP Stack/StackTsk.h"
#include "MDD File System/FSIO.h"
#include "MDD File System/FSDefs.h"
#include <time.h>
#include "node.h"

// Application States
typedef enum
{
    USB_INITIALIZE = 0,                // Initialize the app when a device is attached
	USB_STATE_IDLE,                    // Inactive State
    USB_STATE_LOOP                    // Inactive State


} USB_STATE;


// *****************************************************************************
// *****************************************************************************
// Global Variables
// *****************************************************************************
// *****************************************************************************

AD_PARAM	AdParam;

extern BYTE		header[41], voice[12];
static BYTE        deviceAddress;  // Address of the device on the USB
static	USB_STATE	USBState;      // Current state of the application

static void	send_header_USB (BYTE pkt[]);
static void	send_voice_USB (BYTE pkt[], WORD seq);
static void	from_Inet(void );
static void	from_Rig(void);
static void	send_header_queue(void);
static void	send_voice_queue( void );
static BOOL callsign_check (BYTE CallSign[]);

static	ROM BYTE LastFrame[6] ={0x55,0x55,0x55,0x55,0xc8,0x7a};
static	BYTE LastFrameCheckRx[6];
static	BYTE LastFrameCheckTx[6];

static void	RF_CallsignDisp( BYTE header[]);
static void	RF_BlockedCallsignDisp(BYTE RFheader[]);
static void	Inet_CallsignDisp( BYTE header[]);
static void	Skip_CallsignDisp( BYTE header[]);
static	DWORD	usb_control_msg (BYTE bmRequestType, BYTE request, WORD Value, WORD Index, BYTE *data, WORD Length, WORD timeout);
static	void	LoadAdParam( void );
static	void	SaveAdParam( void );
void	vTaskDelay( portTickType xTicksToDelay );
static	void	CallDisplay(BYTE RFheader[]);


extern	BYTE	PicVer[2];
extern	WORD	DefaultVid;
extern	WORD	DefaultPid;
extern	BOOL	PTT_On;
extern	BOOL	COS_On;


extern	WORD	SSN;

static	BYTE	LCDText[32];

static	WORD 	seq;

static	BOOL	sendSW = FALSE;

void	JitterBufferInit(void);
void	JitterBufferSend (void);
void	JitterBufferSave (BYTE VoicePacket[], WORD tx_seq);

static	BYTE	JitterBuffer[84][12];		
static	WORD	VoicePacketCnt;
static	WORD	JitterBufferPnt;
static	WORD	JitterBufferSize = 84;
static	BOOL	VoicePacketSW;


//******************************************************************************
//******************************************************************************
// Local Routines
//******************************************************************************
//******************************************************************************

/*************************************************************************
 * Function:        CheckForNewAttach
 *
 * Preconditions:   None
 *
 * Input:           None
 *
 * Output:          deviceAddress (global)
 *                  Updates the device address when an attach is found.
 *
 * Returns:         TRUE if a new device has been attached.  FALSE,
 *                  otherwise.
 *
 * Side Effects:    Prints attach message
 *
 * Overview:        This routine checks to see if a new device has been
 *                  attached.  If it has, it records the address.
 *************************************************************************/

BOOL CheckForNewAttach ( void )
{
    // Try to get the device address, if we don't have one.
    if (deviceAddress == 0)
    {
        static	GENERIC_DEVICE_ID DevID;

        DevID.vid   = DefaultVid;
        DevID.pid   = DefaultPid;
        #ifdef USB_GENERIC_SUPPORT_SERIAL_NUMBERS
            DevID.serialNumberLength = 0;
            DevID.serialNumber = NULL;
        #endif

        if (USBHostGenericGetDeviceAddress(&DevID))
        {
            deviceAddress = DevID.deviceAddress;
            return TRUE;
        }
    }

    return FALSE;

} // CheckForNewAttach

/*************************************************************************
 * Function:        ManageDemoState
 *
 * Preconditions:   The DemoState global variable must be initialized to
 *                  USB_STATE_IDLE (0).  (This occurs on reset.)
 *
 * Input:           DemoState (global)
 *                  Actions selected based value of DemoState on function
 *                  entry.
 *
 *                  deviceAddress (global)
 *                  May use device address to access device, depending on
 *                  state.
 *
 *                  DataPacket (global)
 *                  May read data from packet buffer, depending on state.
 *
 * Output:          DemoState (global)
 *                  Updates demo state as appropriate.
 *
 *                  DataPacket (global)
 *                  May cause data in the packet buffer to be updated,
 *                  depending on state.
 *
 * Returns:         None
 *
 * Side Effects:    Depend on state transition
 *
 * Overview:        This routine maintains the state of the application,
 *                  updateing global data and taking actions as necessary
 *                  to maintain the custom demo operations.
 *************************************************************************/
static void ManageState ( void )
{
	static	BYTE	*pDesc;

    // Watch for device detaching
    if (USBHostGenericDeviceDetached(deviceAddress) && deviceAddress != 0)
    {
        USBState = USB_INITIALIZE;
        deviceAddress   = 0;
		memcpy (LCDText, "device detached " "                ", 32);
		xMessage.pcMessage = (char *)&LCDText;
 		xMessage.xMinDisplayTime = 3000 / portTICK_RATE_MS;
		xQueueSend( xLCDQueue, &xMessage, 0 );
    }

    switch (USBState)
    {
  		case USB_STATE_LOOP:
//			if (!VoicePacketCnt) from_Rig();
//			if (!COS_On) from_Inet();	 	/* check message queue from Inet */

			from_Rig();
			from_Inet();
			if (AdParam.UpdateFlag == 0x02) SaveAdParam();
			else if (AdParam.UpdateFlag == 0x00) LoadAdParam();
			break;

    	case USB_INITIALIZE:
        	USBState = USB_STATE_IDLE;
        	break;

    	case USB_STATE_IDLE:
        	if (CheckForNewAttach())
        	{
				pDesc  = USBHostGetDeviceDescriptor(1);
		    	if (pDesc)
				{
	       			USBState = USB_STATE_LOOP;
					pDesc += 12;
					PicVer[1] = *pDesc++;
					PicVer[0] = *pDesc;
					LoadAdParam();
        		}
			}
       		break;
    }
} // ManageDemoState


//******************************************************************************
//******************************************************************************
// USB Support Functions
//******************************************************************************
//******************************************************************************

/*************************************************************************
 * Function:        USB_ApplicationEventHandler
 *
 * Preconditions:   The USB must be initialized.
 *
 * Input:           event       Identifies the bus event that occured
 *
 *                  data        Pointer to event-specific data
 *
 *                  size        Size of the event-specific data
 *
 * Output:          deviceAddress (global)
 *                  Updates device address when an attach or detach occurs.
 *
 *                  DemoState (global)
 *                  Updates the demo state as appropriate when events occur.
 *
 * Returns:         TRUE if the event was handled, FALSE if not
 *
 * Side Effects:    Event-specific actions have been taken.
 *
 * Overview:        This routine is called by the Host layer or client
 *                  driver to notify the application of events that occur.
 *                  If the event is recognized, it is handled and the
 *                  routine returns TRUE.  Otherwise, it is ignored (or
 *                  just "sniffed" and the routine returns FALSE.
 *************************************************************************/

BOOL USB_ApplicationEventHandler ( BYTE address, USB_EVENT event, void *data, DWORD size )
{
	static	BYTE	*pDesc;

	// Handle specific events.
    switch (event)
    {
        case EVENT_GENERIC_ATTACH:
            if (size == sizeof(GENERIC_DEVICE_ID))
            {
                deviceAddress   = ((GENERIC_DEVICE_ID *)data)->deviceAddress;
                USBState = USB_STATE_LOOP;
				pDesc = USBHostGetDeviceDescriptor(deviceAddress);
				pDesc += 12;
				PicVer[1] = *pDesc;
				PicVer[0] = *(pDesc + 1);
		
                return TRUE;
            }
            break;

//        case EVENT_GENERIC_DETACH:
//            deviceAddress   = 0;
//            USBState = USB_INITIALIZE;
//            return TRUE;
//
//        case EVENT_GENERIC_TX_DONE:           // The main state machine will poll the driver.
//        case EVENT_GENERIC_RX_DONE:
//            return TRUE;
//
       case EVENT_VBUS_REQUEST_POWER:
            // We'll let anything attach.
            return TRUE;

        case EVENT_VBUS_RELEASE_POWER:
            // We aren't keeping track of power.
            return TRUE;

        case EVENT_HUB_ATTACH:
//            UART2PrintString( "\r\n***** USB Error - hubs are not supported *****\r\n" );
            return TRUE;
            break;

        case EVENT_UNSUPPORTED_DEVICE:
//            UART2PrintString( "\r\n***** USB Error - device is not supported *****\r\n" );
            return TRUE;
            break;

        case EVENT_CANNOT_ENUMERATE:
//            UART2PrintString( "\r\n***** USB Error - cannot enumerate device *****\r\n" );
            return TRUE;
            break;

        case EVENT_CLIENT_INIT_ERROR:
//            UART2PrintString( "\r\n***** USB Error - client driver initialization error *****\r\n" );
            return TRUE;
            break;

        case EVENT_OUT_OF_MEMORY:
//            UART2PrintString( "\r\n***** USB Error - out of heap memory *****\r\n" );
            return TRUE;
            break;

        case EVENT_UNSPECIFIED_ERROR:   // This should never be generated.
//            UART2PrintString( "\r\n***** USB Error - unspecified *****\r\n" );
            return TRUE;
            break;

        case EVENT_SUSPEND:
        case EVENT_DETACH:
        case EVENT_RESUME:
        case EVENT_BUS_ERROR:
            return TRUE;
            break;

        default:
            break;
    }

    return FALSE;

} // USB_ApplicationEventHandler



/*************************************************************************
 * Function:        main
 *
 * Preconditions:   None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Returns:         Never exits
 *
 * Side Effects:    Runs the application
 *
 * Overview:        This is the USB Custom Demo Application's main entry
 *                  point.
 *************************************************************************/

int prvTaskUSB ( void )
{
   // Initialize the processor and peripherals.
    USBState = USB_INITIALIZE;
	AdParam.UpdateFlag = 0x00;
	static	BYTE	LCDText[32];	

    if ( USBHostInit(0) == TRUE )
    {
			memcpy (LCDText, "USB Interface   " "     Initialized", 32);
			xMessage.pcMessage = (char *)&LCDText;
	 		xMessage.xMinDisplayTime = 500 / portTICK_RATE_MS;
			xQueueSend( xLCDQueue, &xMessage, 0 );
    }
    else
    {
//        printf ( "\r\n\r\nCould not initialize USB Custom Demo App - USB.  Halting.\r\n\r\n" );
        while (1);
    }

	LED2_TRIS = 0;		/* output */

	JitterBufferInit();

    // Main Processing Loop
    while (1)
    {
        // This demo does not check for overcurrent conditions.  See the
        // USB Host - Data Logger for an example of overcurrent detection
        // with the PIC24F and the USB PICtail Plus.

        // Maintain USB Host State
        USBHostTasks();
        // Maintain Demo Application State
        ManageState();
    }

    return 0;

} // main

/**************************************************************/
/*  From INET */
void	from_Inet()
{
	static	packet	q_pkt;
	extern	xQueueHandle xDstarRcvQueue;
	static	WORD	tx_seq;

	while (xQueueReceive (xDstarRcvQueue, &q_pkt, 0) == pdTRUE)
	{
		tx_seq = q_pkt.seq_high * 256 + q_pkt.seq_low; 
		if (q_pkt.type_id == 0x10) send_header_USB(q_pkt.body);
		else if (q_pkt.type_id == 0x20) send_voice_USB(q_pkt.body, tx_seq);
	}
	if (VoicePacketSW && VoicePacketCnt) JitterBufferSend();

}

static void	send_header_USB(BYTE pkt[])
{
	extern	xQueueHandle xDstarRcvQueue;

	if (AppConfig.Flags.RepeaterAcc)
	{
		if (!(pkt[0] & 0x40)) /* Dup on */
		{
			Skip_CallsignDisp (pkt);
			sendSW = FALSE;
			return;
		}
	}
	sendSW = TRUE;
		
	/* Callsign set */
    usb_control_msg(0x40, SET_MyCALL2, 0, 0, &pkt[35], 4, 100);
	usb_control_msg(0x40, SET_MyCALL, 0, 0, &pkt[27], 8, 100);
	usb_control_msg(0x40, SET_YourCALL, 0, 0, &pkt[19], 8, 100);
	usb_control_msg(0x40, SET_RPT1CALL, 0, 0, &pkt[11], 8, 100);
	usb_control_msg(0x40, SET_RPT2CALL, 0, 0, &pkt[3], 8, 100);
    usb_control_msg(0x40, SET_FLAGS, 0, 0, &pkt[0], 3, 100);

	Inet_CallsignDisp (pkt);

	VoicePacketCnt = 0;
	JitterBufferPnt = 0;
	VoicePacketSW = FALSE;
	PTT_On = FALSE;
}

void	send_voice_USB (BYTE pkt[], WORD seq)
{
	static	BYTE	dummy;
	static	BYTE	i;

	if (sendSW)
	{
		JitterBufferSave (pkt, seq); 
	}
	for (i = 0 ; i < 12 ; i++)
	{
		LastFrameCheckTx[0] = LastFrameCheckTx[1];
		LastFrameCheckTx[1] = LastFrameCheckTx[2];
		LastFrameCheckTx[2] = LastFrameCheckTx[3];
		LastFrameCheckTx[3] = LastFrameCheckTx[4];
		LastFrameCheckTx[4] = LastFrameCheckTx[5];
		LastFrameCheckTx[5] = pkt[i];
		if (!memcmp(LastFrameCheckTx, LastFrame, 6))
		{
			VoicePacketSW = TRUE;
			while (VoicePacketCnt) JitterBufferSend ();
			VoicePacketCnt = 0;
			JitterBufferPnt = 0;
			/* PTT OFF */
			usb_control_msg(0x40, SET_PTT, OFF, 0, &dummy, 0, 100);
			PTT_On = FALSE;
			VoicePacketSW = FALSE;
			LED2_IO = 0;
			return;
		}
	}
}

/*************************************************/
/*  From RIG */
static	void	from_Rig()
{
	static	BYTE ssn_temp[2];
	static	DWORD length;
	static	DWORD ret;
	static	WORD	i;
	static	WORD 	voice_pnt;
	extern	BOOL	headerRead;
	extern	BYTE	rig_buffer[32];
	static	BYTE	status;

	/* rf header send */
	if (!headerRead)
	{
		ret = usb_control_msg (0xC0, GET_HEADER, 0, 0, header, 32, 100);
        if (ret != 32)
		{
			return;  /*RF header read? */
		}
        usb_control_msg (0xC0, GET_HEADER, 0, 0, &header[32], 9, 100);
  		usb_control_msg (0xC0, GET_SN_VALUE, 0, 0, ssn_temp, 2, 100);
		SSN = ssn_temp[0] * 4 + (ssn_temp[1] >> 6);
		if (!callsign_check(&header[27]))
		{
			RF_BlockedCallsignDisp(header);
			return;
		}
		RF_CallsignDisp(header);
		send_header_queue();
		headerRead = TRUE;
		voice_pnt = 0;
		COS_On = TRUE;
	} else {
		/* rf voice read */
		length = usb_control_msg (0xC0, GET_DATA, 0, 0, rig_buffer, 32, 100);
		if ((length <= 32 ) && (length > 0))
		{	
			for (i = 0 ; i < length ; i++)
			{
				voice[voice_pnt] = rig_buffer[i];
				voice_pnt++;
				LastFrameCheckRx[0] = LastFrameCheckRx[1]; 
				LastFrameCheckRx[1] = LastFrameCheckRx[2]; 
				LastFrameCheckRx[2] = LastFrameCheckRx[3]; 
				LastFrameCheckRx[3] = LastFrameCheckRx[4]; 
				LastFrameCheckRx[4] = LastFrameCheckRx[5];
				LastFrameCheckRx[5] = rig_buffer[i];
 
				if (!memcmp(LastFrameCheckRx, LastFrame, 6))
				{
					send_voice_queue();
					headerRead = FALSE;
					COS_On = FALSE;
					LED2_IO = 0;
					return;
				}

				if (voice_pnt == 12)
				{
					send_voice_queue();
					voice_pnt = 0;
					LED2_IO ^= 1;
				}
			}
		} else if (length == 0)
		{
			usb_control_msg (0xC0, GET_AD_STATUS, 0, 0, &status, 1, 100);
			if (!(status & COS_OnOff))
			{
				headerRead = FALSE;
				COS_On = FALSE;
				return;
			}
		}
		usb_control_msg (0xC0, GET_AD_STATUS, 0, 0, &status, 1, 100);
		if (status & HeaderDecodeDone)
		{
				headerRead = FALSE;
				COS_On = FALSE;
				return;
		}
	}
}


static	void	send_voice_queue() 	/* read from rig (DV packet) */
{
	static	packet pkt;
	extern	xQueueHandle xDstarSndQueue;
	extern	BYTE voice[12];
	static	BYTE ssn_temp[2];

	memcpy (pkt.body, voice, 12);
	memcpy (pkt.id,  "DVND" ,4);
	pkt.type_id = 0x20;			/* voice */
	pkt.dest_repeater_id = 0x20;
	pkt.send_repeater_id = 'N';
	pkt.send_terminal_id = 'E';;
	pkt.seq_high = seq >> 8;
	pkt.seq_low = seq & 0xff;
	seq++;
	usb_control_msg (0xC0, GET_SN_VALUE, 0, 0, ssn_temp, 2, 100);
	SSN = ssn_temp[0] * 4 + (ssn_temp[1] >> 6);

	if (seq >= 2100) seq = 0;  /* 2 sec. */							
	xQueueSend (xDstarSndQueue, &pkt, 20 / portTICK_RATE_MS);
}


static	void	send_header_queue() 	/* read from rig (DV packet) */
{
	extern BYTE header[41];
	extern xQueueHandle xDstarSndQueue;
	extern	WORD	SSN;
	static	packet pkt;
	call_table call_pkt;

/* RF header send */
		call_pkt.ssn = SSN;
//		send_dv_callEntry (call_pkt);


		memcpy (pkt.body, header, 41);
		memcpy (pkt.id,  "DVND" ,4);
		pkt.type_id = 0x10;		/* header */
		pkt.dest_repeater_id = 0x20;
		pkt.send_repeater_id = 'N';
		pkt.send_terminal_id = 'E';;
		pkt.seq_high = 0;
		pkt.seq_low = 0;
		xQueueSend (xDstarSndQueue, &pkt, 20 / portTICK_RATE_MS);
		seq	= 0;
		return;
}

static	void	RF_CallsignDisp(BYTE RFheader[])
{

		memset (LCDText, 0x20, 32);
		memcpy (&LCDText[27], "Radio", 5);
		CallDisplay(RFheader);
	return;
}

static	void	RF_BlockedCallsignDisp(BYTE RFheader[])
{
		memset (LCDText, 0x20, 32);
		memcpy (&LCDText[27], " Deny", 5);
		CallDisplay(RFheader);
	return;
}

static	void	Inet_CallsignDisp(BYTE RFheader[])
{
		memset (LCDText, 0x20, 32);
		memcpy (&LCDText[27]," Inet",5);
		CallDisplay(RFheader);
	return;
}

static	void	Skip_CallsignDisp(BYTE RFheader[])
{
		memset (LCDText, 0x20, 32);
		memcpy (&LCDText[27]," Skip",5);
		CallDisplay(RFheader);
	return;
}

static	void	CallDisplay (BYTE RFheader[])
{
	static	xLCDMessage xMessage;
	extern	xQueueHandle xLCDQueue;
	static	ROM BYTE hex[16] = {"0123456789ABCDEF"};

		memcpy (&LCDText[0],&RFheader[27], 8);
		LCDText[14] = hex[RFheader[0]>>4];
		LCDText[15] = hex[RFheader[0] & 0x0f];
		memcpy (&LCDText[16],&RFheader[19], 8);
		if (memcmp (&RFheader[35],"    ",4))
		{
			LCDText[8] = '/';
			memcpy (&LCDText[9],&RFheader[35], 4);
		}
		xMessage.pcMessage = (char *)&LCDText;
 		xMessage.xMinDisplayTime = 1000 / portTICK_RATE_MS;
		xQueueSend( xLCDQueue, &xMessage, 0 );
	return;
}

static	DWORD  usb_control_msg (BYTE bmRequestType, BYTE bRequest, WORD wValue, WORD wIndex, BYTE *data, WORD wLength, WORD timeout)
{
	static	DWORD byteCount;
	static	BYTE errorCode;
	static	BYTE RetCode;
	static	DWORD dwRetCode;

	if (bmRequestType & 0x80)
	{
		RetCode = USBHostIssueDeviceRequest( 1, bmRequestType, bRequest, wValue, wIndex, wLength, data, USB_DEVICE_REQUEST_GET, 0xff);
		if (RetCode== USB_SUCCESS)
		{
			if (timeout == 0)
			{
				return 0ul;
			}
			while (!USBHostTransferIsComplete( 1, 0, &errorCode, &byteCount)) ;
			return byteCount;
		} else if (RetCode == USB_ENDPOINT_BUSY) return 0ul;
		else
		{
			dwRetCode = RetCode + 1000;
			return dwRetCode;
		}
	} else {
		RetCode = USBHostIssueDeviceRequest( 1, bmRequestType, bRequest, wValue, wIndex, wLength, data, USB_DEVICE_REQUEST_SET, 0xff);
		if (RetCode == USB_SUCCESS)
		{
			if (timeout == 0)
			{
				if (USBHostTransferIsComplete( 1, 0, &errorCode, &byteCount)) return byteCount;
				else return 1021ul;
			}
			while (!USBHostTransferIsComplete( 1, 0, &errorCode, &byteCount )) ;
			return byteCount;
		} else if (RetCode == USB_ENDPOINT_BUSY) return 1000ul;
		else return 1020ul;
	}
	return byteCount;
}


static void	LoadAdParam()
{
	static BYTE dummy;

		AdParam.UpdateFlag = 0x01;
  	    usb_control_msg (0xC0, GET_DelayTime, 0, 0, &AdParam.DelayTime, 1, 100);
  	    usb_control_msg (0xC0, GET_TimeOut, 0, 0, &AdParam.TimeOut, 1, 100);
  	    usb_control_msg (0xC0, GET_KeepAlive, 0, 0, &AdParam.KeepAlive, 1, 100);	
  	    usb_control_msg (0xC0, GET_JitterBufferSize, 0, 0, &AdParam.JitterSize, 1, 100);	
  	    usb_control_msg (0xC0, GET_MODE, 0, 0, &AdParam.Mode, 1, 100);	
  	    usb_control_msg (0xC0, GET_MODE2, 0, 0, &AdParam.Mode2, 1, 100);	
  	    usb_control_msg (0xC0, GET_INVERT_STATUS, 0, 0, &AdParam.Invert, 1, 100);	
  	    usb_control_msg (0xC0, GET_SN_SQ, 0, 0, (BYTE *)&AdParam.SN_Squelch, 2, 100);	

  	    usb_control_msg (0xC0, GET_BeaconMessageInit, 0, 0, &dummy, 0, 100);	
  	    usb_control_msg (0xC0, GET_BeaconMessage, 0, 0, (BYTE *)&AdParam.BeaconMessage, 20, 100);	
  	    usb_control_msg (0xC0, GET_BeaconTimer, 0, 0, &AdParam.BeaconInterval, 1, 100);	

  	    usb_control_msg (0xC0, GET_AltMyCall, 0, 0, (BYTE *)&AdParam.AltMyCall, 8, 100);	
  	    usb_control_msg (0xC0, GET_AltMyCall2, 0, 0, (BYTE *)&AdParam.AltMyCall2, 4, 100);	
  	    usb_control_msg (0xC0, GET_AltYourCall, 0, 0, (BYTE *)&AdParam.AltYourCall, 8, 100);	
  	    usb_control_msg (0xC0, GET_AltRPT1Call, 0, 0, (BYTE *)&AdParam.AltRPT1Call, 8, 100);	
  	    usb_control_msg (0xC0, GET_AltRPT2Call, 0, 0, (BYTE *)&AdParam.AltRPT2Call, 8, 100);
  	    usb_control_msg (0xC0, GET_RepeaterMode, 0, 0, (BYTE *)&AdParam.AltFlags, 3, 100);
	
}

static	void	SaveAdParam()
{
	static	BYTE	dummy;
	static	DWORD	ret, k;
	static	WORD	i;

  	    ret = usb_control_msg (0x40, SET_DelayTime, AdParam.DelayTime, 0, &dummy, 0, 100);
  	    ret = usb_control_msg (0x40, SET_TimeOut, AdParam.TimeOut, 0, &dummy, 0, 100);
  	    ret = usb_control_msg (0x40, SET_KeepAlive, AdParam.KeepAlive, 0, &dummy, 0, 100);	
  	    ret = usb_control_msg (0x40, SET_JitterBufferSize, AdParam.JitterSize, 0, &dummy, 0, 100);	
		if (AdParam.Mode & 0x02)
		{
			usb_control_msg(0x40, SET_CRC_CHECK, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg(0x40, SET_CRC_CHECK, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Mode & 0x04)
		{
			usb_control_msg (0x40, SET_COS_CHECK, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_COS_CHECK, OFF, 0, &dummy, 0, 100);
		}	
		if (AdParam.Mode & 0x08)
		{
			usb_control_msg (0x40, SET_LastFrame, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_LastFrame, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Mode & 0x80)
		{
			usb_control_msg (0x40, SET_HalfFull, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_HalfFull, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Mode2 & 0x01)
		{
			usb_control_msg (0x40, SET_HeaderGen, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_HeaderGen, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Mode2 & 0x02)
		{
			usb_control_msg (0x40, SET_HeaderGenType, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_HeaderGenType, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Mode2 & 0x04)
		{
			usb_control_msg (0x40, SET_HeaderRep, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_HeaderRep, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Invert & 0x80)
		{
			usb_control_msg (0x40, SET_AutoRxDetect, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_AutoRxDetect, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Invert & 0x01)
		{
			usb_control_msg (0x40, SET_TX_Invert, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_TX_Invert, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.Invert & 0x02)
		{
			usb_control_msg (0x40, SET_RX_Invert, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_RX_Invert, OFF, 0, &dummy, 0, 100);
		}
  	    ret = usb_control_msg (0x40, SET_SN_SQ, AdParam.SN_Squelch, 0, &dummy, 0, 100);	

  	    usb_control_msg (0x40, SET_SlowDataSetInit, 0, 0, &dummy, 0, 100);	
  	    usb_control_msg (0x40, SET_BeaconMessage, 0, 0, (BYTE *)&AdParam.BeaconMessage, 20, 100);
		k = AdParam.BeaconInterval;	
  	    usb_control_msg (0x40, SET_BeaconTimer, k, 0, &dummy, 0, 100);	

  	    usb_control_msg (0x40, SET_AltMyCall, 0, 0, (BYTE *)&AdParam.AltMyCall, 8, 100);	
  	    usb_control_msg (0x40, SET_AltMyCall2, 0, 0, (BYTE *)&AdParam.AltMyCall2, 4, 100);	
  	    usb_control_msg (0x40, SET_AltYourCall, 0, 0, (BYTE *)&AdParam.AltYourCall, 8, 100);	
  	    usb_control_msg (0x40, SET_AltRPT1Call, 0, 0, (BYTE *)&AdParam.AltRPT1Call, 8, 100);	
  	    usb_control_msg (0x40, SET_AltRPT2Call, 0, 0, (BYTE *)&AdParam.AltRPT2Call, 8, 100);
		i = AdParam.AltFlags[2];
  	    usb_control_msg (0x40, SET_AltFlagSet, i, 0, &dummy, 0, 100);

		if (AdParam.AltFlags[0] & 0x08)
		{
			usb_control_msg (0x40, SET_AltMyCallSet, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_AltMyCallSet, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.AltFlags[0] & 0x10)
		{
			usb_control_msg (0x40, SET_AltMyCall2Set, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_AltMyCall2Set, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.AltFlags[0] & 0x20)
		{
			usb_control_msg (0x40, SET_AltYourCallSet, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_AltYourCallSet, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.AltFlags[0] & 0x40)
		{
			usb_control_msg (0x40, SET_AltRPT1CallSet, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_AltRPT1CallSet, OFF, 0, &dummy, 0, 100);
		}
		if (AdParam.AltFlags[0] & 0x80)
		{
			usb_control_msg (0x40, SET_AltRPT2CallSet, ON, 0, &dummy, 0, 100);
		} else {
			usb_control_msg (0x40, SET_AltRPT2CallSet, OFF, 0, &dummy, 0, 100);
		}

		AdParam.UpdateFlag = 0x00;
			
}

static	BOOL	callsign_check (BYTE CallSign[])	/* MyCallSign field Check */
{
	static	FSFILE	*accctl;
	static	char	buf[128],str[128];
	static	char	*token;
	static	WORD	length, len, i, k;
	static	xLCDMessage xMessage;
	extern	xQueueHandle xLCDQueue;


	accctl = NULL;

	if (AppConfig.AccessCtrl != NULL)
	{
		len = strlen ((void *)AppConfig.AccessCtrl);
		memcpy (str, AppConfig.AccessCtrl, len);
		str[len] = 0x00;
		k = 999;
		for (i = 0 ; i < len ; i++)
		{
			if (str[i] == '.') k = i;
		}
		if (k <= 8)
		{
			if (len - k <= 4)
			{
				for (i = 0 ; i < len ; i++)
				{
					str[i] = toupper(str[i]);
				}
			}
		} 

		accctl = FSfopen (str,"r");
	} else {
		return TRUE;
	}
	if (accctl == NULL)
	{
			len = strlen ((void *)AppConfig.AccessCtrl);
			if (len > 16) len = 16;
			memset (LCDText, 0x20, 32);
			memcpy (&LCDText[0],"file not found  ", 16);
			memcpy (&LCDText[16], AppConfig.AccessCtrl, len);
			xMessage.pcMessage = (char *)&LCDText[0];
 			xMessage.xMinDisplayTime = 3000 / portTICK_RATE_MS;
			xQueueSend( xLCDQueue, &xMessage, 0 );
			vTaskDelay(3000 / portTICK_RATE_MS);
			return FALSE;
	}
	
	len = FSfread (buf, 128, 1,  accctl);
	while (len)
	{
		strcpy ((char *)str, (char *)buf);
		if (str[strlen((void *)str)-1] == 0x0a) str[strlen((void *)str)-1] = 0x00;
		token = str;
		for (i = 0 ; i < strlen((void *)str) ; i++)
		{
			*token = toupper (*token);
			token++;
		}
		length = 8;
		for (i = 0 ; i <= 7 ; i++)
		{
			if (str[7-i] == '*')
			{
				length = 7 - i;
				break;
			}		
		}
		if (length == 0) length = 8;

			if (!memcmp (str, "*", 1))
			{
				if (!memcmp(&str[8],"DENY",4))
				{
					FSfclose (accctl);
					return FALSE;
				}
				if (!memcmp(&str[8],"ALLOW",5))
				{
					FSfclose (accctl);
					return TRUE;
				}
			} else if (!memcmp (str, CallSign, length))
			{ 
				if (!memcmp(&str[8],"DENY",4))
				{
					FSfclose (accctl);
					return FALSE;
				}
				if (!memcmp(&str[8],"ALLOW",5))
				{
					FSfclose (accctl);
					return TRUE;
				}
			}
		len = FSfread (buf, 128, 1,  accctl);
	}
	FSfclose (accctl);
	return FALSE;
	
}

/* Jitter Buffer */
void	JitterBufferInit()
{
	int	i;
	static ROM BYTE	NullVoice0[12] = {0x9e,0x8d,0x32,0x88,0x26,0x1a,0x3f,0x61,0xe8,0x55,0x2d,0x16};
	static ROM BYTE	NullVoice1[12] = {0x9e,0x8d,0x32,0x88,0x26,0x1a,0x3f,0x61,0xe8,0x16,0x29,0xf5};


	for (i = 0 ; i < JitterBufferSize ; i++)
	{
		if (i%21 == 0)
		{
			memcpy (&JitterBuffer[i][0], NullVoice0, 12);
		} else {
			memcpy (&JitterBuffer[i][0], NullVoice1, 12);
		}
	}
	JitterBufferPnt = 0;
	VoicePacketCnt = 0;
	VoicePacketSW = FALSE;
	PTT_On = FALSE;
}

void	JitterBufferSave (BYTE VoicePacket[], WORD sequence)
{
	memcpy (&JitterBuffer[sequence%JitterBufferSize][0], VoicePacket, 12);
	VoicePacketCnt++;
	if (VoicePacketCnt > AppConfig.JitterBufferWait) VoicePacketSW = TRUE;
}

void	JitterBufferSend ()
{
	static	BYTE	len;
	static	BYTE	dummy;
	extern	BOOL	headerRead;


	if (!PTT_On)
	{
		if (headerRead)
		{
			sendSW = FALSE;
			JitterBufferPnt = 0;
			VoicePacketCnt = 0;
			VoicePacketSW = FALSE;
			return;
		}	
		while (1)
		{
		   	usb_control_msg(0xC0, GET_REMAINSPACE, 0, 0, &len ,1, 100);
			if (len >=95)
			{
				usb_control_msg(0x40, SET_PTT, ON, 0, &dummy, 0, 100);
				PTT_On = TRUE;
				vTaskDelay (100 / portTICK_RATE_MS);
				break;
			} else {
				vTaskDelay (200 / portTICK_RATE_MS);
			}
		}
	}	

	while (1)
	{	
	   	usb_control_msg(0xC0, GET_REMAINSPACE, 0, 0, &len ,1, 100);
		if (len >= 12)
		{
   			usb_control_msg(0x40, PUT_DATA, 0, 0, &JitterBuffer[JitterBufferPnt][0],12, 100);
			VoicePacketCnt--;
			JitterBufferPnt++;
			if (JitterBufferPnt >= JitterBufferSize) JitterBufferPnt = 0;
			return;
		} else {
			vTaskDelay (50 / portTICK_RATE_MS);
		}
	}
}

/*************************************************************************
 * EOF main.c
 */

