#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
#include <math.h>

#define LED_PIN  PICO_DEFAULT_LED_PIN   // LED
#define PWM_SUB_PIN 2                   // サブ用 (GPIO2)

// PWM信号のクロック分周比
#define PWM_CLOCK_DIVIDER 100.0f
// LEDの明るさを更新する周波数 (Hz)
// この周波数でPWM割り込みが発生する
#define EFFECT_UPDATE_FREQ_HZ 1000
// サイン波ルックアップテーブルのサイズ
#define SINE_LUT_SIZE 256

static uint slice_num = 0;
static uint sub_slice = 0;
static uint16_t wrap = 0;
// サイン波の値を格納するルックアップテーブル
static uint16_t sine_lut[SINE_LUT_SIZE];

void pwm_irq_handler(void)
{
    // 割り込みフラグをクリア
    pwm_clear_irq(slice_num);

    // 0.5Hzの呼吸エフェクトを実現するためのカウンタ
    // (EFFECT_UPDATE_FREQ_HZ回で1周期 = 1秒)
    static uint effect_counter = 0;

    // カウンタをルックアップテーブルのインデックスにマッピング
    uint lut_index = (effect_counter * SINE_LUT_SIZE) / EFFECT_UPDATE_FREQ_HZ;
    uint16_t level = sine_lut[lut_index];

    // 計算済みの値をPWMデューティ比として設定
    pwm_set_gpio_level(LED_PIN, level);
    pwm_set_gpio_level(PWM_SUB_PIN, level);

    if(++effect_counter >= EFFECT_UPDATE_FREQ_HZ) {
        effect_counter = 0;
    }
}

int main()
{
    stdio_init_all();

    gpio_set_function(LED_PIN,GPIO_FUNC_PWM );
    gpio_set_function(PWM_SUB_PIN,GPIO_FUNC_PWM );

    pwm_config c = pwm_get_default_config();
    // クロック分周を設定
    pwm_config_set_clkdiv(&c, PWM_CLOCK_DIVIDER);
    // PWMのWRAP値（カウンタの最大値）を計算・設定
    // これにより、PWM割り込みが EFFECT_UPDATE_FREQ_HZ で発生するようになる
    wrap = (uint16_t)((clock_get_hz(clk_sys) / PWM_CLOCK_DIVIDER) / EFFECT_UPDATE_FREQ_HZ);
    pwm_config_set_wrap(&c, wrap);

    // プログラム開始時にサイン波のルックアップテーブルを生成
    for (int i = 0; i < SINE_LUT_SIZE; ++i) {
        // 0からPIまでの半周期のサイン波を計算
        double sin_val = sin((double)i * M_PI / (double)SINE_LUT_SIZE);
        // 計算結果をPWMのデューティ比にスケーリングしてテーブルに格納
        sine_lut[i] = (uint16_t)((double)wrap * sin_val);
    }
    // LEDのスライスを設定
    slice_num = pwm_gpio_to_slice_num(LED_PIN);
    pwm_init(slice_num, &c, false);
    // サブのスライスを設定
    sub_slice = pwm_gpio_to_slice_num(PWM_SUB_PIN);
    pwm_init(sub_slice, &c, false);

    // 割り込み設定
    // 割り込みハンドラは片方のスライス(slice_num)にのみ設定すれば、
    // 両方のGPIOを同時に制御できる
    pwm_clear_irq(slice_num);
    pwm_set_irq_enabled(slice_num, true);
    irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_irq_handler);
    irq_set_enabled(PWM_IRQ_WRAP, true);

    // 初期輝度を50%に設定
    pwm_set_gpio_level(LED_PIN, wrap/2);
    pwm_set_gpio_level(PWM_SUB_PIN, wrap/2);

    // 両方のPWMスライスを同時に有効化
    pwm_set_enabled(slice_num, true);
    pwm_set_enabled(sub_slice, true);

    while (true) {
        tight_loop_contents();
    }
}
