#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/f1/spi.h>
#include <libopencm3/stm32/f1/exti.h>
#include <libopencm3/cm3/nvic.h>
#include <libLHP_UART.h>



void clock_setup(){
rcc_clock_setup_in_hse_8mhz_out_72mhz();
}

void gpio_setup(){
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
}


volatile uint8_t alive=0;

int main(){
  uint8_t a=0;
  int i,j;
  clock_setup();
  gpio_setup();
  GPIOC_ODR = 0;
  
  setup_UART1();

  clrscreen_uart(USART1);
  printstr(USART1,"LHP - Bluepill\r\n"__FILE__ "\r\n"  __DATE__ " - " __TIME__ "\r\n");
  printstr_blocking(USART1,"---");


  //the gist : we setup gpio interrupts and pass by raw signals
  //when tne command is read (0x3) we alter the read bytes
  //this can only work if spi is "slow" compared to the cpu speed


  //gpio setup
  rcc_periph_clock_enable(RCC_GPIOA);
  rcc_periph_clock_enable(RCC_GPIOB);
  // the normal SPI1 pins : output to the chip
  gpio_set_mode(GPIOA,
                GPIO_MODE_OUTPUT_50_MHZ,
                GPIO_CNF_OUTPUT_PUSHPULL,
                GPIO_SPI1_NSS | GPIO_SPI1_SCK | GPIO_SPI1_MOSI
                );
  gpio_set_mode(GPIOA,
                GPIO_MODE_INPUT,
                GPIO_CNF_INPUT_FLOAT,
                GPIO_SPI1_MISO);

  // the normal SPI2 pins : input from the mcu
  gpio_set_mode(GPIOB,
                GPIO_MODE_INPUT,
                GPIO_CNF_INPUT_FLOAT,
                GPIO_SPI2_NSS | GPIO_SPI2_SCK | GPIO_SPI2_MOSI
                );
  gpio_set_mode(GPIOB,
                GPIO_MODE_OUTPUT_50_MHZ,
                GPIO_CNF_OUTPUT_PUSHPULL,
                GPIO_SPI2_MISO);

  GPIOA_ODR = GPIO_SPI1_NSS;

  //interrupt/exti setup
  rcc_periph_clock_enable(RCC_AFIO);
  nvic_enable_irq(NVIC_EXTI15_10_IRQ); 
  nvic_enable_irq(NVIC_EXTI9_5_IRQ);  

  exti_select_source(EXTI12, GPIOB);// NSS  MCU  side
  exti_select_source(EXTI13, GPIOB);// SCK  MCU  side
  exti_select_source(EXTI15, GPIOB);// MOSI MCU  side
  exti_select_source(EXTI6 , GPIOA);// MIS0 CHIP side

  exti_set_trigger(EXTI12, EXTI_TRIGGER_BOTH);
  exti_set_trigger(EXTI13, EXTI_TRIGGER_BOTH);
  exti_set_trigger(EXTI15, EXTI_TRIGGER_BOTH);
  exti_set_trigger(EXTI6 , EXTI_TRIGGER_BOTH);

  exti_enable_request(EXTI12);
  exti_enable_request(EXTI13);
  exti_enable_request(EXTI15);
  exti_enable_request(EXTI6);

  printstr(USART1,"Waiting in the middle...\r\n");

  while(1){
    GPIOC_ODR ^= (1<<13);
    if(UART1_received_cmd()){
      printstr(USART1,get_receive_buff());
      receive_buff_processed();
      printstr_rn(USART1);
    }
    if(alive){
       print_hex_8 (USART1, alive);
       alive=0;
    }


    for ( i = 0; i < 1600000; i++)	/* Wait enough to be visible. */
      __asm__("nop");
  }

}

enum exti_top_state {
                     exti_waiting_nss,
                     exti_waiting_command,
                     exti_waiting_data,
                     exti_tampering,
};
enum exti_bit_state {
                 exti_waiting_clock,
                 exti_waiting_bit,
};


volatile unsigned int exti_top_state = exti_waiting_nss;

void exti_mitm_isr()
{

  if(exti_get_flag_status(EXTI12)){

    exti_reset_request(EXTI12);
    GPIOA_ODR =
      (GPIOB_IDR & GPIO_SPI2_NSS) ?
      (GPIOA_ODR |= (GPIO_SPI1_NSS)):
      (GPIOA_ODR & ~(GPIO_SPI1_NSS));
  }
  if(exti_get_flag_status(EXTI13)){

    exti_reset_request(EXTI13);
    GPIOA_ODR =
      (GPIOB_IDR & GPIO_SPI2_SCK) ?
      (GPIOA_ODR |= (GPIO_SPI1_SCK)):
      (GPIOA_ODR & ~(GPIO_SPI1_SCK));
  }
  if(exti_get_flag_status(EXTI15)){

    exti_reset_request(EXTI15);
    GPIOA_ODR =
      (GPIOB_IDR & GPIO_SPI2_MOSI) ?
      (GPIOA_ODR |= (GPIO_SPI1_MOSI)):
      (GPIOA_ODR & ~(GPIO_SPI1_MOSI));
  }


  if(exti_get_flag_status(EXTI6)){
    exti_reset_request(EXTI6);
    if(exti_top_state!=exti_tampering){   
      GPIOB_ODR =
        (GPIOA_IDR & GPIO_SPI1_MISO) ?
        (GPIOB_ODR |= (GPIO_SPI2_MISO)):
        (GPIOB_ODR & ~(GPIO_SPI2_MISO));      
    }else{
      ; /*
          do the deed here
          try to do the same thing we did for i2c
          you will need to maintain a global state, i did that for you already with suggested 
         */
    }

  }

 

 }

void exti9_5_isr(void){
  exti_mitm_isr();
}

void exti15_10_isr(void){
  exti_mitm_isr();
}



