#include "xc.h"
#include "init.h"
#include "extern.h"


/* Filter and mask defines for CAN*/
/* Macros used to write filter/mask ID to Register CiRXMxSID and CiRXFxSID */
/* For example, to set up the filter to accept a value of 0x123, the macro when called as */
/* CAN_FILTERMASK2REG_SID(0x123) will write the register space to accept message with ID 0x123 */
/* Use for Standard Messages Only */
#define CAN_FILTERMASK2REG_SID(x) ((x & 0x07FF)<<5)
/* The Macro will set the MIDE bit in CiRXMxSID */
#define CAN_SETMIDE(sid) (sid|0x0008)
/* The Macro will set the EXIDE bit in CiRXFxSID to only accept extended messages */
#define CAN_FILTERXTD(sid) (sid|0x0008)
/* The macro will clear the EXIDE bit in CiRXFxSID to only accept standard messages */
#define CAN_FILTERSTD(sid) (sid & 0xFFF7)
/* Macro used to write filter/mask ID to Register CiRXMxSID, CiRXMxEID, CiRXFxSID and CiRXFxEID */
/* For example, to set up the filter to accept a value of 0x123, the macro when called as */
/* CAN_FILTERMASK2REG_SID(0x123) will write the register space to accept message with ID 0x123 */
/* Use for Extended Messages only*/
#define CAN_FILTERMASK2REG_EID0(x) (x & 0xFFFF)
#define CAN_FILTERMASK2REG_EID1(x) (((x & 0x1FFC)<<3)|(x & 0x3))




void InitCAN1()
{
    unsigned long tmp_EID;

C1CTRL1bits.REQOP=4;  //Put ECAN module in config mode
while (C1CTRL1bits.OPMODE!=4);  //Wait until it is in config mode  TODO:  Needs timeout

/* FCAN is selected to be FCY */
/* FCAN = FCY = 40 MHz */
C1CTRL1bits.CANCKS = 0x1;
/* Bit Time = (Sync Segment + Propagation Delay + Phase Segment 1 + Phase Segment 2) = 20 * TQ */
/* Phase Segment 1 = 8 TQ */
/* Phase Segment 2 = 6 TQ */
/* Propagation Delay = 5 TQ */
/* Sync Segment = 1 TQ */
/* CiCFG1<BRP> =(FCAN/(2 * N * FBAUD))- 1 */
/* BRP_VAL computed in config.h based on bit rate selected there */
C1CFG1bits.BRP = BRP_VAL;
/* Synchronization Jump Width set to 4 TQ */
C1CFG1bits.SJW = 0x3;
/* Phase Segment 1 time is 8 TQ */
C1CFG2bits.SEG1PH = 0x7;
/* Phase Segment 2 time is set to be programmable */
C1CFG2bits.SEG2PHTS = 0x1;
/* Phase Segment 2 time is 6 TQ */
C1CFG2bits.SEG2PH = 0x5;
/* Propagation Segment time is 5 TQ */
C1CFG2bits.PRSEG = 0x4;
/* Bus line is sampled three times at the sample point */
C1CFG2bits.SAM = 0x1;

/* Assign 12 buffers in DMA ram*/
C1FCTRLbits.DMABS=0b100;  //Eight buffers for Tx, and eight for Rx



// Enable buffers and set tx buffer priority
C1TR01CONbits.TXEN0 = 1; /* ECAN1, Buffer 0 is a Transmit Buffer */
C1TR01CONbits.TXEN1 = 1; /* ECAN1, Buffer 1 is a Transmit Buffer */
C1TR23CONbits.TXEN2 = 1; /* ECAN1, Buffer 2 is a Transmit Buffer */
C1TR23CONbits.TXEN3 = 1; /* ECAN1, Buffer 3 is a Transmit Buffer */
C1TR45CONbits.TXEN4 = 1; /* ECAN1, Buffer 4 is a Transmit Buffer */
C1TR45CONbits.TXEN5 = 1; /* ECAN1, Buffer 5 is a Transmit Buffer */
C1TR67CONbits.TXEN6 = 1; /* ECAN1, Buffer 6 is a Transmit Buffer */
C1TR67CONbits.TXEN7 = 1; /* ECAN1, Buffer 7 is a Transmit Buffer */

C1TR01CONbits.TX0PRI = 0b11; /* Message Buffer 0 Priority Level */
C1TR01CONbits.TX1PRI = 0b11; /* Message Buffer 1 Priority Level */
C1TR23CONbits.TX2PRI = 0b11; /* Message Buffer 2 Priority Level */
C1TR23CONbits.TX3PRI = 0b11; /* Message Buffer 3 Priority Level */
C1TR45CONbits.TX4PRI = 0b11; /* Message Buffer 4 Priority Level */
C1TR45CONbits.TX5PRI = 0b11; /* Message Buffer 5 Priority Level */
C1TR67CONbits.TX6PRI = 0b11; /* Message Buffer 6 Priority Level */
C1TR67CONbits.TX7PRI = 0b11; /* Message Buffer 6 Priority Level */

//Set up recieve buffers, mask, etc. for recieving extended frames
/* Enable window to access acceptance filter registers */
C1CTRL1bits.WIN = 0x1;
/* Select Acceptance Filter Mask 0 for Acceptance Filter 0 */
C1FMSKSEL1bits.F0MSK=0x00;
/* Configure Acceptance Filter Mask 0 register to care about all bits. (bits set to 0 here don't count.
Mask Bits (29-bits) : 0b0 0000 0000 0000 0000 0001 1111 1111
SID<10:0> : 0b111 1111 1111 ..SID<10:0> or EID<28:18>
EID<17:16> : 0b11
..EID<17:16>
EID<15:0> : 0b1111 1111 1111 1111 ..EID<15:0> */
C1RXM0SIDbits.SID = (0x1FFC0000) >> 18;
C1RXM0SIDbits.EID = (0x00030000) >> 16;
C1RXM0EIDbits.EID = (0x0000FFFF);

/* Configure Acceptance Filter 0 to match extended identifier, Controller ID = from #define and CMD ID = dec(10) to set mode.
Filter Bits (29-bits) : 0b0 0000 0000 0000 0000 000x xxxx xxxx
SID<10:0> : 0b00000000000 ..SID<10:0> or EID<28:18>
EID<17:16> : 0b00         ..EID<17:16>
EID<15:0> : 0b0000000xxxxxxxxx ..EID<15:0> */
tmp_EID = Assemble_packetID(CAN_SRCID, 10, 0);
C1RXF0SIDbits.SID = (tmp_EID & 0x1FFC0000) >> 18;
C1RXF0SIDbits.EID = (tmp_EID & 0x00030000) >> 16;
C1RXF0EIDbits.EID = (tmp_EID & 0x0000FFFF);


/* Acceptance Filter 0 to check for Extended Identifier */
C1RXM0SIDbits.MIDE = 0x1;
C1RXF0SIDbits.EXIDE= 0x1;

/* Acceptance Filter 0 to use Message Buffer 8 to store message */
C1BUFPNT1bits.F0BP = 0x8;
/* Enable Acceptance Filter 0 */
C1FEN1bits.FLTEN0=0x1;

/* Clear window to access ECAN control registers */
C1CTRL1bits.WIN = 0x0;

//Put CAN1 into Normal mode
C1CTRL1bits.REQOP = 0;
while(C1CTRL1bits.OPMODE != 0);

}

void InitDma12()  //DMA channel 1 is used to transfer data to the CAN controller for subsequent transmission
                  //DMA channel 2 is used to transfer recieved data from the CAN controller to the CPU memory
{

    /* Initialize the DMA channel 0 for ECAN TX and clear the colission flags */
DMACS0bits.PWCOL1 = 0;
DMACS0bits.XWCOL1 = 0;
/* Set up Channel 1 for peripheral indirect addressing mode normal operation, word operation */
/* and select TX to peripheral */
DMA1CON = 0x2020;
/* Set up the address of the peripheral ECAN1 (C1TXD) */
DMA1PAD = 0x0442;
/* Set the data block transfer size of 8 */
DMA1CNT = 7;
/* Automatic DMA TX initiation by DMA request */
DMA1REQ = 0x0046;  //IRQ select register
/* DPSRAM atart address offset value */
DMA1STA = __builtin_dmaoffset(&ECAN1MSGBUF);
/* Enable the channel */
DMA1CONbits.CHEN = 1;  

/* Initialize DMA Channel 2 for ECAN RX and clear the collision flags */
DMACS0bits.PWCOL2 = 0;
DMACS0bits.XWCOL2 = 0;
/* Set up Channel 2 for Peripheral Indirect addressing mode (normal operation, word operation */
/* and select as RX to peripheral */
DMA2CON = 0x0020;
/* Set up the address of the peripheral ECAN1 (C1RXD) */
DMA2PAD = 0x0440;
/* Set the data block transfer size of 8 */
DMA2CNT = 7;
/* Automatic DMA Rx initiation by DMA request */
DMA2REQ = 0x0022;
/* DPSRAM atart address offset value */
DMA2STA = __builtin_dmaoffset(&ECAN1MSGBUF);
/* Enable the channel */
DMA2CONbits.CHEN = 1;  



/* Enable ECAN1 interrupt */
_C1IP = 3;
IEC2bits.C1IE = 1;
/* Enable transmit interrupt */
C1INTEbits.TBIE = 0;
/* Enable ECAN1 receive Interrupt */
C1INTEbits.RBIE = 1;

}


void InitDma0()  //DMA channel 0 is used to transfer data at the end of the ADC conversion process
{
DMA0CONbits.AMODE = 0; // Configure DMA for Register indirect with post increment
DMA0CONbits.MODE = 2; // Configure DMA for Continuous mode with ping-pong
DMA0PAD = (int)&ADC1BUF0;
DMA0CNT = NUMAIO*FILTERSAMPLES-1;
DMA0REQ = 13;  //Select ADC1 convert done
DMA0STA = __builtin_dmaoffset(BufferA);
DMA0STB = __builtin_dmaoffset(BufferB);
_DMA0IP = 5;  
IFS0bits.DMA0IF = 0; //Clear the DMA interrupt flag bit
IEC0bits.DMA0IE = 1; //Set the DMA interrupt enable bit
DMA0CONbits.CHEN = 1;

}


// This sets up the ADC sample and convert sequence.  This ADC is set up to run in scan mode,
// it cycles throught the specified channels.  After all are converted a DMA transfer
// occurs which transfers all values into memory locations.
// With this interrupt set to occur at xxkHz, and x channels to be scanned, new
// analog data is available at xkHz, although the samples were all taken x.xx microseconds apart.

void InitADC_WithIntrpt()
{
    AD1PCFGH = AIOMASK_H; // select specified analog input pins
    AD1PCFGL = AIOMASK_L; // select specified analog input pins

    AD1CON1bits.SSRC = 2;  //Clock source select
    AD1CON1bits.ASAM = 1; //Auto-sample start bit
    AD1CON1bits.AD12B = 1; //12 bit mode, disables simultaneous sampling
    AD1CON1bits.FORM = 2; //Report Results as un-signed Fractional.  i.e. dddd dddd dddd 0000 is the twelve bits
    //AD1CON1bits.FORM = 3; //Report Results as signed Fractional.  i.e. sddd dddd dddd 0000 is the twelve bits
    AD1CSSH = ~AIOMASK_H; // Scan specified inputs
    AD1CSSL = ~AIOMASK_L; // Scan specified inputs

    //AD1CON2bits.SMPI = NUMAIO*FILTERSAMPLES-1;   //Generate DMA interrupt every numsamp conversions
    AD1CON2bits.SMPI = 0x0f;   //Generate DMA interrupt every numsamp conversions
    AD1CON2bits.CSCNA = 1;  //Scan inputs
    AD1CON2bits.VCFG = 3; //Use Vref+ and Vref- as reference

    AD1CON3bits.ADCS = 1;  //Conversion clock select
    AD1CON3bits.SAMC = 0x1f;  //Auto-sample time bits

  
    _AD1IF = 0;  //Clear Interrupt
 // _AD1IE = 1;  //Enable Interrupt

    AD1CON1bits.ADON = 1;  //Enable ADC1

}
