// Simulation of my submission for the final project for the 2021
// HackadayU course 'Raspberry Pi Pico and RP2040 - The Deep Dive
// This simulation runs Pong on the Raspberry Pi Pico, using a 
// custom PIO-based composite video peripheral
// Alan Reed, 2021

#include <stdio.h>
#include "pico/stdlib.h"
#include <stdlib.h>

#include "hardware/timer.h"
#include "hardware/gpio.h"
#include "connections.h"
#include "pong.h"

// Use alarm 0
#define ALARM_NUM 0
#define ALARM_IRQ TIMER_IRQ_0


// Manual timer initialisation as the timer SDK functions don't seem to work on sim
// Code borrowed from Pico Examples repo
static void alarm_in_us(uint32_t delay_us) {
    // Enable the interrupt for our alarm (the timer outputs 4 alarm irqs)
    hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
    // Set irq handler for alarm irq
    irq_set_exclusive_handler(ALARM_IRQ, alarm_irq);
    // Enable the alarm irq
    irq_set_enabled(ALARM_IRQ, true);
    // Enable interrupt in block and at processor

    // Alarm is only 32 bits so if trying to delay more
    // than that need to be careful and keep track of the upper
    // bits
    uint64_t target = timer_hw->timerawl + delay_us;

    // Write the lower 32 bits of the target time to the alarm which
    // will arm it
    timer_hw->alarm[ALARM_NUM] = (uint32_t) target;
}

static void alarm_irq(void) {
    // Clear the alarm irq
    hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);

    // Assume alarm 0 has fired
    alarm_in_us(PONG_FRAME_INTERVAL_ms * 1000);
    pong_tick();
}

void button_cb(unsigned int gpio, uint32_t events) {
  if (events & GPIO_IRQ_EDGE_RISE) { 
    if (gpio == PLAYER1_BUTTON_UP || gpio == PLAYER1_BUTTON_DOWN) {
      pong_move_player(1, PONG_DIRECTION_STOP);
    }
    else if (gpio == PLAYER2_BUTTON_UP || gpio == PLAYER2_BUTTON_DOWN) {
      pong_move_player(2, PONG_DIRECTION_STOP);
    }
  } else if (events & GPIO_IRQ_EDGE_FALL) { 
    switch(gpio) {
      case PLAYER1_BUTTON_UP:
        pong_move_player(1, PONG_DIRECTION_UP);
        break;
      case PLAYER1_BUTTON_DOWN:
        pong_move_player(1, PONG_DIRECTION_DOWN);
        break;
      case PLAYER2_BUTTON_UP:
        pong_move_player(2, PONG_DIRECTION_UP);
        break;
      case PLAYER2_BUTTON_DOWN:
        pong_move_player(2, PONG_DIRECTION_DOWN);
        break;
    }
  }
}

void setup() {
  Serial1.begin(115200);

  // stdio_init_all();
  gpio_set_function(SERIAL_RX_PIN, GPIO_FUNC_UART);
  gpio_set_function(SERIAL_TX_PIN, GPIO_FUNC_UART);

  Serial1.print("Pi Pico Pong\r\n");
  Serial1.print("Created by Alan Reed\r\n");
  pong_init();

  irq_set_enabled(TIMER_IRQ_3, false);
  // struct repeating_timer timer;
  // add_repeating_timer_ms(PONG_FRAME_INTERVAL_ms, pong_gametick_callback, NULL, &timer);

  gpio_pull_up(PLAYER1_BUTTON_DOWN);
  gpio_pull_up(PLAYER1_BUTTON_UP);
  gpio_pull_up(PLAYER2_BUTTON_DOWN);
  gpio_pull_up(PLAYER2_BUTTON_UP);
  gpio_set_irq_enabled_with_callback(PLAYER1_BUTTON_DOWN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);
  gpio_set_irq_enabled_with_callback(PLAYER1_BUTTON_UP, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);
  gpio_set_irq_enabled_with_callback(PLAYER2_BUTTON_DOWN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);
  gpio_set_irq_enabled_with_callback(PLAYER2_BUTTON_UP, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &button_cb);

  // Set the tick timer going
  alarm_in_us(PONG_FRAME_INTERVAL_ms * 1000);
}

void loop() {
  pong_update();
}
BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT