/*
 * Kneron peripheral driver test code for GPIO
 *
 * Copyright (C) 2019 Kneron, Inc. All rights reserved.
 *
 */

#include "cmsis_os2.h"

#include "kdrv_pinmux.h"
#include "kdrv_gpio.h"
#include "kmdw_console.h"

static void gpio_test_thread(void *argument);
static void gpio_callback(kdrv_gpio_pin_t pin, void *arg);

void gpio_example_init(void)
{
    DSG("Creating a user thread for interrupt notification\n");

    // create a thread to wait for interrupt notifications
    osThreadNew(&gpio_test_thread, NULL, NULL);

    DSG("Configuring pins to GPIO function, GPIO22(SD_CLK), GPIO23(SD_CMD), GPIO24(SD_DAT0), GPIO25(SD_DAT1)\n");

    /* 
       configure selected pins as GPIO function (pinmux)
       users must check pinmux table to configure specified pins
       as desired peripheral functions properly
    */
    kdrv_pinmux_config(KDRV_PIN_SD_CLK, PIN_MODE_3, PIN_PULL_NONE, PIN_DRIVING_8MA); // as GPIO 22
    kdrv_pinmux_config(KDRV_PIN_SD_CMD, PIN_MODE_3, PIN_PULL_UP, PIN_DRIVING_8MA);   // as GPIO 23
    kdrv_pinmux_config(KDRV_PIN_SD_DAT_0, PIN_MODE_3, PIN_PULL_UP, PIN_DRIVING_8MA); // as GPIO 24
    kdrv_pinmux_config(KDRV_PIN_SD_DAT_1, PIN_MODE_3, PIN_PULL_UP, PIN_DRIVING_8MA); // as GPIO 25

    DSG("init gpio controller\n");

    // init GPIO controller
    kdrv_gpio_initialize();

    DSG("setting GPIO22 : Output Low\n");

    // set GPIO 22 as output low in the beginning
    kdrv_gpio_set_attribute(GPIO_PIN_22, GPIO_DIR_OUTPUT);
    kdrv_gpio_write_pin(GPIO_PIN_22, false);

    DSG("setting GPIO23 : Input with pull-high\n");

    // set GPIO 23 as digital input
    kdrv_gpio_set_attribute(GPIO_PIN_23, GPIO_DIR_INPUT);

    DSG("setting GPIO24 : Interrupt source, pull-high, debounce\n");

    /* set GPIO 24 as interrupt input, pull-high, debounce */
    {
        // first disable interrupt in case of wrong condition
        kdrv_gpio_set_interrupt(GPIO_PIN_24, false);

        // set pin attributes as desired
        kdrv_gpio_set_attribute(GPIO_PIN_24, (GPIO_DIR_INPUT | GPIO_INT_EDGE_FALLING));

        // enable internal hardware debounce with clock rate
        kdrv_gpio_set_debounce(GPIO_PIN_24, true /* 1 for enable */, 1000);

        // at last enable interrupt after all settings done
        kdrv_gpio_set_interrupt(GPIO_PIN_24, true);
    }

    DSG("setting GPIO25 : Interrupt source, pull-high, debounce\n");

    /* set GPIO 25 as interrupt input, pull-high, debounce */
    {
        // first disable interrupt in case of wrong condition
        kdrv_gpio_set_interrupt(GPIO_PIN_25, false);

        // set pin attributes as desired
        kdrv_gpio_set_attribute(GPIO_PIN_25, (GPIO_DIR_INPUT | GPIO_INT_EDGE_FALLING));

        // enable internal hardware debounce with clock rate
        kdrv_gpio_set_debounce(GPIO_PIN_25, true /* 1 for enable */, 1000);

        // at last enable interrupt after all settings done
        kdrv_gpio_set_interrupt(GPIO_PIN_25, true);
    }

    // set interrupt callback for GPIO interrupt
    kdrv_gpio_register_callback(gpio_callback, NULL);

    /* exit here then let kernel get started */
}

static void gpio_callback(kdrv_gpio_pin_t pin, void *arg)
{
    if (pin == GPIO_PIN_24)
    {
        static bool toogle = false;
        /* print something */
        DSG("GPIO24(SD_DAT0) btn is clicked, now inverse GPIO22(SD_CLK)\n");

        toogle = toogle ? false : true;
        kdrv_gpio_write_pin(GPIO_PIN_22, toogle);
    }
    else if (pin == GPIO_PIN_25)
    {
        /* print something */
        DSG("GPIO25(SD_DAT1) btn clicked\n");
    }
}

static void gpio_test_thread(void *argument)
{

    for (;;)
    {
        uint32_t flags = osThreadFlagsWait(0x1, osFlagsWaitAny, 2000); // 2 secs timeout
        if (flags == osFlagsErrorTimeout)
        {
            // do following per 2 secs timeout

            // read GPIO 23
            bool value;
            kdrv_gpio_read_pin(GPIO_PIN_23, &value);

            /* print GPIO 23 value */
            DSG("GPIO23(SD_CMD) input : %s\n", value ? "High" : "Low");
        }
    }
}
