/**
 * @file    ble.h
 * @brief   BLE module
 * @author  Kenny Tran
 * @date    Jul 06 2023
 * @version 0.0.1
 *
 * @section LICENSES
 * Copyright (C) Morgan Advanced Programmable Systems, Inc.
 */


#ifndef BLE_H_
#define BLE_H_


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

#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/addr.h>


/*--------------------------------------------------------------------------------------------------
 * MACROS & CONSTANTS
 *------------------------------------------------------------------------------------------------*/
#define BLE_FILENAME                    ("ble")
#define BLE_SETTINGS_FILENAME           ("ble_settings")

#define BLE_DEVICE_NAME_PREFIX          ("CS_")

/*
 * Settings backend storage limits.
 * Zephyr's BT stack stores ~8 sub-keys per bonded peer (LTK, peer addr,
 * IRK, CSRK, flags, CCC entries, etc.).  24 slots gives comfortable headroom.
 */
#define BLE_PAIRING_MAX_ENTRIES        (8)
#define BLE_PAIRING_MAX_KEY_LEN        (32)
#define BLE_PAIRING_MAX_VAL_LEN        (96)



/*--------------------------------------------------------------------------------------------------
 * TYPE DEFINITIONS & ENUMERATIONS
 *------------------------------------------------------------------------------------------------*/
typedef struct BLE_config
{
    char                 adv_name[16];
    bool                 enabled       : 1;
    uint8_t              reserved      : 7;
} __attribute__((packed, aligned(1))) BLE_config_s;

typedef struct
{
    char    key[BLE_PAIRING_MAX_KEY_LEN];
    uint8_t val[BLE_PAIRING_MAX_VAL_LEN];
    uint8_t val_len;
    bool    used         : 1;
    uint8_t reserved     : 7;
} __attribute__((packed, aligned(1))) BLE_settings_entry_s;

typedef struct BLE_settings
{
    bt_addr_le_t         peer_addr;                 /* 7 bytes: type (1) + addr (6) */
    bool                 bonded        : 1;
    uint8_t              reserved      : 7;
    BLE_settings_entry_s settings[BLE_PAIRING_MAX_ENTRIES];
} __attribute__((packed, aligned(1))) BLE_settings_s;

/* Read callback */
typedef ssize_t (*BLE_read_cb_t) (struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
                                  uint16_t len, uint16_t offset);
/* Write callback. */
typedef ssize_t (*BLE_write_cb_t) (struct bt_conn *conn, const struct bt_gatt_attr *attr,
	                               const void *buf, uint16_t len, uint16_t offset, uint8_t flags);

/* CCC callback. */
typedef void (*BLE_ccc_cb_t) (const struct bt_gatt_attr *attr, uint16_t value);


/* Characteristics table for notifications. */
/*--------------------------------------------------------------------------------------------------
 * ATTRIBUTE INDEX LOOKUP TABLE
 * 
 * Each characteristic with CCC takes 3 indices:
 *   - Characteristic declaration
 *   - Characteristic value (this is what we notify on)
 *   - CCC descriptor
 * 
 * Formula: value_index = 1 + (char_position * 3) + 1
 * Where char_position is 0-based position in service definition
 *------------------------------------------------------------------------------------------------*/
typedef enum
{
    BLE_CHAR_ADV_NAME = 0,
    BLE_CHAR_PAIRING,
    BLE_CHAR_RING_COLOR,
    BLE_CHAR_RING_BRIGHTNESS,
    BLE_CHAR_INDICATOR_COLOR,
    BLE_CHAR_INDICATOR_BRIGHTNESS,
    BLE_CHAR_LEVEL_COLOR,
    BLE_CHAR_LEVEL_BRIGHTNESS,
    BLE_CHAR_BUBBLE_BRIGHTNESS,
    BLE_CHAR_FIBER_BRIGHTNESS,
    BLE_CHAR_PIN_BRIGHTNESS,
    BLE_CHAR_LEVEL_CALIBRATE,
    BLE_CHAR_LEVEL_SENSITIVITY,
    BLE_CHAR_LEVEL_OPTION,
    BLE_CHAR_LEVEL_VISCOSITY,
    BLE_CHAR_LEVEL_ANGLE,
    BLE_CHAR_AMBIENT_LIGHT,
    BLE_CHAR_FSM_TIMEOUT,
    BLE_CHAR_FSM_AUTO_BRIGHTNESS,
    BLE_CHAR_FSM_APP_CONFIG,
    BLE_CHAR_APP_MPCB_VERSION,
    BLE_CHAR_APP_RPCB_VERSION,
    BLE_CHAR_APP_VERSION,
    BLE_CHAR_APP_MFG_ID,
    BLE_CHAR_APP_MFG_DATE,
    BLE_CHAR_APP_PN,
    BLE_CHAR_APP_SN,
    BLE_CHAR_APP_POWER_COUNT,
    BLE_CHAR_APP_CLI_ENABLED,
    BLE_CHAR_BATTERY_LEVEL,
    BLE_CHAR_FSM_MODE,

    /* Shot capture service. */
    BLE_CHAR_USER_SHOT_CNT,
    BLE_CHAR_TOTAL_SHOT_CNT,
    BLE_CHAR_SHOT_DATA_REQUEST,
    BLE_CHAR_SHOT_DATA,

    BLE_CHAR_COUNT
} BLE_char_e;



/*--------------------------------------------------------------------------------------------------
 * PRIVATE CONSTANTS & VARIABLES
 *------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------
 * PRIVATE FUNCTION PROTOTYPES
 *------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------
 * PUBLIC FUNCTION PROTOTYPES
 *------------------------------------------------------------------------------------------------*/
void BLE_init (void);

void BLE_adv_name_set (char *p_str);

void BLE_enable (bool en, bool save);

bool BLE_is_enabled (void);

bool BLE_is_connected (void);

void BLE_notify (BLE_char_e idx, const void *p_data, uint16_t len);

/**
 * @brief Notify BLE that shot data is ready, then push it to phone via notifications.
 * @param p_data    Pointer to shot data buffer (header + data).
 * @param total_len Total length of header + shot data.
 */
void BLE_shot_data_ready(uint8_t *p_data, uint32_t total_len);

/**
 * @brief Notify BLE that no shot data file was found.
 */
void BLE_shot_data_not_found(void);

/**
 * @brief Notify BLE that a timeout occurred while waiting for phone to send shot data consumed.
 */
void BLE_shot_data_timeout(void);

void BLE_cli_cmd (int32_t argc, char **argv);


#endif /* BLE_H_ */
