#include "band_nctu.h"
#include "error.h"
#include "led.h"
#include "nrf_drv_pwm.h"
#include "nrf_log.h"
#include "nrf_pwm.h"
#include "nrfx_pwm.h"

#define USED_PWM(idx) (1UL << idx)

static bool          _gLedInitialized = false;
static uint8_t       _gPwmUsed        = 0;
static nrf_drv_pwm_t _gPwm0           = NRF_DRV_PWM_INSTANCE(0);

static void _ledPwmConfig(const uint8_t pin) {
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            pin | NRF_DRV_PWM_PIN_INVERTED,       // channel 0
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_125kHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 25000,
        .load_mode    = NRF_PWM_LOAD_COMMON,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&_gPwm0, &config0, NULL));
    _gPwmUsed |= USED_PWM(0);

    // This array cannot be allocated on stack (hence "static") and it must
    // be in RAM (hence no "const", though its content is not changed).
    static uint16_t /*const*/ seqValues[] =
    {
        0x0010
    };
    nrf_pwm_sequence_t const seq =
    {
        .values.p_common = seqValues,
        .length          = NRF_PWM_VALUES_LENGTH(seqValues),
        .repeats         = 0,
        .end_delay       = 4
    };

    nrf_drv_pwm_simple_playback(&_gPwm0, &seq, 3, NRF_DRV_PWM_FLAG_STOP);
}

int ledInit(void) {
    nrf_gpio_cfg_output(LED_R);
    nrf_gpio_cfg_output(LED_G);
    nrf_gpio_cfg_output(LED_B);
    _gLedInitialized = true;

    return 0;
}

int ledClearR(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }

    nrf_gpio_pin_clear(LED_R);

    return 0;
}

int ledClearG(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }

    nrf_gpio_pin_clear(LED_G);

    return 0;
}

int ledClearB(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }

    nrf_gpio_pin_clear(LED_B);

    return 0;
}

int ledClearRGB(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }
        
    ledClearR();
    ledClearG();
    ledClearB();

    return 0;
}    

int ledSetR(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }

    nrf_gpio_pin_set(LED_R);
    _ledPwmConfig(LED_R);

    return 0;
}

int ledSetG(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }

    nrf_gpio_pin_set(LED_G);
    _ledPwmConfig(LED_G);

    return 0;
}

int ledSetB(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }

    nrf_gpio_pin_set(LED_B);
    _ledPwmConfig(LED_B);

    return 0;
}

int ledSetRGB(void) {
    if (!_gLedInitialized) {
        return ERROR_LED_UNINITIALIZED;
    }

    ledSetR();
    ledSetG();
    ledSetB();

    return 0;
}

