#ifndef __HCI_DRIVER_H__
#define __HCI_DRIVER_H__

#include <stdbool.h>

#include "utils/simple_buf.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Receive data from the controller/HCI driver.
 *
 * This is the main function through which the HCI driver provides the
 * host with data from the controller. The buffer needs to have its type
 * set with the help of bt_buf_set_type() before calling this API.
 *
 * When CONFIG_BT_RECV_IS_RX_THREAD is defined then this API should not be used
 * for so-called high priority HCI events, which should instead be delivered to
 * the host stack through bt_recv_prio().
 *
 * @param buf Network buffer containing data from the controller.
 *
 * @return 0 on success or negative error number on failure.
 */
int bt_recv(simple_buf_t *buf);

/**
 * @brief Receive high priority data from the controller/HCI driver.
 *
 * This is the same as bt_recv(), except that it should be used for
 * so-called high priority HCI events. There's a separate
 * bt_hci_evt_get_flags() helper that can be used to identify which events
 * have the BT_HCI_EVT_FLAG_RECV_PRIO flag set.
 *
 * As with bt_recv(), the buffer needs to have its type set with the help of
 * bt_buf_set_type() before calling this API. The only exception is so called
 * high priority HCI events which should be delivered to the host stack through
 * bt_recv_prio() instead.
 *
 * @param buf Network buffer containing data from the controller.
 *
 * @return 0 on success or negative error number on failure.
 */
int bt_recv_prio(simple_buf_t *buf);

/** Possible values for the 'bus' member of the bt_hci_driver struct */
enum bt_hci_driver_bus
{
    BT_HCI_DRIVER_BUS_VIRTUAL = 0,
    BT_HCI_DRIVER_BUS_USB = 1,
    BT_HCI_DRIVER_BUS_PCCARD = 2,
    BT_HCI_DRIVER_BUS_UART = 3,
    BT_HCI_DRIVER_BUS_RS232 = 4,
    BT_HCI_DRIVER_BUS_PCI = 5,
    BT_HCI_DRIVER_BUS_SDIO = 6,
    BT_HCI_DRIVER_BUS_SPI = 7,
    BT_HCI_DRIVER_BUS_I2C = 8,
    BT_HCI_DRIVER_BUS_IPM = 9,
};

/**
 * @brief Abstraction which represents the HCI transport to the controller.
 *
 * This struct is used to represent the HCI transport to the Bluetooth
 * controller.
 */
struct bt_hci_driver
{
    /**
     * @brief Open the HCI transport.
     *
     * Opens the HCI transport for operation. This function must not
     * return until the transport is ready for operation, meaning it
     * is safe to start calling the send() handler.
     *
     * If the driver uses its own RX thread, i.e.
     * CONFIG_BT_RECV_IS_RX_THREAD is set, then this
     * function is expected to start that thread.
     *
     * @return 0 on success or negative error number on failure.
     */
    int (*open)(void* arg);

    /**
     * @brief Send HCI buffer to controller.
     *
     * Send an HCI command or ACL data to the controller. The exact
     * type of the data can be checked with the help of bt_buf_get_type().
     *
     * @note This function must only be called from a cooperative thread.
     *
     * @param buf Buffer containing data to be sent to the controller.
     *
     * @return 0 on success or negative error number on failure.
     */
    int (*send)(simple_buf_t *buf);

    /**
     * @brief For hci sync work.
     *
     */
    void (*polling)(void);
};

/**
 * @brief Register a new HCI driver to the Bluetooth stack.
 *
 * This needs to be called before any application code runs. The bt_enable()
 * API will fail if there is no driver registered.
 *
 * @param drv A bt_hci_driver struct representing the driver.
 *
 * @return 0 on success or negative error number on failure.
 */
int bt_hci_driver_register(const struct bt_hci_driver *drv);

/**
 * @brief Setup the HCI transport, which usually means to reset the
 * Bluetooth IC.
 *
 * @note A weak version of this function is included in the H4 driver, so
 *       defining it is optional per board.
 *
 * @param dev The device structure for the bus connecting to the IC
 *
 * @return 0 on success, negative error value on failure
 */
// int bt_hci_transport_setup(const struct device *dev);

/** Allocate an HCI event buffer.
 *
 * This function allocates a new buffer for an HCI event. It is given the
 * avent code and the total length of the parameters. Upon successful return
 * the buffer is ready to have the parameters encoded into it.
 *
 * @param evt        Event OpCode.
 * @param len        Length of event parameters.
 *
 * @return Newly allocated buffer.
 */
simple_buf_t *bt_hci_evt_create(uint8_t evt, uint8_t len);

/** Allocate an HCI Command Complete event buffer.
 *
 * This function allocates a new buffer for HCI Command Complete event.
 * It is given the OpCode (encoded e.g. using the BT_OP macro) and the total
 * length of the parameters. Upon successful return the buffer is ready to have
 * the parameters encoded into it.
 *
 * @param op         Command OpCode.
 * @param plen       Length of command parameters.
 *
 * @return Newly allocated buffer.
 */
simple_buf_t *bt_hci_cmd_complete_create(uint16_t op, uint8_t plen);

/** Allocate an HCI Command Status event buffer.
 *
 * This function allocates a new buffer for HCI Command Status event.
 * It is given the OpCode (encoded e.g. using the BT_OP macro) and the status
 * code. Upon successful return the buffer is ready to have the parameters
 * encoded into it.
 *
 * @param op         Command OpCode.
 * @param status     Status code.
 *
 * @return Newly allocated buffer.
 */
simple_buf_t *bt_hci_cmd_status_create(uint16_t op, uint8_t status);

struct bt_hci_chipset_driver
{
    /**
     * @brief init work process.
     *
     */
    void (*init_work)(void);
    /**
     * @brief Boot work process.
     *
     */
    void (*boot_start)(void);

    /**
     * @brief Prepare work process.
     *
     * Work after send reset command.
     *
     */
    void (*prepare_start)(void);

    void (*event_process)(uint8_t event, simple_buf_t *buf);
};

/**
 * @typedef bt_hci_event_process_t
 * @brief Callback for hci event handle.
 *
 * @param err zero on success or (negative) error code otherwise.
 */
typedef void (*bt_hci_event_process_t)(uint8_t event, simple_buf_t *buf);

void bt_hci_set_boot_ready(void);

void bt_hci_set_prepare_ready(void);

int bt_hci_chipset_driver_register(const struct bt_hci_chipset_driver *drv);

#ifdef __cplusplus
}
#endif

/**
 * @}
 */

#endif