/* 
 * File:   SPIMain.c
 * Author: hbrown6
 *
 * Created on November 19, 2019, 3:40 PM
 */
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config.h"
#include <sys/attribs.h>
#include <stdint.h>
#include <string.h>

#define RF95_Max_Payload_Len 255
#define RF95_Header_Len 4
#define RF95_Max_Message_Len  (RF95_Max_Payload_Len - RF95_Header_Len) 
// This is the address that indicates a broadcast
#define RH_BROADCAST_ADDRESS 0xFF 
#define _txHeaderTo RH_BROADCAST_ADDRESS
#define _txHeaderFrom RH_BROADCAST_ADDRESS
#define _txHeaderId 0
#define _txHeaderFlags 0

void spi_init(){
    DDPCONbits.JTAGEN = 0;
    TRISBbits.TRISB8 = 0;
    TRISBbits.TRISB14 = 0;
    TRISFbits.TRISF4 = 0;
    TRISFbits.TRISF5 = 1;
    TRISBbits.TRISB12 = 0;
    LATBbits.LATB12 = 1;
    // SPI Pins
    // Disable Interrupts
    IEC1bits.SPI4EIE = 0;
    IEC1bits.SPI4RXIE = 0;
    IEC1bits.SPI4TXIE = 0;
    // Turn off the SPI during config
    SPI4CONbits.ON = 0;
    // Clear the SPI buffer
    SPI4BUF = 0;
    SPI4BRG = 1;
    
    SPI4STATbits.SPIROV = 0;    
    SPI4CONbits.FRMEN = 0;
    SPI4CONbits.FRMSYNC = 0;
    SPI4CONbits.FRMPOL = 0;
    SPI4CONbits.MSSEN = 1;
    SPI4CONbits.FRMSYPW = 0;
    SPI4CONbits.FRMCNT = 0b000;
    SPI4CONbits.SPIFE = 0;
    SPI4CONbits.ENHBUF = 0;
    SPI4CONbits.SIDL = 0;
    SPI4CONbits.MODE16 = 1;
    SPI4CONbits.MODE32 = 0;
    SPI4CONbits.SMP = 1;
    SPI4CONbits.CKE = 1;
    SPI4CONbits.SSEN = 1;
    SPI4CONbits.CKP = 0;
    SPI4CONbits.MSTEN = 1;

    SPI4CONbits.ON = 1;
    delay(13000);                   //delay 10 ms - waiting for LoRa to turn on-NEEDED
}

int spi_read(int reg_name){
    //LATFbits.LATF4 = 1;
    reg_name = reg_name & 0x7F;
    int shifter = 0x00;
    int shifted = (reg_name << 8) | shifter;
    
    SPI4BUF = shifted;                // Write to the buffer
    while (!SPI4STATbits.SPIRBF); 
    return SPI4BUF;
}

int spi_write(int reg_name,int val){
    //LATFbits.LATF4 = 1;
    reg_name = reg_name | 0x80;
    int shifted = (reg_name << 8) | val;
    
    SPI4BUF = shifted;                // Write to the buffer
    while (!SPI4STATbits.SPIRBF);
    return SPI4BUF;
}
/*
int spi_burst_write(int reg_name, const char* data, uint8_t len){
    uint16_t to_send = (reg_name | 0x80)<<8 | (uint8_t) *data++; //first byte of transmission
    
    // to_send[] = {(reg_name << 8)};
    
    
    
    //uint8_t address[] = {reg_name << 8};
    //uint8_t to_send[] = {address data};
    
    //SPI4BUF = to_send;
    //while(!SPI4STATbits.SPIRBF)
    return SPI4BUF;
}
*/
void delay(int ber){
    int num;
    for(num = 1; num < ber; num++);
}

void Manual_R(void){
    LATBbits.LATB12 = 0;
    T2CONbits.TON = 1;
    while(T1CONbits.TON);
}

void timerconfig(){
    __builtin_enable_interrupts();
    INTCONbits.TPC = 0b111;
    INTCONbits.MVEC = 1;
    T1CONbits.TON = 0;          //Disable timer while config
    T1CONbits.TCS = 0;          //Use internal clock
    T1CONbits.TGATE = 0;        //clock gating disable
    T1CONbits.TCKPS = 0b00;     //pre-scaler 1:1
    TMR1 = 0;                   //reset timer
    PR1 = 500;              //period length
    IPC1bits.T1IP = 7;          //interrupt priority level
    IFS0bits.T1IF = 0;          //clear flag
    IEC0bits.T1IE = 1;          //timer interrupt
    T1CONbits.TON = 1;          //timer on
}

void __ISR(_TIMER_1_VECTOR,IPL7AUTO) Timer1ISR(void){
    if (PR1 == 500){
        PR1 = 20000;
        T1CONbits.TON = 1;
    }
    else{
        PR1 = 500;
        T1CONbits.TON = 0;
    }
    TMR1 = 0;
    LATBbits.LATB12 = 1;
    IFS0bits.T1IF = 0;      //clears the NC interrupt
}

void SPI_LoRa_Setup(){          //TX arduino 
    spi_write(0x01,0x80);
    int ack = spi_read(0x01);
    spi_write(0x0E,0x00);       // Config RSSI, 2 samples used
    spi_write(0x0F,0x00);       // Sets RSSI collision threshold to 0 dB
    spi_write(0x01,0x80);       
    spi_write(0x1D,0x72);       // measured frequency offset
    spi_write(0x1E,0x74);
    spi_write(0x26,0x00);       // sets preamble size to be 0
    spi_write(0x20,0x00);       // disables TimeoutRxRssi
    spi_write(0x21,0x08);       // Timeout interrupt generated 8*16*T_bit after switching to Rx mode if Rssi interrupt does not occur
    spi_write(0x06,0x6C);       // Setting RF carrier frequency
    spi_write(0x07,0x80);       
    spi_write(0x08,0x00);       
    //makes sense^^^
    spi_write(0x4D,0x04);       // keeping default value of PA_BOOST 
    spi_write(0x09,0x8C);       // RegPaConfig
    //Set the resolution of the carrier f
    spi_write(0x06,0xE4);       
    spi_write(0x07,0xC0);
    spi_write(0x08,0x00);
    //
    spi_write(0x4D,0x07);       // Changing value of PA_BOOST
    spi_write(0x09,0x8F);       // RegPaConfig
    spi_write(0x01,0x05);       // Access Low Freq Mode registers, Stdby mode
    spi_write(0x40,0x00);       // Mapping pins?
}

int RX(void){
    int RegIrqFlags = spi_read(0x12);
    RegIrqFlags = RegIrqFlags & 0x00FF;
    int RegIrqFlagsShifted = (RegIrqFlags >> 4);
    if(RegIrqFlagsShifted != 0x5){
        return 0;
    }
    int RegRxNbBytes = spi_read(0x13);
    int RegFifoRxCurrentAddr = spi_read(0x10);
    spi_write(0x0D,RegFifoRxCurrentAddr);
    
    
    //now you are ready to listen!
    /*
    int i = 0;
    int Ans = 0;
    for(i=1; i < RegRxNbBytes;i++){
        RegFifoRxCurrentAddr = RegFifoRxCurrentAddr & 0x7F;
        int shifter = 0x00;
        int shifted = (RegFifoRxCurrentAddr << 8) | shifter;
    
        SPI4BUF = shifted;                // Write to the buffer
        while (!SPI4STATbits.SPIRBF); 
        //char Ans[] = {Ans, (char) SPI4BUF};//concatenate(Ans,SPI4BUF);
    }
     * */
    return Ans;
}

int concatenate(unsigned x, unsigned y) {
    unsigned pow = 10;
    while(y >= pow)
        pow *= 10;
    return x * pow + y;        
}

int TX(const char* message, int length){
    int FIFO_buffer = 0x00;
    uint8_t send_byte; 
    if ((length+4) > RF95_Max_Message_Len){
        return 1;
    }
    
    //waitPacketSent();  //Make sure that the chip is ready
    spi_write(0x01, 0x01); // Set Mode to Idle
    spi_write(0x0D, 0x00); // Set FIFO pointer to zero
    
    // Write all of the headers to the FIFO if we want to do that
    spi_write(FIFO_buffer, _txHeaderTo);
    spi_write(FIFO_buffer, _txHeaderFrom);
    spi_write(FIFO_buffer, _txHeaderId);
    spi_write(FIFO_buffer, _txHeaderFlags);
    
    while(length--){
        send_byte = *message++;
        spi_write(FIFO_buffer, send_byte);
    }
    spi_write(0x22,0x20);
    //Put in Transmit Mode using register 0x01 to send message
    spi_write(0x01, 0x03);
    int status;
    int transmit = 1;
    while(transmit){
        status = spi_read(0x12);
        if (status & 0b00001000){
            transmit = 0;
        }
    }
    
    return 0;
}

int main(void) {
    spi_init();
    timerconfig();
    Manual_R();
    SPI_LoRa_Setup();
    /*
    while(1){
        char payload[20] = "123456789ASDFGHJKLPO";
        TX(payload, 20);
    }
     * */
    int powerplay[] = RX();
    TX(powerplay, 20);
    
    return 0;
}
