/** 
 * @file    event.c
 * @brief   Event module
 * @author  Kenny Tran
 * @date    Nov 19 2024
 * @version 0.0.1
 *
 * @section LICENSES
 * Copyright (C) Morgan Advanced Programmable Systems, Inc.
 */


/*--------------------------------------------------------------------------------------------------
 * INCLUDE FILES
 *------------------------------------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#include "../lib/errno.h"
#include "../lib/print.h"
#include "../lib/debug.h"

#include "../bsp/button.h"
#include "../bsp/battery.h"
#include "../bsp/wdt.h"

#include "../app/ble.h"
#include "../app/motion.h"
#include "../app/shot_capture.h"

#include "event.h"


/*--------------------------------------------------------------------------------------------------
 * TYPE DEFINITIONS & ENUMERATIONS
 *------------------------------------------------------------------------------------------------*/
typedef enum
{
    _EVENT_STATE_INIT,
    _EVENT_STATE_IDLE,

    _EVENT_STATE_LP,
    _EVENT_STATE_CP,
    _EVENT_STATE_RP,

    _EVENT_STATE_CH,                /* Center press and long hold to enter subconfig. */

    _EVENT_STATE_SUBCONFIG,
    _EVENT_STATE_SUBCONFIG_LP,
    _EVENT_STATE_SUBCONFIG_CP,
    _EVENT_STATE_SUBCONFIG_RP,
    _EVENT_STATE_SUBCONFIG_CH,      /* Center press and long hold in subconfig to exit subconfig. */

    _EVENT_STATE_RHLP,              /* Right hold, Left pressed */

    _EVENT_STATE_RHCP,              /* Right hold, center pressed */

    _EVENT_STATE_LHCP,              /* Left hold, center pressed */

    _EVENT_STATE_LHRP,              /* Left hold, right pressed */

    _EVENT_STATE_RHCHLP,            /* Right hold, center hold, left pressed */

    _EVENT_STATE_LHCHRP,            /* Left hold, center hold, right pressed */


    _EVENT_STATE_SUBCAL,
    _EVENT_STATE_SUBCAL_CH,
} _event_state_e;


/*--------------------------------------------------------------------------------------------------
 * MACROS & CONSTANTS
 *------------------------------------------------------------------------------------------------*/
K_THREAD_STACK_DEFINE(_event_stack, EVENT_STACK_SIZE);


/*--------------------------------------------------------------------------------------------------
 * PRIVATE CONSTANTS & VARIABLES
 *------------------------------------------------------------------------------------------------*/
static struct k_thread _event_thread;
static _event_state_e  _event_state         = _EVENT_STATE_INIT;
static EVENT_e         _event               = EVENT_NONE;
static uint32_t        _event_timer_ms      = 0;
static uint16_t        _event_batt_charging __attribute__((section(".noinit")));


/*--------------------------------------------------------------------------------------------------
 * PRIVATE FUNCTION PROTOTYPES
 *------------------------------------------------------------------------------------------------*/
static void _event_task (void *p1, void *p2, void *p3);


/*--------------------------------------------------------------------------------------------------
 * PUBLIC FUNCTION DEFINITIONS
 *------------------------------------------------------------------------------------------------*/
void EVENT_init (void)
{
    PRINT (INFO, "Initializing EVENT...\r\n");

    /* Initialize BUTTON module. */   
    if (BUTTON_init () != ERRNO_SUCCESS)
    {
        PRINT (ERROR, "Failure to initialize BUTTON.\r\n");
    }

    /* Initialize shot capture. */
    (void) SHOT_CAPTURE_init ();
}

void EVENT_reset (void)
{
    _event_state    = _EVENT_STATE_IDLE;
    _event          = EVENT_NONE;
    _event_timer_ms = 0;
}

bool EVENT_in_process (void)
{
    /* An event is in process if we are not in idle. */
    if (_event_state != _EVENT_STATE_IDLE)
    {
        return true;
    }

    return false;
}

EVENT_e EVENT_last_get (void)
{
    EVENT_e evt = _event;

    /* Clear event once read. */
    _event = EVENT_NONE;

    return evt;
}

void EVENT_force (EVENT_e event)
{
    switch (event)
    {
        case EVENT_CHARGER_CONNECTED:
            _event       = EVENT_CHARGER_CONNECTED;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_CHARGER_DISCONNECTED:
            _event       = EVENT_CHARGER_DISCONNECTED;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_BATTERY_FULL:
            _event       = EVENT_BATTERY_FULL;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_ACCEL_MOTION:
            _event       = EVENT_ACCEL_MOTION;
            _event_state = _EVENT_STATE_IDLE;
            break;

         case EVENT_GYRO_MOTION:
            _event       = EVENT_GYRO_MOTION;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_POWER:
            _event       = EVENT_POWER;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_DECREASE_PIN_BRIGHTNESS:
            _event       = EVENT_DECREASE_PIN_BRIGHTNESS;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_INCREASE_PIN_BRIGHTNESS:
            _event       = EVENT_INCREASE_PIN_BRIGHTNESS;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_DECREASE_RING_BRIGHTNESS:
            _event       = EVENT_DECREASE_RING_BRIGHTNESS;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_INCREASE_RING_BRIGHTNESS:
            _event       = EVENT_INCREASE_RING_BRIGHTNESS;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_CONFIG_ENTER:
            _event       = EVENT_CONFIG_ENTER;
            _event_state = _EVENT_STATE_CH;
            break;

        case EVENT_SUBCONFIG_PREV:
            _event       = EVENT_SUBCONFIG_PREV;
            _event_state = _EVENT_STATE_SUBCONFIG;
            break;

        case EVENT_SUBCONFIG_MODE_CHANGE:
            _event       = EVENT_SUBCONFIG_MODE_CHANGE;
            _event_state = _EVENT_STATE_SUBCONFIG;
            break;

        case EVENT_SUBCONFIG_NEXT:
            _event       = EVENT_SUBCONFIG_NEXT;
            _event_state = _EVENT_STATE_SUBCONFIG;
            break;

        case EVENT_CONFIG_EXIT:
            _event       = EVENT_CONFIG_EXIT;
            _event_state = _EVENT_STATE_SUBCONFIG_CH;
            break;

        case EVENT_AUTO_BRIGHTNESS:
            _event = EVENT_AUTO_BRIGHTNESS;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_BLE_ENABLE:
            _event       = EVENT_BLE_ENABLE;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_BLE_DISABLE:
            _event       = EVENT_BLE_DISABLE;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_BLE_CONNECTED:
            _event       = EVENT_BLE_CONNECTED;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_BLE_DISCONNECTED:
            _event       = EVENT_BLE_DISCONNECTED;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_FACTORY_RESET:
            _event       = EVENT_FACTORY_RESET;
            _event_state = _EVENT_STATE_IDLE;
            break;

        case EVENT_SUBCAL_START:
            _event       = EVENT_SUBCAL_START;
            _event_state = _EVENT_STATE_SUBCAL;
            break;

        case EVENT_SUBCAL_NEXT:
            _event       = EVENT_SUBCAL_NEXT;
            _event_state = _EVENT_STATE_SUBCAL;
            break;

        case EVENT_SHOT_DETECTED:
            _event       = EVENT_SHOT_DETECTED;
            _event_state = _EVENT_STATE_IDLE;
            break;
    }

    /* Reset timer counter. */
    _event_timer_ms = 0;
}

void EVENT_task_suspend (void)
{
    k_thread_suspend (&_event_thread);
}

void EVENT_task_resume (void)
{
    k_thread_resume (&_event_thread);
}

void EVENT_task_install (void)
{
    static k_tid_t id;

    id = k_thread_create (&_event_thread,
                          _event_stack,
                          EVENT_STACK_SIZE,
                          _event_task,
                          NULL,
                          NULL,
                          NULL,
                          EVENT_THREAD_PRIORITY,
                          0,
                          K_NO_WAIT);
    k_thread_name_set(&_event_thread, "EVENT_task");  
}

void EVENT_cli_cmd (int32_t argc, char **argv)
{
    EVENT_e evt;

    if (argc == 0)
    {
        evt = EVENT_last_get ();

        PRINT (INFO, "EVENT\r\n");
        PRINT (INFO, "-------------------------------------------\r\n");
        PRINT (INFO, "Last event :  ");
        switch (evt)
        {
            case EVENT_NONE:
                PRINT (INFO, "NONE\r\n");
                break;

            case EVENT_CHARGER_CONNECTED:
                PRINT (INFO, "CHARGER_CONNECTED\r\n");
                break;

            case EVENT_CHARGER_DISCONNECTED:
                PRINT (INFO, "CHARGER_DISCONNECTED\r\n");
                break;

            case EVENT_BATTERY_FULL:
                PRINT (INFO, "BATTERY_FULL\r\n");
                break;

            case EVENT_ACCEL_MOTION:
                PRINT (INFO, "ACCEL_MOTION\r\n");
                break;

            case EVENT_GYRO_MOTION:
                PRINT (INFO, "GYRO_MOTION\r\n");
                break;

            case EVENT_POWER:
                PRINT (INFO, "POWER\r\n");
                break;

            case EVENT_DECREASE_PIN_BRIGHTNESS:
                PRINT (INFO, "DECREASE_PIN_BRIGHTNESS\r\n");
                break;

            case EVENT_INCREASE_PIN_BRIGHTNESS:
                PRINT (INFO, "INCREASE_PIN_BRIGHTNESS\r\n");
                break;

            case EVENT_DECREASE_RING_BRIGHTNESS:
                PRINT (INFO, "DECREASE_RING_BRIGHTNESS\r\n");
                break;

            case EVENT_INCREASE_RING_BRIGHTNESS:
                PRINT (INFO, "INCREASE_RING_BRIGHTNESS\r\n");
                break;

            case EVENT_CONFIG_ENTER:
                PRINT (INFO, "CONFIG_ENTER\r\n");
                break;

            case EVENT_SUBCONFIG_PREV:
                PRINT (INFO, "SUBCONFIG_PREV\r\n");
                break;

            case EVENT_SUBCONFIG_MODE_CHANGE:
                PRINT (INFO, "SUBCONFIG_MODE_CHANGE\r\n");
                break;

            case EVENT_SUBCONFIG_NEXT:
                PRINT (INFO, "SUBCONFIG_NEXT\r\n");
                break;

            case EVENT_CONFIG_EXIT:
                PRINT (INFO, "CONFIG_EXIT\r\n");
                break;

            case EVENT_AUTO_BRIGHTNESS:
                PRINT (INFO, "AUTO_BRIGHTNESS\r\n");
                break;

            case EVENT_BLE_ENABLE:
                PRINT (INFO, "EVENT_BLE_ENABLE\r\n");
                break;

            case EVENT_BLE_DISABLE:
                PRINT (INFO, "EVENT_BLE_DISABLE\r\n");
                break;

            case EVENT_BLE_CONNECTED:
                PRINT (INFO, "BLE_CONNECTED\r\n");
                break;

            case EVENT_BLE_DISCONNECTED:
                PRINT (INFO, "BLE_DISCONNECTED\r\n");
                break;

            case EVENT_FACTORY_RESET:
                PRINT (INFO, "FACTORY RESET\r\n");
                break;

            case EVENT_SUBCAL_START:
                PRINT (INFO, "SUBCAL_START\r\n");
                break;

            case EVENT_SUBCAL_NEXT:
                PRINT (INFO, "SUBCAL_NEXT\r\n");
                break;

            case EVENT_SHOT_DETECTED:
                PRINT (INFO, "SHOT_DETECTED\r\n");
                break;
        }

        PRINT (INFO, "_event_state :  %d\r\n", _event_state);
    }
    else if (argc == 2)
    {
        if (!strcmp (argv[0], "--set") || !strcmp (argv[0], "-s"))
        {
            if (!strcmp (argv[1], "cc"))
            {
                EVENT_force (EVENT_CHARGER_CONNECTED);
            }
            else if (!strcmp (argv[1], "cd"))
            {
                EVENT_force (EVENT_CHARGER_DISCONNECTED);
            }
            else if (!strcmp (argv[1], "bfull"))
            {
                EVENT_force (EVENT_BATTERY_FULL);
            }
            else if (!strcmp (argv[1], "accel_motion"))
            {
                EVENT_force (EVENT_ACCEL_MOTION);
            }
            else if (!strcmp (argv[1], "gyro_motion"))
            {
                EVENT_force (EVENT_GYRO_MOTION);
            }
            else if (!strcmp (argv[1], "power"))
            {
                EVENT_force (EVENT_POWER);
            }
            else if (!strcmp (argv[1], "p-"))
            {
                EVENT_force (EVENT_DECREASE_PIN_BRIGHTNESS);
            }
            else if (!strcmp (argv[1], "p+"))
            {
                EVENT_force (EVENT_INCREASE_PIN_BRIGHTNESS);
            }
            else if (!strcmp (argv[1], "r-"))
            {
                EVENT_force (EVENT_DECREASE_RING_BRIGHTNESS);
            }
            else if (!strcmp (argv[1], "r+"))
            {
                EVENT_force (EVENT_INCREASE_RING_BRIGHTNESS);
            }
            else if (!strcmp (argv[1], "cfg"))
            {
                EVENT_force (EVENT_CONFIG_ENTER);
            }
            else if (!strcmp (argv[1], "cfg-"))
            {
                EVENT_force (EVENT_SUBCONFIG_PREV);
            }
            else if (!strcmp (argv[1], "cfgmode"))
            {
                EVENT_force (EVENT_SUBCONFIG_MODE_CHANGE);
            }
            else if (!strcmp (argv[1], "cfg+"))
            {
                EVENT_force (EVENT_SUBCONFIG_NEXT);
            }
            else if (!strcmp (argv[1], "cfgexit"))
            {
                EVENT_force (EVENT_CONFIG_EXIT);
            }
            else if (!strcmp (argv[1], "autobright"))
            {
                EVENT_force (EVENT_AUTO_BRIGHTNESS);
            }
            else if (!strcmp (argv[1], "bleen"))
            {
                EVENT_force (EVENT_BLE_ENABLE);
            }
            else if (!strcmp (argv[1], "bledis"))
            {
                EVENT_force (EVENT_BLE_DISABLE);
            }
            else if (!strcmp (argv[1], "bleconn"))
            {
                EVENT_force (EVENT_BLE_CONNECTED);
            }
            else if (!strcmp (argv[1], "bledisconn"))
            {
                EVENT_force (EVENT_BLE_DISCONNECTED);
            }
            else if (!strcmp (argv[1], "freset"))
            {
                EVENT_force (EVENT_FACTORY_RESET);
            }
            else if (!strcmp (argv[1], "calstart"))
            {
                EVENT_force (EVENT_SUBCAL_START);
            }
            else if (!strcmp (argv[1], "calnext"))
            {
                EVENT_force (EVENT_SUBCAL_NEXT);
            }
            else if (!strcmp (argv[1], "shotdet"))
            {
                EVENT_force (EVENT_SUBCAL_NEXT);
            }
            else
            {
                goto USAGE;
            }
        }
        else
        {
            goto USAGE;
        }
    }
    else
    {
USAGE:
        PRINT (INFO, "Usage: event [OPTION...]\r\n");
        PRINT (INFO, "  -s | --set           Set an event\r\n");
        PRINT (INFO, "    <%%s>               cc (charger connected)\r\n");
        PRINT (INFO, "                       cd (charger disconnected)\r\n");
        PRINT (INFO, "                       bfull (battery full)\r\n");
        PRINT (INFO, "                       accel_motion\r\n");
        PRINT (INFO, "                       gyro_motion\r\n");
        PRINT (INFO, "                       power\r\n");
        PRINT (INFO, "                       p- (decrease pin brightness)\r\n");
        PRINT (INFO, "                       p+ (increase pin brightness)\r\n");
        PRINT (INFO, "                       r- (decrease ring brightness)\r\n");
        PRINT (INFO, "                       r+ (increase ring brightness)\r\n");
        PRINT (INFO, "                       cfg\r\n");
        PRINT (INFO, "                       cfg-\r\n");
        PRINT (INFO, "                       cfgmode\r\n");
        PRINT (INFO, "                       cfg+\r\n");
        PRINT (INFO, "                       cfgexit\r\n");
        PRINT (INFO, "                       ble\r\n");
        PRINT (INFO, "                       freset\r\n");
        PRINT (INFO, "                       calstart\r\n");
        PRINT (INFO, "                       calnext\r\n");
        PRINT (INFO, "                       shotdet\r\n");
    }
}


/*--------------------------------------------------------------------------------------------------
 * PRIVATE FUNCTION DEFINITIONS
 *------------------------------------------------------------------------------------------------*/
static void _event_task (void *p1, void *p2, void *p3)
{
    static bool     prev_ble_connected = false;
    static uint32_t prev_shot_count    = 0;
           bool     left_pressed;
           bool     center_pressed;
           bool     right_pressed;
           bool     is_charging;

    while (1)
    {
        DBG_STAT_INC(event_task_counter);
        DBG_STAT_INC_IF(i2c_transfer_active,event_task_during_i2c_counter);
        /* Read button states. */
        (void) BUTTON_is_pressed (BUTTON_LEFT,   &left_pressed);
        (void) BUTTON_is_pressed (BUTTON_CENTER, &center_pressed);
        (void) BUTTON_is_pressed (BUTTON_RIGHT,  &right_pressed);

        /* Check charging status. */
        is_charging = BATTERY_is_charging ();

        switch (_event_state)
        {
            case _EVENT_STATE_INIT:
                /* Update previous charging state. */
                _event_batt_charging = (_event_batt_charging << 1) | (uint16_t) is_charging;

                /* On init, prev shot count will be 0.  This will always generate a SHOT DETECTED event in IDLE.
                   Set here to prevent false event. */
                prev_shot_count = SHOT_CAPTURE_config_get ()->user_shot_cnt;

                _event_state = _EVENT_STATE_IDLE;
                break;

            case _EVENT_STATE_IDLE:
                /* Check for button presses. */
                if (left_pressed)
                {
                    _event_state = _EVENT_STATE_LP;
                }
                else if (center_pressed)
                {
                    _event_state = _EVENT_STATE_CP;
                }
                else if (right_pressed)
                {
                    _event_state = _EVENT_STATE_RP;
                }
                
                /* Check if charger is connected / disconnected. */
                if ((_event_batt_charging == 0) && is_charging)
                {
                    float voltage;

                    if (BATTERY_voltage_get (&voltage))
                    {
                        PRINT (ERROR, "Failure to read battery voltage.\r\n");
                    }
                    
                    /* If we are greated than 4.1V, connected event likely means it's because the battery is full and pulse charging. */
                    if (voltage < 4.1f)
                    {
                        _event = EVENT_CHARGER_CONNECTED;
                    }
                }
                else if ((_event_batt_charging == 0xFFFF) && !is_charging)
                {
                    float voltage;

                    if (BATTERY_voltage_get (&voltage))
                    {
                        PRINT (ERROR, "Failure to read battery voltage.\r\n");
                    }
                    
                    /* If we are greated than 4.1V, disconnected event likely means it's because the battery is full. */
                    if (voltage >= 4.1f)
                    {
                        _event = EVENT_BATTERY_FULL;    
                    }
                    else
                    {
                        _event = EVENT_CHARGER_DISCONNECTED;
                    }
                }
                /* Check for BLE connection. */
                else if (!prev_ble_connected && BLE_is_connected ())
                {
                    _event = EVENT_BLE_CONNECTED;
                }
                else if (prev_ble_connected && !BLE_is_connected ())
                {
                    _event = EVENT_BLE_DISCONNECTED;
                }
                /* Check for shot. */
                else if (SHOT_CAPTURE_config_get ()->user_shot_cnt != prev_shot_count)
                {
                    _event = EVENT_SHOT_DETECTED;
                }
                /* Check for accel motion. */
                else if (MOTION_linear_detected ())
                {
                    _event = EVENT_ACCEL_MOTION;
                }

                /* Check for gyro motion. */
                else if (MOTION_angular_detected())
                {
                    _event = EVENT_GYRO_MOTION;
                }
                
                /* Update previous shot count. */
                prev_shot_count = SHOT_CAPTURE_config_get ()->user_shot_cnt;
                
                /* Update previous charging state. */
                _event_batt_charging = (_event_batt_charging << 1) | (uint16_t) is_charging;

                /* Update previous BLE state. */
                prev_ble_connected = BLE_is_connected ();
                break;

            case _EVENT_STATE_LP:
                if (left_pressed)
                {
                    /* Check if center is pressed while left is held. */
                    if (center_pressed)
                    {
                        _event_state = _EVENT_STATE_LHCP;
                    }
                    else if (right_pressed)
                    {
                        _event_state = _EVENT_STATE_LHRP;
                    }
                    /* Check if hold time meets short hold interval. */
                    else if (_event_timer_ms >= EVENT_SHORT_HOLD_PERIOD_MS)
                    {
                        /* Center button has been held for EVENT_SHORT_HOLD_PERIOD_MS.  Set event */
                        _event       = EVENT_DECREASE_RING_BRIGHTNESS;
                        _event_state = _EVENT_STATE_IDLE;
                        /* Reset timer counter. */
                        _event_timer_ms = 0;
                    }
                    else
                    {
                        _event_timer_ms += EVENT_TASK_PERIOD_MS;
                    }
                }
                else
                {
                    /* Left button pressed and released.  Set event and reset to idle state. */
                    _event       = EVENT_DECREASE_PIN_BRIGHTNESS;
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_CP:
                if (center_pressed)
                {
                    /* Check if hold time meets long hold interval. */
                    if (_event_timer_ms >= EVENT_LONG_HOLD_PERIOD_MS)
                    {
                        /* Center button has been held for EVENT_LONG_HOLD_PERIOD_MS.  Set event and move to sub config state. */
                        _event       = EVENT_CONFIG_ENTER;
                        _event_state = _EVENT_STATE_CH;
                        /* Reset timer counter. */
                        _event_timer_ms = 0;
                    }
                    else
                    {
                        _event_timer_ms += EVENT_TASK_PERIOD_MS;
                    }
                }
                else
                {
                    /* Reset timer counter. */
                    _event_timer_ms = 0;
                    /* Center button pressed and released.  Set event and reset to idle state. */
                    _event       = EVENT_POWER;
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_RP:
                if (right_pressed)
                {
                    /* Check if left is pressed while right is held. */
                    if (left_pressed)
                    {
                        _event_state = _EVENT_STATE_RHLP;
                    }
                    /* Check if center is pressed while right is held. */
                    else if (center_pressed)
                    {
                        _event_state = _EVENT_STATE_RHCP;
                    }
                    /* Check if hold time meets short hold interval. */
                    else if (_event_timer_ms >= EVENT_SHORT_HOLD_PERIOD_MS)
                    {
                        /* Center button has been held for EVENT_SHORT_HOLD_PERIOD_MS.  Set event */
                        _event       = EVENT_INCREASE_RING_BRIGHTNESS;
                        _event_state = _EVENT_STATE_IDLE;
                        /* Reset timer counter. */
                        _event_timer_ms = 0;
                    }
                    else
                    {
                        _event_timer_ms += EVENT_TASK_PERIOD_MS;
                    }
                }
                else
                {
                    /* Right button pressed and released.  Set event and reset to idle state. */
                    _event       = EVENT_INCREASE_PIN_BRIGHTNESS;
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_CH:
                if (!center_pressed)
                {
                    /* Once released, go to subconfig state. */
                    _event_state = _EVENT_STATE_SUBCONFIG;
                }
                break;

            case _EVENT_STATE_SUBCONFIG:
                if (left_pressed)
                {
                    _event_state = _EVENT_STATE_SUBCONFIG_LP;
                }
                else if (center_pressed)
                {
                    _event_state = _EVENT_STATE_SUBCONFIG_CP;
                }
                else if (right_pressed)
                {
                    _event_state = _EVENT_STATE_SUBCONFIG_RP;
                }
                break;

            case _EVENT_STATE_SUBCONFIG_LP:
                if (!left_pressed)
                {
                    /* Left button pressed while in subconfig.  Set event and go back to subconfig state. */
                    _event       = EVENT_SUBCONFIG_PREV;
                    _event_state = _EVENT_STATE_SUBCONFIG;
                }
                break;

            case _EVENT_STATE_SUBCONFIG_CP:
                if (center_pressed)
                {
                    /* Check if hold time meets long hold interval. */
                    if (_event_timer_ms >= EVENT_LONG_HOLD_PERIOD_MS)
                    {
                        /* Center button has been held for EVENT_LONG_HOLD_PERIOD_MS.  Set event and reset state. */
                        _event       = EVENT_CONFIG_EXIT;
                        _event_state = _EVENT_STATE_SUBCONFIG_CH;
                        /* Reset timer counter. */
                        _event_timer_ms = 0;
                    }
                    else
                    {
                        _event_timer_ms += EVENT_TASK_PERIOD_MS;
                    }
                }
                else
                {
                    /* Reset timer counter. */
                    _event_timer_ms = 0;
                    /* Center button pressed and released while in sub config.  Set event and go back to subconfig state. */
                    _event       = EVENT_SUBCONFIG_MODE_CHANGE;
                    _event_state = _EVENT_STATE_SUBCONFIG;
                }
                break;

            case _EVENT_STATE_SUBCONFIG_RP:
                if (!right_pressed)
                {
                    /* Right button pressed while in subconfig.  Set event and go back to subconfig state. */
                    _event       = EVENT_SUBCONFIG_NEXT;
                    _event_state = _EVENT_STATE_SUBCONFIG;
                }
                break;


            case _EVENT_STATE_SUBCONFIG_CH:
                if (!center_pressed)
                {
                    /* Once released, go back to idle. */
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_RHLP:
                if (left_pressed && right_pressed)
                {
                    /* Check if hold time meets long hold interval. */
                    if (_event_timer_ms >= EVENT_CALIBRATION_PERIOD_MS)
                    {
                        /* Right and left habe been held for EVENT_CALIBRATION_PERIOD_MS.  Set event. */
                        _event       = EVENT_SUBCAL_START;
                        _event_state = _EVENT_STATE_SUBCAL;
                        /* Reset timer counter. */
                        _event_timer_ms = 0;
                    }
                    else
                    {
                        _event_timer_ms += EVENT_TASK_PERIOD_MS;
                    }
                }
                else
                {
                    /* Reset timer counter. */
                    _event_timer_ms = 0;
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_RHCP:
                if (right_pressed && center_pressed)
                {
                    /* Check if left is pressed while right and center are held. */
                    if (left_pressed)
                    {
                        _event_state = _EVENT_STATE_RHCHLP;
                    }
                }
                else
                {
                    /* Reset to idle state. */
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;
                

            case _EVENT_STATE_LHRP:
                if (!right_pressed)
                {
                    /* If left pressed and held, then right pressed and released, set auto brightness event. */
                    _event = EVENT_AUTO_BRIGHTNESS;
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_LHCP:
                if (left_pressed && center_pressed)
                {
                    /* Check if right is pressed while left and center are held. */
                    if (right_pressed)
                    {
                        _event_state = _EVENT_STATE_LHCHRP;
                    }
                }
                else
                {
                    /* Reset to idle state. */
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_RHCHLP:
                if (right_pressed && center_pressed && left_pressed)
                {
                    
                }
                else
                {
                    /* Reset timer counter. */
                    _event_timer_ms = 0;
                    /* On all three button released, enable BLE. */
                    _event       = EVENT_BLE_DISABLE;
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_LHCHRP:
                if (left_pressed && center_pressed && right_pressed)
                {
                    /* Check if hold time meets long hold interval. */
                    if (_event_timer_ms >= EVENT_FACTORY_RESET_PERIOD_MS)
                    {
                        /* Center button has been held for EVENT_FACTORY_RESET_PERIOD_MS.  Set event. */
                        _event       = EVENT_FACTORY_RESET;
                        _event_state = _EVENT_STATE_IDLE;
                        /* Reset timer counter. */
                        _event_timer_ms = 0;
                    }
                    else
                    {
                        _event_timer_ms += EVENT_TASK_PERIOD_MS;
                    }
                }
                else
                {
                    /* Reset timer counter. */
                    _event_timer_ms = 0;
                    /* On all three button released, enable BLE. */
                    _event       = EVENT_BLE_ENABLE;
                    _event_state = _EVENT_STATE_IDLE;
                }
                break;

            case _EVENT_STATE_SUBCAL:
                if (center_pressed)
                {
                    /* Reset timer counter. */
                    _event_timer_ms = 0;
                    _event_state = _EVENT_STATE_SUBCAL_CH;
                }
                break;

            case _EVENT_STATE_SUBCAL_CH:
                if (!center_pressed)
                {
                    /* Reset timer counter. */
                    _event_timer_ms = 0;
                    _event       = EVENT_SUBCAL_NEXT;
                    _event_state = _EVENT_STATE_SUBCAL;
                }
                break;
        }

        /* Feed watchdog at end of loop. */
        WDT_feed ();

        k_msleep (EVENT_TASK_PERIOD_MS);
    }
}
