#include <Arduino.h>
#include <Adafruit_ST7735.h>
#include <TinyGPSPlus.h>
#include <logger.h>
#include "board.h"
#include "sx1262.h"

TinyGPSPlus gps;
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
logging::Logger logger;
Sx1262 radio = Sx1262(SX1262_RST, SX1262_SCK, SX1262_MOSI, SX1262_MISO, SX1262_NSS ,SX1262_DIO1, SX1262_BUSY);

void setup_radio()
{
    /*tft.setTextColor(ST77XX_GREEN, ST77XX_BLACK);
    tft.setCursor(0, 12);
    tft.print("[Sx1262] ");
    tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);*/
    /*
    C'est le bout trouvé dans le code kikiwi
    pour la config
    ==============
        SX1276FskSetGMSK(GAUSSIAN_FILTER_0_5);	// FSK modulation shaping
		SX1276FskBaudRate(BAUDRATE_1200);		// Data baudrate
		SX1276FskSetRFPower(14);
		SX1276FskSetPayloadLength( DATA_FRAME_SIZE );
		SX1276FskPacketFormat(RF_PACKETCONFIG1_PACKETFORMAT_FIXED);
		SX1276FskSetPacketCrcOn( true );
    pour le Tx
    ==========
    	SX1276FskSetOpMode(RF_OPMODE_STANDBY);
        SX1276WriteFIFO(RadioFrame, DATA_FRAME_SIZE);
        SX1276FskSetOpMode(RF_OPMODE_TRANSMITTER);	
        SYS_Delay(500); /// Validé 500
        SX1276FskSetOpMode(RF_OPMODE_STANDBY);
    */

    radio.beginSPI();
    radio.reset();

    /* 0x80 */
    radio.SetStandby();
    /* 0x17 */    
    radio.GetDeviceErrors();
    /* 0x07 */
    radio.ClearDeviceErrors();

    /*
     * On veut que le DIO3 soit utilisé pour l'alimentation du TCXO
     */
    /* 0x97 */
    radio.SetDIO3AsTCXOCtrl(0x00, 0x140);

    /*
     * Table 13-74: SetBufferBaseAddress SPI Transaction
     * De toute façon le bousin ne fera que du Tx
     */
    /* 0x8f */
    radio.SetBufferBaseAddress(0x00, 0x00);

    /* 0x8a */
    radio.SetPacketType(SX126X_PACKET_TYPE_GFSK);

    /* 0x93 */
    radio.SetRxTxFallbackMode(SX126X_RX_TX_FALLBACK_MODE_STDBY_RC);
    /* 0x88 */
    radio.SetCadParams(0x03, 0x0d, 0x0a, 0x00, 0x00000000);
    /* 0x02 */
    radio.ClearIRQStatus();
    /* 0x08 */
    radio.SetDioIrqParams(0x0201, 0x0001, 0x0000, 0x0000);
    /* 0x89 */
    radio.Calibrate();

    /* Long temp de LoRa BUSY, 9,1ms environs */


    /* 0xc0 */
    radio.getStatusCommand(SX126X_GET_STATUS);
    /* 0x96 */
    radio.SetRegulatorMode(SX126X_REGULATOR_MODE_DCDC);
    /* 0x11 */
    radio.GetPacketType();
    /* 0x8b */
    radio.SetModulationParams(1200, SX126X_GFSK_PULSE_SHAPE_BT_0_5 ,SX126X_GFSK_BANDWIDTH_156200, 0x00000010);
    /*
     * OCP Configuration
     * Table 12-1: List of Registers Used for Over Current Protection
     * 0x18 (60 mA) or 0x38 (140 mA) for SX1262
     * 0x18 (60 mA) for SX1261
     */
    /* 0x0d */
    radio.regWrite(SX126X_REG_OCP, 0x18);
    /* 0x11 */
    radio.GetPacketType();
    /*
     * Table 13-36: SetRfFrequency SPI Transaction
    main/sx1276-Fsk.c:146:    SX1276->RegSyncConfig = RF_SYNCCONFIG_AUTORESTARTRXMODE_WAITPLL_ON | RF_SYNCCONFIG_PREAMBLEPOLARITY_AA |
    main/sx1276-Fsk.c:147:                            RF_SYNCCONFIG_SYNC_ON |
    main/sx1276-Fsk.c:148:                            RF_SYNCCONFIG_SYNCSIZE_4;
     */
    /* 0x8c */
    radio.SetPacketParams(0x100, 0x05, 4, 0x00, 0x00, 50, 1, 0);
    /* 0x11 */
    radio.GetPacketType();
    /*
     * on écrit les valeurs de sync_words voulu, comme dans kikiwi
     Vu dans les sources :
    main/sx1276-Fsk.c:150:    SX1276->RegSyncValue1 = 0x69;
    main/sx1276-Fsk.c:151:    SX1276->RegSyncValue2 = 0x81;
    main/sx1276-Fsk.c:152:    SX1276->RegSyncValue3 = 0x7E;
    main/sx1276-Fsk.c:153:    SX1276->RegSyncValue4 = 0x96;
     */
    /*0x0d 4 fois*/
    radio.regWrite(0x06C0, 0x69);
    radio.regWrite(0x06C1, 0x81);
    radio.regWrite(0x06C2, 0x7E);
    radio.regWrite(0x06C3, 0x96);
    /*
     * On veut que le DIO2 soit utilisé pour le RF Switch
     */
    /* 0x9d */
    radio.SetDIO2AsRfSwitchCtrl(1);
    /* 0x98 */
    radio.CalibrateImage(0x6b, 0x6f);   // DETERMINER CES VALEURS ?!

    /* UN PEU LONG AUSSI LE LoRa BUSY, environs 6,59ms  */

    /* 0x86 */
    radio.SetRfFrequency(869450000);

    

    /* 0xc0 */
    radio.getStatusCommand(SX126X_GET_STATUS);
    /* 0x0d */
    radio.regWrite(0x08d8, 0xde);       // A determiner aussi
    /* 0x1d */
    /* 0xc0 */
    radio.getStatusCommand(SX126X_GET_STATUS);
    /*
     * Table 13-21: PA Operating Modes with Optimal Settings
     */
    /* 0x95 */
    radio.SetPaConfig(0x02, 0x02, 0x00, 0x01);
    /*
     * Table 13-40: SetTxParams SPI Transaction
     */
    /* 0x8e */
    radio.SetTxParams(SX126X_POWER_10_DBM, SX126X_RAMP_TIME_200_US);
    /* 0x0d */
    radio.regWrite(0x08e7, 0x18);       // A determiner aussi

/*
##################3
JUSQUE IXI TOUT VA BIEN

*/

   /* 0x17 */    
    radio.GetDeviceErrors();
    /* 0xc0 */
    radio.getStatusCommand(SX126X_GET_STATUS);
    /*
     * Table 13-42: Set Modulation Prameters in GFSK Mode
     */
 
    /* 0x11 */
    radio.GetPacketType();
    //logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "SX1262", "Setup done");
}

void setup_gps()
{    
    Serial1.begin(115200, SERIAL_8N1, GPS_RX, GPS_TX);
    tft.setCursor(0, 0);
    tft.setTextColor(ST77XX_GREEN, ST77XX_BLACK);
    tft.print("[GPS] ");
    tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
    tft.print("Setup done.");
    logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "GPS", "Setup done");
}

void setup_tft()
{
    pinMode(TFT_CS, OUTPUT);
    pinMode(TFT_RST, OUTPUT);
    pinMode(TFT_CS, OUTPUT);

    tft.initR(INITR_MINI160x80_PLUGIN);
    tft.setRotation(1); // Landscape
    tft.fillScreen(ST77XX_BLACK);
    tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
    tft.setTextSize(1.5);

    delay(50); // Wait for screen to clear

    // Enable backlight
    pinMode(TFT_LED, OUTPUT);
    digitalWrite(TFT_LED, HIGH);
}


void setup() 
{
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);

    USBSerial.begin(115200);
    logger.setSerial(&USBSerial);

    // Enable power to peripherals
    pinMode(VEXT_CTL, OUTPUT);
    digitalWrite(VEXT_CTL, HIGH);
    
    setup_tft();
    //setup_gps();
    setup_radio();
    
    digitalWrite(LED_BUILTIN, LOW);
    tft.fillScreen(ST77XX_BLACK);
    tft.fillCircle(150, 10, 2, ST77XX_WHITE);
}

void read_nmea(uint32_t ms)
{
    unsigned long start = millis();
    char c;
    logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "GPS", "Reading NMEA data :");
    do
    {

        while (Serial1.available()) {
            c = Serial1.read();
            gps.encode(c);
            USBSerial.write(c);
        }
    } while (millis() - start < ms);

    if (gps.time.isUpdated())
    {
        tft.setCursor(0, 9);
        tft.printf("%04u-%02u-%02u %02u:%02u:%02u",
                   gps.date.year(), gps.date.month(), gps.date.day(),
                   gps.time.hour(), gps.time.minute(), gps.time.second());
    }

    if (gps.location.isUpdated())
    {
        tft.setCursor(0, 24);
        tft.printf("Lat: % 3.6f\nLon: % 3.6f\n", gps.location.lat(), gps.location.lng());
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "GPS", "Lat: % 3.6f, Lon: % 3.6f", gps.location.lat(), gps.location.lng());
    }

    if (gps.altitude.isUpdated())
    {
        tft.setCursor(0, 28);
        tft.printf("Alt: %3.0fft ", gps.altitude.feet());
        logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "GPS", "Alt: %3.0fft", gps.altitude.feet());
    }
    
    USBSerial.println();

}

void loop() 
{
    /*
    tft.setTextColor(ST7735_GREEN, ST77XX_BLACK);
    tft.setCursor(0, 0);
    tft.print("[GPS NMEA] ");
    tft.setTextColor(ST7735_WHITE, ST77XX_BLACK);

        

    tft.fillCircle(150, 10, 2, ST77XX_GREEN);
    // read_nmea(1000);
    tft.fillCircle(150, 10, 2, ST77XX_WHITE);
    */

    /* 0x80 */
    radio.SetStandby();

    /*0x8C*/
    radio.SetPacketParams(0x100, 0x05, 4, 0x00, 0x00, 50, 1, 0);
    /*0x08*/
    radio.SetDioIrqParams(0x0201, 0x0001, 0x0000, 0x0000);


    /* 0x8f */
    radio.SetBufferBaseAddress(0x00, 0x00);
    /*0x0e*/
    radio.WriteBuffer("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB");
    radio.ClearIRQStatus();
    radio.regRead(0x0889);

    radio.getStatusCommand(0);
    radio.GetPacketType();

    radio.regWrite(SX126X_REG_TX_MODULATION, 0x04);
    radio.SetTx(0);


    delay(250);

// shutdown the ESP32 to save power



}
