// Open source PIC USB stack echo demo
// USB stack by JTR and Honken
// CC-BY
//
// USB driver files should be in '..\dp_usb\'
// Enter a USB VID and PID in prj_usb_config.h

//USB stack
#include "../dp_usb/usb_stack_globals.h"    // USB stack only defines Not function related.
#include "descriptors.h"	// JTR Only included in main.c
//#include "configwords.h"	// JTR only included in main.c
#include "fraisemaster.h"
#include "stdio.h"

// PIC18F Move reset vectors for bootloader compatibility
#ifdef __18CXX
	#define REMAPPED_RESET_VECTOR_ADDRESS		0x800
	#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x808
	#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x818
#endif

void SetupBoard(void);
void InterruptHandlerHigh();
void InterruptHandlerLow();
void USBSuspend(void);

int _user_putc(char c)
{
   putc_cdc(c);
}

#pragma udata
extern BYTE usb_device_state;

//BYTE LineFromUsb[96];
//BYTE LineFromUsbLen=0;
//#pragma udata accessram
volatile BYTE SofFlag;

#pragma code

void SOFHandler(void)
{
    //static BYTE il;

    //if(il++==200) { il=0; mLED_2_Toggle(); }
    SofFlag=1;
    CDCFlushOnTimeout();
}


#ifdef PIC_18F
void main(void)
#else
int main(void)
#endif
{
    BYTE RecvdByte;
        long int jj;

    stdout = _H_USER; // Use our own special output function for STDOUT

    initCDC(); // setup the CDC state machine
    SetupBoard(); //setup the hardware, customize for your hardware
    usb_init(cdc_device_descriptor, cdc_config_descriptor, cdc_str_descs, USB_NUM_STRINGS); // initialize USB. TODO: Remove magic with macro
    usb_start(); //start the USB peripheral
    


// PIC18 INTERRUPTS
// It is the users resposibility to set up high, low or legacy mode
// interrupt operation. The following macros for high and low interrupt
// setup have been removed:

#define EnableUsbHighPriInterrupt()             do { RCONbits.IPEN = 1; IPR2bits.USBIP = 1; INTCONbits.GIEH = 1;} while(0) // JTR new
#define EnableUsbLowPriInterrupt()              do { RCONbits.IPEN = 1; IPR2bits.USBIP = 0; INTCONbits.GIEL = 1;} while(0)  // JTR new

// By default, the interrupt mode will be LEGACY (ISR Vector 0x08)
// (Same as high priority vector wise but the operation (latency) is
// not the same. Consult the data sheet for details.)

// If a priority mode is enabled then this affects ALL other interrupt
// sources therefore it does not belong to the usb stack to be
// doing this. It is a global, user application choice.

#if defined USB_INTERRUPTS // See the prj_usb_config.h file.
    EnableUsbPerifInterrupts(USB_TRN + USB_SOF + USB_UERR + USB_URST);
#if defined __18CXX //turn on interrupts for PIC18
    //EnableUsbHighPriInterrupt();
    EnableUsbLowPriInterrupt();
    INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;
#endif
    EnableUsbGlobalInterrupt(); // Only enables global USB interrupt. Chip interrupts must be enabled by the user (PIC18)
#endif


// Wait for USB to connect
    do {
#ifndef USB_INTERRUPTS
        usb_handler();
#endif
    } while (usb_device_state < CONFIGURED_STATE);

    usb_register_sof_handler(SOFHandler); // Register our CDC timeout handler after device configured
    //usb_register_sof_handler(CDCFlushOnTimeout); // Register our CDC timeout handler after device configured
    
    FraiseInit();

// Main echo loop
    do {

// If USB_INTERRUPT is not defined each loop should have at least one additional call to the usb handler to allow for control transfers.
#ifndef USB_INTERRUPTS
        usb_handler();
#endif

// Receive and send method 1
// The CDC module will call usb_handler each time a BULK CDC packet is sent or received.
// If there is a byte ready will return with the number of bytes available and received byte in RecvdByte
        /*if (poll_getc_cdc(&RecvdByte))
            putc_cdc(RecvdByte); */
            
        if(!FrGotLineFromUsb) {
            while(poll_getc_cdc(&RecvdByte)) {
                if(RecvdByte=='\n') {
                    FrGotLineFromUsb=1;
                    //printf((const far rom char*)"rcvd line !\n");
                    break;
                }
                else if(LineFromUsbLen<(sizeof(LineFromUsb)-1))
                    LineFromUsb[LineFromUsbLen++]=RecvdByte;
            }
        }

        if(SofFlag==1) { FraiseSOF(); SofFlag=0; }

        FraiseService();


        /*if(!UserSW) { //goto booloader... doesn't work well... bouhou !
            INTCONbits.GIEH=0;
            INTCONbits.GIEL=0;
            //SuspendUsb();
            //UCONbits.USBEN = 0;
            UCFGbits.UPUEN=0;
            UCFGbits.UTRDIS=1;
            mLED_2_On();
            while(jj++<600000) ;
            mLED_2_Off();
            while(jj++<600000) ;
            Reset();
        }*/
        //while(!UserSW);
// Receive and send method 2
// Same as poll_getc_cdc except that byte is NOT removed from queue.
// This function will wait for a byte and return and remove it from the queue when it arrives.
        /*if (peek_getc_cdc(&RecvdByte)) {
            RecvdByte = getc_cdc(); 
            putc_cdc(RecvdByte+1);
        }*/

// Receive and send method 3
// If there is a byte ready will return with the number of bytes available and received byte in RecvdByte
// use CDC_Flush_In_Now(); when it has to be sent immediately and not wait for a timeout condition.
      /*  if (poll_getc_cdc(&RecvdByte)) {
            putc_cdc(RecvdByte+1); //
            CDC_Flush_In_Now(); 
        }*/
    } while (1);

} //end main

//board hardware setup
//add your hardware here
void SetupBoard(void) {

#if defined (PIEDUSB)
    //disable some defaults
    ADCON1 |= 0b1111; //all pins digital
    CVRCON = 0b00000000;
    LATC = 0x00;
    TRISC = 0xFF;
#endif

}

// USB suspend not yet enabled
void USBSuspend(void) {}

//interrupt routines for PIC 18 and PIC24
#if defined(USB_INTERRUPTS)

//PIC 24F type USB interrupts
#if defined(__PIC24FJ64GB106__) || defined(__PIC24FJ128GB106__) || defined(__PIC24FJ192GB106__) || defined(__PIC24FJ256GB106__) || defined(__PIC24FJ64GB108__) || defined(__PIC24FJ128GB108__) || defined(__PIC24FJ192GB108__) || defined(__PIC24FJ256GB108__) || defined(__PIC24FJ64GB110__) || defined(__PIC24FJ128GB110__) || defined(__PIC24FJ192GB110__) || defined(__PIC24FJ256GB110__) 
#pragma interrupt _USB1Interrupt
void __attribute__((interrupt, auto_psv)) _USB1Interrupt() {
    //USB interrupt
    //IRQ enable IEC5bits.USB1IE
    //IRQ flag	IFS5bits.USB1IF
    //IRQ priority IPC21<10:8>
    usb_handler();
    ClearGlobalUsbInterruptFlag();
}
#elif defined (__18CXX) //PIC18F style interrupts with remapping for bootloader
//	Interrupt remap chain
//
//This function directs the interrupt to
// the proper function depending on the mode
// set in the mode variable.
//USB stack on low priority interrupts,
#pragma interruptlow InterruptHandlerLow nosave= PROD, PCLATH, PCLATU, TBLPTR, TBLPTRU, TABLAT, section (".tmpdata"), section("MATH_DATA")
void InterruptHandlerLow(void) {
    usb_handler();
    ClearGlobalUsbInterruptFlag();
    //FraiseISR();
}

#pragma interrupt InterruptHandlerHigh nosave= PROD, PCLATH, PCLATU, TBLPTR, TBLPTRU, TABLAT, section (".tmpdata"), section("MATH_DATA")
void InterruptHandlerHigh(void) { //Also legacy mode interrupt.
    //usb_handler();
    //ClearGlobalUsbInterruptFlag();
    FraiseISR();
}

//these statements remap the vector to our function
//When the interrupt fires the PIC checks here for directions
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS

void Remapped_High_ISR(void) {
    _asm goto InterruptHandlerHigh _endasm
}

#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS

void Remapped_Low_ISR(void) {
    _asm goto InterruptHandlerLow _endasm
}

//relocate the reset vector
extern void _startup(void);
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS

void _reset(void) {
    _asm goto _startup _endasm
}
//set the initial vectors so this works without the bootloader too.
#if 0
#pragma code HIGH_INTERRUPT_VECTOR = 0x08

void High_ISR(void) {
    _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18

void Low_ISR(void) {
    _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
#endif

#endif //defined (__18CXX)
#endif //defined(USB_INTERRUPTS)

#pragma code


