/* Motenpoche 
 *
 * (c) 2023 Daniele Lacamera <root@danielinux.net>
 *
 *
 * Motenpoche is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Motenpoche is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 *
 */
#include <stdio.h>
#include <stdint.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#include "hardware/i2c.h"
#include "hardware/spi.h"
#include "cryptoengine.h"

#include "bsp/board.h"

#include "tusb.h"
#include "usb_descriptors.h"
#include "ui.h"

#include "user_settings.h"
#include "wolfssl/wolfcrypt/settings.h"
#include "class/cdc/cdc.h"
#include "class/cdc/cdc_device.h"
#include "class/msc/msc.h"
#include "hardware/gpio.h"
#include "flash.h"
#include "display.h"
#include "hid.h"
    

void core1_main(void);
static volatile int main_plug = 1;
int thread_control_ui = 0;


/* DOUT */

#define RED_LED 17
#define GREEN_LED 16
#define PICO_LED    PICO_DEFAULT_LED_PIN

static uint Led[] = {
    RED_LED,
    GREEN_LED,
    PICO_LED
};


/* DIN */
#define ROT_S0       19
#define ROT_S1       20
#define ROT_KEY      18
#define OK_BUTTON    21
#define BACK_BUTTON  22

/* I2C */
#define I2C         (&i2c1_inst)
#define I2C_BAUDRATE 48000
#define I2C_SCL_PIN 27
#define I2C_SDA_PIN 26

/* SPI */
#define SPI              (spi0)
#define SPI_BAUDRATE     100000
#define SPI_SCLK_PIN     2
#define SPI_MOSI_PIN     3
#define SPI_MISO_PIN     4
#define SPI_FLASH_CS_PIN 5



uint16_t flash_info = 0xFFFF;

#define AIRCR *(volatile uint32_t *)(0xE000ED0C)
#define AIRCR_VKEY (0x05FA << 16)
#define AIRCR_SYSRESETREQ (1 << 2)
static void sys_reboot(void)
{
    AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY;
    while(1)
        ;
}

void system_reboot(void)
{
    int i;
    main_plug = 0;
    thread_control_ui = 2;
    for (i = display_getcontrast(); i >= 0; i--) {
        display_setcontrast(i);
        sleep_ms(5);
    }
    display_clear();
}

void system_boot(void)
{
    int i, ret;
    set_sys_clock_48mhz();
    multicore_reset_core1();
    //stdio_init_all();

    printf("Initializing USB...\r\n");
    tusb_init();
    printf("Done.\r\n");

    /* LED and Douts */
    printf("Setting LEDs\r\n");
    for (i = 0; i < 3; i++) {
        gpio_init(Led[i]);
        gpio_set_dir(Led[i], GPIO_OUT);
        gpio_put(Led[i], 0);
    }
    gpio_put(RED_LED, 1);
    gpio_put(GREEN_LED, 1);
    printf("Done.\n");

    /* BTN Dins */
    printf("Setting buttons and digital inputs...\r\n");
    gpio_init(ROT_S0);
    gpio_init(ROT_S1);
    gpio_init(ROT_KEY);
    gpio_init(OK_BUTTON);
    gpio_init(BACK_BUTTON);
    gpio_set_dir(ROT_S0, GPIO_IN);
    gpio_set_dir(ROT_S1, GPIO_IN);
    gpio_set_dir(ROT_KEY, GPIO_IN);
    gpio_set_dir(OK_BUTTON, GPIO_IN);
    gpio_set_dir(BACK_BUTTON, GPIO_IN);
    gpio_pull_down(ROT_S0); 
    gpio_pull_down(ROT_S1); 
    gpio_pull_up(ROT_KEY); 
    gpio_pull_down(OK_BUTTON);
    gpio_pull_down(BACK_BUTTON);
    printf("Done.\n");



    printf("Initializing SPI Flash\r\n");
    gpio_init(SPI_SCLK_PIN);
    gpio_init(SPI_MOSI_PIN);
    gpio_init(SPI_MISO_PIN);
    gpio_init(SPI_FLASH_CS_PIN);
    gpio_set_function(SPI_SCLK_PIN, GPIO_FUNC_SPI);
    gpio_set_function(SPI_MOSI_PIN, GPIO_FUNC_SPI);
    gpio_set_function(SPI_MISO_PIN, GPIO_FUNC_SPI);
    gpio_set_dir(SPI_FLASH_CS_PIN, GPIO_OUT);
    gpio_put(SPI_FLASH_CS_PIN, 1);
    spi_init(SPI, SPI_BAUDRATE);
    flash_info = flash_init(SPI);
    
    printf("Initializing I2C Display\r\n");
    gpio_init(I2C_SDA_PIN);
    gpio_init(I2C_SCL_PIN);
    gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
    i2c_init(I2C, I2C_BAUDRATE);
    ui_init(I2C);
    printf("Done\r\n");
    
    printf("Starting CPU Core 1\r\n");
    multicore_launch_core1(core1_main);
    printf("Done\r\n");

    gpio_put(RED_LED, 0);
    printf("Init complete.\r\n");
}

#define ROT_UP 1
#define ROT_DOWN 2

uint32_t rotary_action(void)
{
    uint32_t action = 0;
    if (gpio_get(ROT_S0))
        action |= 1;
    if (gpio_get(ROT_S1))
        action |= 2;
    return action;
}

int rot_updown(void)
{
    static int rot_up = 0;
    static int rot_down = 0;
    static uint32_t rotary_pos = 0;
    uint32_t rotary_now;
    rotary_now = rotary_action();
    if (rotary_now != rotary_pos) {
        if ((rotary_pos == 0 && rotary_now == 3) ||
                (rotary_pos == 3 && rotary_now == 2) ||
                (rotary_pos == 2 && rotary_now == 0) ||
                (rotary_pos == 1 && rotary_now == 3)) {
            rot_down++;
            rot_up = 0;
        }
        if ((rotary_pos == 0 && rotary_now == 1) ||
                (rotary_pos == 3 && rotary_now == 1) ||
                (rotary_pos == 2 && rotary_now == 3) ||
                (rotary_pos == 1 && rotary_now == 0)) {
            rot_up++;
            rot_down = 0;
        }
        rotary_pos = rotary_now;
    }
    if (rot_up > 1) {
        rot_up = 0;
        return ROT_UP;
    }
    if (rot_down > 1) {
        rot_down = 0;
        return ROT_DOWN;
    }
    return 0;
}

static uint32_t key_press_counter = 0;
static uint32_t ok_press_counter = 0;
static uint32_t back_press_counter = 0;

void clear_input(void)
{
    key_press_counter = 0;
    ok_press_counter = 0;
    back_press_counter = 0;
}

void poll_buttons(void)
{
    int rot_ud = 0;

    if (gpio_get(ROT_KEY) == 0) {
        key_press_counter++;
    } else {
        key_press_counter = 0;
    }

    if (gpio_get(OK_BUTTON) != 0) {
        ok_press_counter++;
    } else {
        ok_press_counter = 0;
    }
    if (gpio_get(BACK_BUTTON) != 0) {
        back_press_counter++;
    } else {
        back_press_counter = 0;
    }
    
    if (ok_press_counter == 100) {
        printf("OK: pressed\n");
        ui_confirm_button();
        return;
    }
    
    if (key_press_counter == 100) {
        printf("key: pressed\n");
        ui_key_button();
        return;
    }
    
    if (back_press_counter == 100) {
        printf("back: pressed\n");
        ui_back_button();
        return;
    }
    if ((fsm_get() == VAULT_BOOTUP) && (back_press_counter == 100000)) {
        uint32_t i;
        for (i = 0; i < VAULT_FLASH_SIZE; i+=SPI_FLASH_SECTOR_SIZE)
            flash_sector_erase(i);

        system_reboot();
        return;
    }

    rot_ud = rot_updown();

    if (rot_ud == ROT_UP) {
        ui_rot_up();
        sleep_ms(1);
        return;
    }
    if (rot_ud == ROT_DOWN) {
        ui_rot_down();
        sleep_ms(1);
        return;
    }
}

uint8_t *fbuf = NULL;


static uint8_t flash_buf[4];
int main(void) {
    int i;
    system_boot();
    printf("Loop started.\n");


    while (main_plug) {
        uint32_t ms_tick = board_millis();
        if ((ms_tick % 10) == 0) {
            if (thread_control_ui == 0) {
                poll_buttons();
            }
        }
        if (thread_control_ui == 0) {
            if ((ms_tick % 100) == 0) {
                ui_task();
            }
        }
    }
    
    /* End of session. Goodbye. */
    multicore_reset_core1();
    sys_reboot();
}

void core1_main(void)
{
    while(1) {
        hid_task();
        tud_task();
    }
}
