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

#include "hardware/pwm.h"
#include "hardware/clocks.h"

#define RED_PIN 1
#define YELLOW_PIN 5
#define GREEN_PIN 9
#define GREEN_PEDESTRIANS_PIN 16
#define BUZZER_PIN 21
#define BUZZER_FREQUENCY 100
#define BUTTON_PIN 12
#define ON 1
#define OFF 0

void pwm_led_put(int pino, int status) {
  gpio_put(pino, status);
}

void pwm_init_buzzer(uint pin) {
  // configurar o pino como saída de PWM
  gpio_set_function(pin, GPIO_FUNC_PWM);
  
  // obter o slice do PWM associado ao pino
  uint slice_num = pwm_gpio_to_slice_num(pin);

  // configurar o PWM com frequência desejada
  pwm_config config = pwm_get_default_config();
  pwm_config_set_clkdiv(&config, clock_get_hz(clk_sys) / (BUZZER_FREQUENCY * 4096)); // Divisor de clock
  pwm_init(slice_num, &config, true);

  // iniciar o PWM no nível baixo
  pwm_set_gpio_level(pin, 0);
}

void beep(uint pin, uint duration_ms) {
  // obter o slice do PWM associado ao pino
  uint slice_num = pwm_gpio_to_slice_num(pin);

  // configurar o duty cycle ara 50% (ativo)
  pwm_set_gpio_level(pin, 2048);

  sleep_ms(duration_ms);

  // desativar o sinal PWM (duty cycle 0)
  pwm_set_gpio_level(pin, 0);

  sleep_ms(100);
}

int main() {
  gpio_init(RED_PIN);
  gpio_set_dir(RED_PIN, GPIO_OUT);
  gpio_init(GREEN_PIN);
  gpio_set_dir(GREEN_PIN, GPIO_OUT);
  gpio_init(YELLOW_PIN);
  gpio_set_dir(YELLOW_PIN, GPIO_OUT);
  gpio_init(GREEN_PEDESTRIANS_PIN);
  gpio_set_dir(GREEN_PEDESTRIANS_PIN, GPIO_OUT);

  gpio_init(BUZZER_PIN);
  gpio_set_dir(BUZZER_PIN, GPIO_OUT);
  pwm_init_buzzer(BUZZER_PIN);
  
  gpio_init(BUTTON_PIN);
  gpio_set_dir(BUTTON_PIN, GPIO_IN);
  gpio_pull_down(BUTTON_PIN);

  while(true) {
    pwm_led_put(GREEN_PIN, ON);
    sleep_ms(8000);
    pwm_led_put(GREEN_PIN, OFF);

    pwm_led_put(YELLOW_PIN, ON);
    sleep_ms(2000);
    pwm_led_put(YELLOW_PIN, OFF);

    pwm_led_put(RED_PIN, ON);
    pwm_led_put(GREEN_PEDESTRIANS_PIN, ON);
    beep(BUZZER_PIN, 10000);
    pwm_led_put(RED_PIN, OFF);
    pwm_led_put(GREEN_PEDESTRIANS_PIN, OFF);
  }

  return 0;
}