# -*- coding: utf-8 -*-
# pylint: disable=C0103
# pylint: disable=C0111
# pylint: disable=W0235
import machine
import utime
import ustruct
from micropython import const, heap_lock, heap_unlock
from ubinascii import hexlify, unhexlify

from bluetooth_low_energy.modules.base_hci import (
    BaseHCI,
    HardwareException
)
from bluetooth_low_energy.protocols.hci import (
    HCI_COMMAND_PKT,
    HCI_EVENT_HDR_SIZE,
    HCI_EVENT_PKT,
    HCI_READ_PACKET_SIZE
)
from bluetooth_low_energy.protocols.hci.cmd import (
    HCI_COMMAND,
    HCI_COMMANDS,
    OGF_VENDOR_CMD
)
from bluetooth_low_energy.protocols.hci.event import (
    EVT_CMD_COMPLETE,
    EVT_CMD_STATUS,
    EVT_HARDWARE_ERROR,
    EVT_LE_META_EVENT,
    EVT_VENDOR,
    HCI_EVENT,
    HCI_EVENTS,
    HCI_VENDOR_EVENTS
)
from bluetooth_low_energy.protocols.hci.status import (
    BLE_STATUS_SUCCESS
)
from bluetooth_low_energy.protocols.hci.uart import (
    HCI_UART
)
from bluetooth_low_energy.protocols.hci.vendor_specifics.st_microelectronics.bluenrg_ms.cmd import (
    HCI_VENDOR_COMMANDS,
    OCF_ATT_EXECUTE_WRITE_REQ,
    OCF_ATT_FIND_BY_TYPE_VALUE_REQ,
    OCF_ATT_FIND_INFO_REQ,
    OCF_ATT_PREPARE_WRITE_REQ,
    OCF_ATT_READ_BY_GROUP_TYPE_REQ,
    OCF_ATT_READ_BY_TYPE_REQ,
    OCF_GAP_ALLOW_REBOND_DB,
    OCF_GAP_AUTHORIZATION_RESPONSE,
    OCF_GAP_CLEAR_SECURITY_DB,
    OCF_GAP_CONFIGURE_WHITELIST,
    OCF_GAP_CREATE_CONNECTION,
    OCF_GAP_DELETE_AD_TYPE,
    OCF_GAP_GET_BONDED_DEVICES,
    OCF_GAP_GET_SECURITY_LEVEL,
    OCF_GAP_INIT,
    OCF_GAP_IS_DEVICE_BONDED,
    OCF_GAP_PASSKEY_RESPONSE,
    OCF_GAP_RESOLVE_PRIVATE_ADDRESS,
    OCF_GAP_SEND_PAIRING_REQUEST,
    OCF_GAP_SET_AUTH_REQUIREMENT,
    OCF_GAP_SET_AUTHOR_REQUIREMENT,
    OCF_GAP_SET_BROADCAST_MODE,
    OCF_GAP_SET_DIRECT_CONNECTABLE,
    OCF_GAP_SET_DISCOVERABLE,
    OCF_GAP_SET_IO_CAPABILITY,
    OCF_GAP_SET_LIMITED_DISCOVERABLE,
    OCF_GAP_SET_NON_CONNECTABLE,
    OCF_GAP_SET_NON_DISCOVERABLE,
    OCF_GAP_SET_UNDIRECTED_CONNECTABLE,
    OCF_GAP_SLAVE_SECURITY_REQUEST,
    OCF_GAP_START_AUTO_CONN_ESTABLISH_PROC,
    OCF_GAP_START_CONNECTION_UPDATE,
    OCF_GAP_START_GENERAL_CONN_ESTABLISH_PROC,
    OCF_GAP_START_GENERAL_DISCOVERY_PROC,
    OCF_GAP_START_LIMITED_DISCOVERY_PROC,
    OCF_GAP_START_NAME_DISCOVERY_PROC,
    OCF_GAP_START_OBSERVATION_PROC,
    OCF_GAP_START_SELECTIVE_CONN_ESTABLISH_PROC,
    OCF_GAP_TERMINATE,
    OCF_GAP_TERMINATE_GAP_PROCEDURE,
    OCF_GAP_UPDATE_ADV_DATA,
    OCF_GATT_ADD_CHAR,
    OCF_GATT_ADD_CHAR_DESC,
    OCF_GATT_ADD_SERV,
    OCF_GATT_ALLOW_READ,
    OCF_GATT_CONFIRM_INDICATION,
    OCF_GATT_DEL_CHAR,
    OCF_GATT_DEL_INC_SERV,
    OCF_GATT_DEL_SERV,
    OCF_GATT_DISC_ALL_CHARAC_DESCRIPTORS,
    OCF_GATT_DISC_ALL_CHARAC_OF_SERV,
    OCF_GATT_DISC_ALL_PRIM_SERVICES,
    OCF_GATT_DISC_CHARAC_BY_UUID,
    OCF_GATT_DISC_PRIM_SERVICE_BY_UUID,
    OCF_GATT_EXCHANGE_CONFIG,
    OCF_GATT_FIND_INCLUDED_SERVICES,
    OCF_GATT_INCLUDE_SERV,
    OCF_GATT_INIT,
    OCF_GATT_READ_CHAR_DESC,
    OCF_GATT_READ_CHARAC_VAL,
    OCF_GATT_READ_HANDLE_VALUE,
    OCF_GATT_READ_HANDLE_VALUE_OFFSET,
    OCF_GATT_READ_LONG_CHARAC_DESC,
    OCF_GATT_READ_LONG_CHARAC_VAL,
    OCF_GATT_READ_MULTIPLE_CHARAC_VAL,
    OCF_GATT_READ_USING_CHARAC_UUID,
    OCF_GATT_SET_DESC_VAL,
    OCF_GATT_SET_EVT_MASK,
    OCF_GATT_SET_SECURITY_PERMISSION,
    OCF_GATT_SIGNED_WRITE_WITHOUT_RESPONSE,
    OCF_GATT_UPD_CHAR_VAL,
    OCF_GATT_UPD_CHAR_VAL_EXT,
    OCF_GATT_WRITE_CHAR_DESC,
    OCF_GATT_WRITE_CHAR_VALUE,
    OCF_GATT_WRITE_CHARAC_RELIABLE,
    OCF_GATT_WRITE_LONG_CHARAC_DESC,
    OCF_GATT_WRITE_LONG_CHARAC_VAL,
    OCF_GATT_WRITE_RESPONSE,
    OCF_GATT_WRITE_WITHOUT_RESPONSE,
    OCF_GET_UPDATER_BUFSIZE,
    OCF_GET_UPDATER_VERSION,
    OCF_HAL_DEVICE_STANDBY,
    OCF_HAL_GET_ANCHOR_PERIOD,
    OCF_HAL_GET_FW_BUILD_NUMBER,
    OCF_HAL_GET_LINK_STATUS,
    OCF_HAL_LE_TX_TEST_PACKET_NUMBER,
    OCF_HAL_READ_CONFIG_DATA,
    OCF_HAL_SET_TX_POWER_LEVEL,
    OCF_HAL_TONE_START,
    OCF_HAL_TONE_STOP,
    OCF_HAL_WRITE_CONFIG_DATA,
    OCF_L2CAP_CONN_PARAM_UPDATE_REQ,
    OCF_L2CAP_CONN_PARAM_UPDATE_RESP,
    OCF_UPDATER_CALC_CRC,
    OCF_UPDATER_ERASE_BLUE_FLAG,
    OCF_UPDATER_ERASE_SECTOR,
    OCF_UPDATER_HW_VERSION,
    OCF_UPDATER_PROG_DATA_BLOCK,
    OCF_UPDATER_READ_DATA_BLOCK,
    OCF_UPDATER_REBOOT,
    OCF_UPDATER_RESET_BLUE_FLAG,
    OCF_UPDATER_START
)
from bluetooth_low_energy.protocols.hci.vendor_specifics.st_microelectronics.bluenrg_ms.constant import (
    UUID_TYPE_16
)
from bluetooth_low_energy.protocols.hci.vendor_specifics.st_microelectronics.bluenrg_ms.event import (
    HCI_VENDOR_EVENTS as ST_HCI_VENDOR_EVENTS
)

# Add ST Microelectronics Vendor Specific HCI_COMMANDS
HCI_COMMANDS[OGF_VENDOR_CMD] = HCI_VENDOR_COMMANDS
# Add ST Microelectronics Vendor Specific HCI_EVENTS
HCI_VENDOR_EVENTS.update(ST_HCI_VENDOR_EVENTS)

HCI_PCK_TYPE_OFFSET = const(0)
EVENT_PARAMETER_TOT_LEN_OFFSET = const(2)

_READ_HEADER_MASTER = b'\x0B\x00\x00\x00\x00'
_WRITE_HEADER_MASTER = b'\x0A\x00\x00\x00\x00'


class CSContext(object):

    def __init__(self, pin):
        self._pin = pin

    def __enter__(self):
        # Assert CS line
        self._pin.off()

    def __exit__(self, exc_type, exc_value, traceback):
        # Release CS line
        self._pin.on()
        return all(map(lambda x: x is None, [exc_type, exc_value, traceback]))


class BlueNRG_MS(BaseHCI):
    """
    Bluetooth Low Energy Network Processor supporting
    Bluetooth 4.1 core specification
    """

    def __init__(
        self,
        spi_bus=machine.SPI(2, baudrate=8000000, polarity=0),
        irq_pin=machine.Pin('B8', machine.Pin.IN, machine.Pin.PULL_DOWN),
        rst_pin=machine.Pin('B9', machine.Pin.OUT_PP),
        nss_pin=machine.Pin('B12', machine.Pin.OUT_PP),
    ):
        """
        Defaults:
            - SPI(2) on the Y position:
                (NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)
              Params:
                phase: 0
                dir: SPI_DIRECTION_2LINES
                bits: 8
                nss: SPI_NSS_SOFT
                firstbit: SPI_FIRSTBIT_MSB
                ti: SPI_TIMODE_DISABLED
                crc:
                crc_calc: SPI_CRCCALCULATION_DISABLED

            PYBV1x:
            - IRQ  on Y3/B8 Pin
            - RST  on Y4/B9 Pin
            - NSS  on Y5/B12 Pin
            - SCK  on Y6/B13 Pin
            - MISO on Y7/B14 Pin
            - MOSI on Y8/B15 Pin

            ESPRUINO_PICO:
            - IRQ  on B8 Pin
            - RST  on B9 Pin
            - NSS  on A10 Pin
            - SCK  on A7 Pin
            - MISO on A6 Pin
            - MOSI on A5 Pin

        """

        if not isinstance(spi_bus, machine.SPI):
            raise TypeError("")

        m_pins = (irq_pin, rst_pin, nss_pin)
        if not all([isinstance(pin, machine.Pin) for pin in m_pins]):
            raise TypeError("")

        self._spi_bus = spi_bus

        self._irq_pin = irq_pin
        self._rst_pin = rst_pin
        self._nss_pin = nss_pin

        self._rw_header_slave = bytearray(5)

        # Release CS line
        self._nss_pin.on()

    def reset(self):
        """
        Reset BlueNRG-MS module
        """
        self._rst_pin.off()
        utime.sleep_us(5)
        self._rst_pin.on()
        utime.sleep_us(5)

    def any(self):
        """any"""
        return bool(self._irq_pin.value())

    def set_spi_irq_as_output(self):
        """Pull IRQ high"""
        self._irq_pin.init(mode=machine.Pin.OUT_PP,
                           pull=machine.Pin.PULL_NONE, value=1)

    def set_spi_irq_as_input(self):
        """IRQ input"""
        self._irq_pin.init(mode=machine.Pin.IN, pull=machine.Pin.PULL_DOWN)

    def hw_bootloader(self):
        """hw_bootloader"""
        self.set_spi_irq_as_output()
        self.reset()
        utime.sleep_ms(4)
        self.set_spi_irq_as_input()

    def run(self, callback=None, callback_time=1000):
        """
        BLE event loop

        Note: This function call __start__() when invoked and __stop__() when
              KeyboardInterrupt, StopIteration or an Exception
              is raised.

              __process__() called whenever there is an event to be processed
        """
        try:
            self.__start__()
            start = utime.ticks_ms()
            while True:
                event = self.read(retry=5)
                if self.hci_verify(event):
                    self.__process__(event)
                # user defined periodic callback
                if callable(callback) and utime.ticks_diff(
                        utime.ticks_ms(), start) >= callback_time:
                    callback()
                    start = utime.ticks_ms()

        except (KeyboardInterrupt, StopIteration) as ex:
            raise ex
        except Exception as ex:
            raise ex
        finally:
            self.__stop__()

    def __start__(self):
        raise NotImplementedError()

    def __stop__(self):
        raise NotImplementedError()

    def __process__(self, event):
        raise NotImplementedError()

    def read(self, size=HCI_READ_PACKET_SIZE, retry=5):
        """
        Read packet from BlueNRG-MS module
        """
        result = None
        while retry:
            with CSContext(self._nss_pin):
                # Exchange header
                self._spi_bus.write_readinto(
                    _READ_HEADER_MASTER,
                    self._rw_header_slave
                )
                rx_read_bytes = (
                    self._rw_header_slave[4] << 8
                ) | self._rw_header_slave[3]
                if self._rw_header_slave[0] == 0x02 and rx_read_bytes > 0:
                    # SPI is ready
                    # avoid to read more data that size of the buffer
                    if rx_read_bytes > size:
                        rx_read_bytes = size
                    data = b'\xFF' * rx_read_bytes
                    result = bytearray(rx_read_bytes)
                    self._spi_bus.write_readinto(data, result)
                    break
                else:
                    utime.sleep_us(50)
            retry -= 1

        # Add a small delay to give time to the BlueNRG to set the IRQ pin low
        # to avoid a useless SPI read at the end of the transaction
        utime.sleep_us(150)
        return result

    def write(self, header, param, retry=5):
        """
        Write packet to BlueNRG-MS module
        """
        result = None
        while retry:
            with CSContext(self._nss_pin):
                # Exchange header
                self._spi_bus.write_readinto(
                    _WRITE_HEADER_MASTER,
                    self._rw_header_slave
                )
                rx_write_bytes = self._rw_header_slave[1]
                rx_read_bytes = (
                    self._rw_header_slave[4] << 8
                ) | self._rw_header_slave[3]
                if self._rw_header_slave[0] == 0x02 and (
                        rx_write_bytes > 0 or rx_read_bytes > 0):
                    # SPI is ready
                    if header:
                        # avoid to write more data that size of the buffer
                        if rx_write_bytes >= len(header):
                            result = bytearray(len(header))
                            self._spi_bus.write_readinto(header, result)
                            if param:
                                rx_write_bytes -= len(header)
                                # avoid to read more data that size of the
                                # buffer
                                if len(param) > rx_write_bytes:
                                    tx_bytes = rx_write_bytes
                                else:
                                    tx_bytes = len(param)
                                result = bytearray(tx_bytes)
                                self._spi_bus.write_readinto(param, result)
                                break
                            else:
                                break
                        else:
                            break
                    else:
                        break
                else:
                    utime.sleep_us(50)
            retry -= 1

        return result

    def hci_verify(self, hci_pckt):
        """
        Verify HCI packet
        """
        if hci_pckt is None:
            return False

        if hci_pckt[HCI_PCK_TYPE_OFFSET] != HCI_EVENT_PKT:
            return False

        if hci_pckt[EVENT_PARAMETER_TOT_LEN_OFFSET] != \
                len(hci_pckt) - (1 + HCI_EVENT_HDR_SIZE):
            return False

        return True

    def hci_wait_event(self, evtcode=0, subevtcode=0, timeout=1000, retry=5):
        """
        Wait for event and filter it if needed
        """
        # Maximum timeout is 1 seconds
        start = utime.ticks_ms()
        while utime.ticks_diff(utime.ticks_ms(), start) <= min(timeout, 1000):
            event = self.read(retry=retry)
            if self.hci_verify(event) and isinstance(event, (bytearray, bytes)):
                hci_uart = HCI_UART.from_buffer(event)
                if hci_uart.pkt_type == HCI_EVENT_PKT:
                    hci_evt = HCI_EVENT.from_buffer(hci_uart.data)
                    if not evtcode and not subevtcode:
                        return hci_evt
                    if subevtcode:
                        if hci_evt.evtcode in (EVT_LE_META_EVENT, EVT_VENDOR):
                            if hci_evt.subevtcode == subevtcode:
                                return hci_evt
                            else:
                                raise ValueError("unexpected subevtcode")
                    if evtcode:
                        if hci_evt.evtcode == evtcode:
                            return hci_evt
                        else:
                            raise ValueError("unexpected evtcode")
                else:
                    raise TypeError("not HCI_EVENT_PKT")
            else:
                continue

    def hci_send_cmd(self, cmd, is_async=False, timeout=1000, retry=5):
        """hci_send_cmd"""
        if not isinstance(cmd, HCI_COMMAND):
            raise TypeError("HCI_COMMAND")

        header, param = cmd.to_buffer(split=True)
        if len(header) == cmd.struct_size:
            header = ustruct.pack("<B3s", HCI_COMMAND_PKT, header)
        self.hci_send(header, param)

        if is_async:
            return

        # Maximum timeout is 1 seconds
        start = utime.ticks_ms()
        while utime.ticks_diff(utime.ticks_ms(), start) <= min(timeout, 1000):
            event = self.read(retry=retry)
            if self.hci_verify(event) and isinstance(event, (bytearray, bytes)):
                hci_uart = HCI_UART.from_buffer(event)
                if hci_uart.pkt_type == HCI_EVENT_PKT:
                    hci_evt = HCI_EVENT.from_buffer(hci_uart.data)
                    if hci_evt.evtcode == EVT_CMD_STATUS:
                        if hci_evt.struct.opcode != cmd.opcode:
                            raise ValueError(hci_evt.struct.opcode)
                        if cmd.evtcode != hci_evt.evtcode:
                            if hci_evt.struct.status != BLE_STATUS_SUCCESS:
                                raise ValueError(hci_evt.struct.status)
                        cmd.response_data = hci_evt.data[hci_evt.struct_size:]
                        return event
                    elif hci_evt.evtcode == EVT_CMD_COMPLETE:
                        if hci_evt.struct.opcode != cmd.opcode:
                            raise ValueError(hci_evt.struct.opcode)
                        cmd.response_data = hci_evt.data[hci_evt.struct_size:]
                        return event
                    elif hci_evt.evtcode == EVT_LE_META_EVENT:
                        if hci_evt.subevtcode != cmd.evtcode:
                            raise ValueError(hci_evt.subevtcode)
                        cmd.response_data = hci_evt.data[hci_evt.struct_size:]
                        return event
                    elif hci_evt.evtcode == EVT_HARDWARE_ERROR:
                        cmd.response_data = hci_evt.data[hci_evt.struct_size:]
                        raise HardwareException(cmd.response_data)
            else:
                continue

    def hci_send(self, header, param=b'', retry=5):
        """
        Send HCI Header, if data available send it
        """
        return self.write(header, param, retry=retry)

    def get_version(self):
        """
        Get BlueNRG-MS firmware version
        """
        hci_cmd = self.hci_le_read_local_version()
        response = hci_cmd.response_struct
        if response.status != BLE_STATUS_SUCCESS:
            raise ValueError("status")
        fw_major = response.hci_revision & 0xFF
        fw_minor = (response.lmp_pal_subversion & 0xF0) >> 4
        fw_qualifier = (response.lmp_pal_subversion & 0xF)
        patch = ('' if fw_qualifier == 0 else chr(96 + fw_qualifier))
        dev = ('dev' if response.lmp_pal_subversion & 0x8000 else '')
        return ''.join(['.'.join(map(str, [fw_major, fw_minor])), patch, dev])

    ###########################################################################
    #                         HCI Library Functions                           #
    ###########################################################################

    ###########################################################################
    #                                GAP                                      #
    ###########################################################################

    def aci_gap_init_IDB04A1(self, role=0):
        """aci_gap_init_IDB04A1"""
        data = ustruct.pack(
            "<B",
            role)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_INIT,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_init_IDB05A1(
            self, role=0, privacy_enabled=False, device_name_char_len=0):
        """aci_gap_init_IDB05A1"""
        data = ustruct.pack(
            "<BBB",
            role, int(privacy_enabled), device_name_char_len)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_INIT,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_non_discoverable(self):
        """aci_gap_set_non_discoverable"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_NON_DISCOVERABLE)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_limited_discoverable(
            self, adv_type=0, adv_interv_min=0, adv_interv_max=0,
            own_addr_type=0, adv_filter_policy=0, local_name_len=0,
            local_name=b'', service_uuid_len=0, service_uuid_list=b'',
            slave_conn_interv_min=0, slave_conn_interv_max=0):
        """aci_gap_set_limited_discoverable"""
        data = ustruct.pack(
            "<BHHBBB{:d}sB{:d}sHH".format(local_name_len, service_uuid_len),
            adv_type, adv_interv_min, adv_interv_max,
            own_addr_type,
            adv_filter_policy,
            local_name_len,
            local_name,
            service_uuid_len,
            service_uuid_list,
            slave_conn_interv_min, slave_conn_interv_max)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_LIMITED_DISCOVERABLE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_discoverable(
            self, adv_type=0, adv_interv_min=0, adv_interv_max=0,
            own_addr_type=0, adv_filter_policy=0, local_name_len=0,
            local_name=b'', service_uuid_len=0, service_uuid_list=b'',
            slave_conn_interv_min=0, slave_conn_interv_max=0):
        """aci_gap_set_discoverable"""
        data = ustruct.pack(
            "<BHHBBB{:d}sB{:d}sHH".format(local_name_len, service_uuid_len),
            adv_type, adv_interv_min, adv_interv_max,
            own_addr_type, adv_filter_policy,
            local_name_len,
            local_name,
            service_uuid_len,
            service_uuid_list,
            slave_conn_interv_min, slave_conn_interv_max)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_DISCOVERABLE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_direct_connectable_IDB05A1(
            self, own_addr_type=0, directed_adv_type=0, initiator_addr_type=0,
            initiator_addr=b'', adv_interv_min=0, adv_interv_max=0):
        """aci_gap_set_direct_connectable_IDB05A1"""
        data = ustruct.pack(
            "<BBB6sHH",
            own_addr_type, directed_adv_type,
            initiator_addr_type, initiator_addr,
            adv_interv_min, adv_interv_max)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_DIRECT_CONNECTABLE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_direct_connectable_IDB04A1(
            self, own_addr_type=0, initiator_addr_type=0, initiator_addr=b''):
        """aci_gap_set_direct_connectable_IDB04A1"""
        data = ustruct.pack(
            "<BB6s",
            own_addr_type, initiator_addr_type,
            initiator_addr)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_DIRECT_CONNECTABLE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_io_capability(self, io_capability=0):
        """aci_gap_set_io_capability"""
        data = ustruct.pack(
            "<B",
            io_capability)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_IO_CAPABILITY,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_auth_requirement(
            self, mitm_mode=0, oob_enable=False, oob_data=b'',
            min_encryption_key_size=0, max_encryption_key_size=0,
            use_fixed_pin=False, fixed_pin=0, bonding_mode=0):
        """aci_gap_set_auth_requirement"""
        data = ustruct.pack(
            "<BB16sBBBIB",
            mitm_mode, int(oob_enable), oob_data,
            min_encryption_key_size, max_encryption_key_size,
            int(use_fixed_pin), fixed_pin, bonding_mode)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_AUTH_REQUIREMENT,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_author_requirement(
            self, conn_handle=0, authorization_enable=False):
        """aci_gap_set_author_requirement"""
        data = ustruct.pack(
            "<HB",
            conn_handle, int(authorization_enable))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_AUTHOR_REQUIREMENT,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_pass_key_response(self, conn_handle=0, passkey=0):
        """aci_gap_pass_key_response"""
        data = ustruct.pack(
            "<HI",
            conn_handle, passkey)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_PASSKEY_RESPONSE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_authorization_response(self, conn_handle=0, authorize=0):
        """aci_gap_authorization_response"""
        data = ustruct.pack(
            "<HB",
            conn_handle, authorize)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_AUTHORIZATION_RESPONSE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_non_connectable_IDB05A1(
            self, adv_type=0, own_address_type=0):
        """aci_gap_set_non_connectable_IDB05A1"""
        data = ustruct.pack(
            "<BB",
            adv_type, own_address_type)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_NON_CONNECTABLE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_non_connectable_IDB04A1(
            self, adv_type=0):
        """aci_gap_set_non_connectable_IDB04A1"""
        data = ustruct.pack(
            "<B",
            adv_type)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_NON_CONNECTABLE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_undirected_connectable(
            self, own_addr_type=0, adv_filter_policy=0):
        """aci_gap_set_undirected_connectable"""
        data = ustruct.pack(
            "<BB",
            own_addr_type, adv_filter_policy)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_UNDIRECTED_CONNECTABLE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_slave_security_request(
            self, conn_handle=0, bonding=0, mitm_protection=0):
        """aci_gap_slave_security_request"""
        data = ustruct.pack(
            "<HBB",
            conn_handle, bonding, mitm_protection)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SLAVE_SECURITY_REQUEST,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_update_adv_data(self, adv_len=0, adv_data=b''):
        """aci_gap_update_adv_data"""
        data = ustruct.pack(
            "<B{:d}s".format(adv_len),
            adv_len, adv_data)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_UPDATE_ADV_DATA,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_delete_ad_type(self, ad_type=0):
        """aci_gap_delete_ad_type"""
        data = ustruct.pack(
            "<B",
            ad_type)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_DELETE_AD_TYPE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_get_security_level(self):
        """aci_gap_get_security_level"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_GET_SECURITY_LEVEL)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_configure_whitelist(self):
        """aci_gap_configure_whitelist"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_CONFIGURE_WHITELIST)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_terminate(self, conn_handle=0, reason=0):
        """aci_gap_terminate"""
        data = ustruct.pack(
            "<HB",
            conn_handle, reason)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_TERMINATE,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_clear_security_database(self):
        """aci_gap_clear_security_database"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_CLEAR_SECURITY_DB)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_allow_rebond_IDB05A1(self, conn_handle=0):
        """aci_gap_allow_rebond_IDB05A1"""
        data = ustruct.pack(
            "<H",
            conn_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_ALLOW_REBOND_DB,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_allow_rebond_IDB04A1(self):
        """aci_gap_allow_rebond_IDB04A1"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_ALLOW_REBOND_DB)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_limited_discovery_proc(
            self, scan_interval=0, scan_window=0,
            own_address_type=0, filter_duplicates=0):
        """aci_gap_start_limited_discovery_proc"""
        data = ustruct.pack(
            "<HHBB",
            scan_interval, scan_window, own_address_type, filter_duplicates)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_LIMITED_DISCOVERY_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_general_discovery_proc(
            self, scan_interval=0, scan_window=0,
            own_address_type=0, filter_duplicates=0):
        """aci_gap_start_general_discovery_proc"""
        data = ustruct.pack(
            "<HHBB",
            scan_interval, scan_window, own_address_type, filter_duplicates)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_GENERAL_DISCOVERY_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_name_discovery_proc(
            self, scan_interval=0, scan_window=0, peer_bdaddr_type=0,
            peer_bdaddr=b'', own_bdaddr_type=0, conn_min_interval=0,
            conn_max_interval=0, conn_latency=0, supervision_timeout=0,
            min_conn_length=0, max_conn_length=0):
        """aci_gap_start_name_discovery_proc"""
        data = ustruct.pack(
            "<HHB6sBHHHHHH",
            scan_interval, scan_window,
            peer_bdaddr_type, peer_bdaddr, own_bdaddr_type,
            conn_min_interval, conn_max_interval, conn_latency,
            supervision_timeout, min_conn_length, max_conn_length)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_NAME_DISCOVERY_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_auto_conn_establish_proc_IDB05A1(
            self, scan_interval=0, scan_window=0, own_bdaddr_type=0,
            conn_min_interval=0, conn_max_interval=0, conn_latency=0,
            supervision_timeout=0, min_conn_length=0, max_conn_length=0,
            num_whitelist_entries=0, addr_array=b''):
        """aci_gap_start_auto_conn_establish_proc_IDB05A1"""
        data = ustruct.pack(
            "<HHBHHHHHHB{:d}s".format(num_whitelist_entries * 7),
            scan_interval, scan_window,
            own_bdaddr_type,
            conn_min_interval, conn_max_interval, conn_latency,
            supervision_timeout,
            min_conn_length, max_conn_length,
            num_whitelist_entries,
            addr_array)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_AUTO_CONN_ESTABLISH_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_auto_conn_establish_proc_IDB04A1(
            self, scan_interval=0, scan_window=0, own_bdaddr_type=0,
            conn_min_interval=0, conn_max_interval=0, conn_latency=0,
            supervision_timeout=0, min_conn_length=0, max_conn_length=0,
            use_reconn_addr=False, reconn_addr=b'', num_whitelist_entries=0,
            addr_array=b''):
        """aci_gap_start_auto_conn_establish_proc_IDB04A1"""
        data = ustruct.pack(
            "<HHBHHHHHHB6sB{:d}s".format(num_whitelist_entries * 7),
            scan_interval, scan_window,
            own_bdaddr_type,
            conn_min_interval, conn_max_interval, conn_latency,
            supervision_timeout,
            min_conn_length, max_conn_length,
            int(use_reconn_addr), reconn_addr,
            num_whitelist_entries,
            addr_array)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_AUTO_CONN_ESTABLISH_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_general_conn_establish_proc_IDB05A1(
            self, scan_type=0, scan_interval=0, scan_window=0,
            own_address_type=0, filter_duplicates=False):
        """aci_gap_start_general_conn_establish_proc_IDB05A1"""
        data = ustruct.pack(
            "<BHHBB",
            scan_type, scan_interval, scan_window,
            own_address_type, int(filter_duplicates))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_GENERAL_CONN_ESTABLISH_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_general_conn_establish_proc_IDB04A1(
            self, scan_type=0, scan_interval=0, scan_window=0,
            own_address_type=0, filter_duplicates=False, reconn_addr=b''):
        """aci_gap_start_general_conn_establish_proc_IDB04A1"""
        data = ustruct.pack(
            "<BHHBB6s",
            scan_type, scan_interval, scan_window,
            own_address_type, int(filter_duplicates),
            reconn_addr)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_GENERAL_CONN_ESTABLISH_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_selective_conn_establish_proc(
            self, scan_type=0, scan_interval=0, scan_window=0,
            own_address_type=0, filter_duplicates=False,
            num_whitelist_entries=0, addr_array=b''):
        """aci_gap_start_selective_conn_establish_proc"""
        data = ustruct.pack(
            "<BHHBBB{:d}s".format(num_whitelist_entries * 7),
            scan_type, scan_interval, scan_window, own_address_type,
            int(filter_duplicates), num_whitelist_entries, addr_array)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_SELECTIVE_CONN_ESTABLISH_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_create_connection(
            self, scan_interval=0, scan_window=0, peer_bdaddr_type=0,
            peer_bdaddr=b'', own_bdaddr_type=0, conn_min_interval=0,
            conn_max_interval=0, conn_latency=0, supervision_timeout=0,
            min_conn_length=0, max_conn_length=0):
        """aci_gap_create_connection"""
        data = ustruct.pack(
            "<HHB6sBHHHHHH",
            scan_interval, scan_window,
            peer_bdaddr_type, peer_bdaddr,
            own_bdaddr_type,
            conn_min_interval, conn_max_interval, conn_latency,
            supervision_timeout,
            min_conn_length, max_conn_length)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_CREATE_CONNECTION,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_terminate_gap_procedure(self, procedure_code=0):
        """aci_gap_terminate_gap_procedure"""
        data = ustruct.pack(
            "<B",
            procedure_code)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_TERMINATE_GAP_PROCEDURE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_connection_update(
            self, conn_handle=0, conn_min_interval=0, conn_max_interval=0,
            conn_latency=0, supervision_timeout=0, min_conn_length=0,
            max_conn_length=0):
        """aci_gap_start_connection_update"""
        data = ustruct.pack(
            "<HHHHHHH",
            conn_handle,
            conn_min_interval, conn_max_interval, conn_latency,
            supervision_timeout, min_conn_length, max_conn_length)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_CONNECTION_UPDATE,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_send_pairing_request(self, conn_handle=0, force_rebond=False):
        """aci_gap_send_pairing_request"""
        data = ustruct.pack(
            "<HB",
            conn_handle, int(force_rebond))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SEND_PAIRING_REQUEST,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_resolve_private_address_IDB05A1(self, private_address=b''):
        """aci_gap_resolve_private_address_IDB05A1"""
        data = ustruct.pack(
            "<6s",
            private_address)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_RESOLVE_PRIVATE_ADDRESS,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_resolve_private_address_IDB04A1(self):
        """aci_gap_resolve_private_address_IDB04A1"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_RESOLVE_PRIVATE_ADDRESS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_set_broadcast_mode(
            self, adv_interv_min=0, adv_interv_max=0, adv_type=0,
            own_addr_type=0, adv_data_length=0, adv_data=b'',
            num_whitelist_entries=0, addr_array=b''):
        """aci_gap_set_broadcast_mode"""
        data = ustruct.pack(
            "<HHBBB{:d}sB{:d}s".format(
                adv_data_length, num_whitelist_entries * 7),
            adv_interv_min, adv_interv_max,
            adv_type, own_addr_type,
            adv_data_length,
            adv_data,
            num_whitelist_entries,
            addr_array)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_SET_BROADCAST_MODE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_start_observation_procedure(
            self, scan_interval=0, scan_window=0, scan_type=0,
            own_address_type=0, filter_duplicates=False):
        """aci_gap_start_observation_procedure"""
        data = ustruct.pack(
            "<HHBBB",
            scan_interval, scan_window, scan_type,
            own_address_type, int(filter_duplicates))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_START_OBSERVATION_PROC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_is_device_bonded(self, peer_address_type=0, peer_address=b''):
        """aci_gap_is_device_bonded"""
        data = ustruct.pack(
            "<B6s",
            peer_address_type, peer_address)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_IS_DEVICE_BONDED,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gap_get_bonded_devices(self):
        """aci_gap_get_bonded_devices"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GAP_GET_BONDED_DEVICES)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    ###########################################################################
    #                               GATT                                      #
    ###########################################################################

    def aci_gatt_init(self):
        """aci_gatt_init"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_INIT)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_add_serv(
            self, service_uuid_type=0, service_uuid=b'', service_type=0,
            max_attr_records=0):
        """aci_gatt_add_serv"""
        uuid_len = 2 if service_uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<B{:d}sBB".format(uuid_len),
            service_uuid_type, service_uuid,
            service_type, max_attr_records)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_ADD_SERV,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_include_service(
            self, service_handle=0, included_start_handle=0,
            included_end_handle=0, included_uuid_type=0, included_uuid=b''):
        """aci_gatt_include_service"""
        uuid_len = 2 if included_uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HHHB{:d}s".format(uuid_len),
            service_handle, included_start_handle,
            included_end_handle, included_uuid_type,
            included_uuid)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_INCLUDE_SERV,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_add_char(
            self, service_handle=0, char_uuid_type=0, char_uuid=b'',
            char_value_len=0, char_properties=0, sec_permissions=0,
            gatt_evt_mask=0, encry_key_size=0, is_variable=False):
        """aci_gatt_add_char"""
        uuid_len = 2 if char_uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HB{:d}sBBBBBB".format(uuid_len),
            service_handle, char_uuid_type, char_uuid,
            char_value_len, char_properties, sec_permissions,
            gatt_evt_mask, encry_key_size, int(is_variable))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_ADD_CHAR,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_add_char_desc(
            self, service_handle=0, char_handle=0, desc_uuid_type=0,
            uuid=b'', desc_value_max_len=0, desc_value_len=0, desc_value=b'',
            sec_permissions=0, acc_permissions=0, gatt_evt_mask=0,
            encry_key_size=0, is_variable=False):
        """aci_gatt_add_char_desc"""
        uuid_len = 2 if desc_uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HHB{:d}sBB{:d}sBBBBB".format(uuid_len, desc_value_len),
            service_handle, char_handle, desc_uuid_type,
            uuid, desc_value_max_len, desc_value_len,
            desc_value, sec_permissions,
            acc_permissions, gatt_evt_mask, encry_key_size,
            int(is_variable))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_ADD_CHAR_DESC,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_update_char_value(
            self, serv_handle=0, char_handle=0, char_val_offset=0,
            char_value_len=0, char_value=b''):
        """aci_gatt_update_char_value"""
        data = ustruct.pack(
            "<HHBB{:d}s".format(char_value_len),
            serv_handle, char_handle, char_val_offset,
            char_value_len, char_value)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_UPD_CHAR_VAL,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_del_char(self, serv_handle=0, char_handle=0):
        """aci_gatt_del_char"""
        data = ustruct.pack(
            "<HH",
            serv_handle, char_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DEL_CHAR,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_del_service(self, serv_handle=0):
        """aci_gatt_del_service"""
        data = ustruct.pack(
            "<H",
            serv_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DEL_SERV,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_del_include_service(
            self, serv_handle=0, include_serv_handle=0):
        """aci_gatt_del_include_service"""
        data = ustruct.pack(
            "<HH",
            serv_handle, include_serv_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DEL_INC_SERV,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_set_event_mask(self, event_mask=0):
        """aci_gatt_set_event_mask"""
        data = ustruct.pack(
            "<I",
            event_mask)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_SET_EVT_MASK,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_exchange_configuration(self, conn_handle=0):
        """aci_gatt_exchange_configuration"""
        data = ustruct.pack(
            "<H",
            conn_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_EXCHANGE_CONFIG,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_att_find_information_req(
            self, conn_handle=0, start_handle=0, end_handle=0):
        """aci_att_find_information_req"""
        data = ustruct.pack(
            "<HHH",
            conn_handle, start_handle, end_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_ATT_FIND_INFO_REQ,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_att_find_by_type_value_req(
            self, conn_handle=0, start_handle=0, end_handle=0,
            uuid=b'', attr_val_len=0, attr_val=b''):
        """aci_att_find_by_type_value_req"""
        data = ustruct.pack(
            "<HHH2sB{:d}s".format(attr_val_len),
            conn_handle, start_handle, end_handle, uuid,
            attr_val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_ATT_FIND_BY_TYPE_VALUE_REQ,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_att_read_by_type_req(
            self, conn_handle=0, start_handle=0, end_handle=0,
            uuid_type=0, uuid=b''):
        """aci_att_read_by_type_req"""
        uuid_len = 2 if uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HHHB{:d}s".format(uuid_len),
            conn_handle, start_handle, end_handle,
            uuid_type, uuid)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_ATT_READ_BY_TYPE_REQ,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_att_read_by_group_type_req(
            self, conn_handle=0, start_handle=0, end_handle=0,
            uuid_type=0, uuid=b''):
        """aci_att_read_by_group_type_req"""
        uuid_len = 2 if uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HHHB{:d}s".format(uuid_len),
            conn_handle, start_handle, end_handle,
            uuid_type, uuid)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_ATT_READ_BY_GROUP_TYPE_REQ,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_att_prepare_write_req(
            self, conn_handle=0, attr_handle=0, value_offset=0,
            attr_val_len=0, attr_val=b''):
        """aci_att_prepare_write_req"""
        data = ustruct.pack(
            "<HHHB{:d}s".format(attr_val_len),
            conn_handle, attr_handle, value_offset,
            attr_val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_ATT_PREPARE_WRITE_REQ,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_att_execute_write_req(self, conn_handle=0, execute=0):
        """aci_att_execute_write_req"""
        data = ustruct.pack(
            "<HB",
            conn_handle, execute)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_ATT_EXECUTE_WRITE_REQ,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_disc_all_prim_services(self, conn_handle=0):
        """aci_gatt_disc_all_prim_services"""
        data = ustruct.pack(
            "<H",
            conn_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DISC_ALL_PRIM_SERVICES,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_disc_prim_service_by_uuid(
            self, conn_handle=0, uuid_type=0, uuid=b''):
        """aci_gatt_disc_prim_service_by_uuid"""
        uuid_len = 2 if uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HB{:d}s".format(uuid_len),
            conn_handle, uuid_type, uuid)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DISC_PRIM_SERVICE_BY_UUID,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_find_included_services(
            self, conn_handle=0, start_handle=0, end_handle=0):
        """aci_gatt_find_included_services"""
        data = ustruct.pack(
            "<HHH",
            conn_handle, start_handle, end_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_FIND_INCLUDED_SERVICES,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_disc_all_charac_of_serv(
            self, conn_handle=0, start_attr_handle=0, end_attr_handle=0):
        """aci_gatt_disc_all_charac_of_serv"""
        data = ustruct.pack(
            "<HHH",
            conn_handle, start_attr_handle, end_attr_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DISC_ALL_CHARAC_OF_SERV,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_disc_charac_by_uuid(
            self, conn_handle=0, start_handle=0, end_handle=0,
            uuid_type=0, uuid=b''):
        """aci_gatt_disc_charac_by_uuid"""
        uuid_len = 2 if uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HHHB{:d}s".format(uuid_len),
            conn_handle, start_handle, end_handle, uuid_type, uuid)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DISC_CHARAC_BY_UUID,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_disc_all_charac_descriptors(
            self, conn_handle=0, char_val_handle=0, char_end_handle=0):
        """aci_gatt_disc_all_charac_descriptors"""
        data = ustruct.pack(
            "<HHH",
            conn_handle, char_val_handle, char_end_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_DISC_ALL_CHARAC_DESCRIPTORS,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_charac_val(self, conn_handle=0, attr_handle=0):
        """aci_gatt_read_charac_val"""
        data = ustruct.pack(
            "<HH",
            conn_handle, attr_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_CHARAC_VAL,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_using_charac_uuid(
            self, conn_handle=0, start_handle=0, end_handle=0,
            uuid_type=0, uuid=b''):
        """aci_gatt_read_using_charac_uuid"""
        uuid_len = 2 if uuid_type == UUID_TYPE_16 else 16
        data = ustruct.pack(
            "<HHHB{:d}s".format(uuid_len),
            conn_handle, start_handle, end_handle, uuid_type, uuid)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_USING_CHARAC_UUID,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_long_charac_val(
            self, conn_handle=0, attr_handle=0, val_offset=0):
        """aci_gatt_read_long_charac_val"""
        data = ustruct.pack(
            "<HHH",
            conn_handle, attr_handle, val_offset)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_LONG_CHARAC_VAL,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_multiple_charac_val(
            self, conn_handle=0, num_handles=0, set_of_handles=b''):
        """aci_gatt_read_multiple_charac_val"""
        data = ustruct.pack(
            "<HB{:d}s".format(num_handles * 2),
            conn_handle, num_handles, set_of_handles)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_MULTIPLE_CHARAC_VAL,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_write_charac_value(
            self, conn_handle=0, attr_handle=0, val_len=0, attr_value=b''):
        """aci_gatt_write_charac_value"""
        data = ustruct.pack(
            "<HHB{:d}s".format(val_len),
            conn_handle, attr_handle, val_len, attr_value)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_WRITE_CHAR_VALUE,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_write_long_charac_val(
            self, conn_handle=0, attr_handle=0, val_offset=0,
            val_len=0, attr_val=b''):
        """aci_gatt_write_long_charac_val"""
        data = ustruct.pack(
            "<HHHB{:d}s".format(val_len),
            conn_handle, attr_handle, val_offset, val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_WRITE_LONG_CHARAC_VAL,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_write_charac_reliable(
            self, conn_handle=0, attr_handle=0, val_offset=0,
            val_len=0, attr_val=b''):
        """aci_gatt_write_charac_reliable"""
        data = ustruct.pack(
            "<HHHB{:d}s".format(val_len),
            conn_handle, attr_handle, val_offset, val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_WRITE_CHARAC_RELIABLE,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_write_long_charac_desc(
            self, conn_handle=0, attr_handle=0,
            val_offset=0, val_len=0, attr_val=b''):
        """aci_gatt_write_long_charac_desc"""
        data = ustruct.pack(
            "<HHHB{:d}s".format(val_len),
            conn_handle, attr_handle, val_offset, val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_WRITE_LONG_CHARAC_DESC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_long_charac_desc(
            self, conn_handle=0, attr_handle=0, val_offset=0):
        """aci_gatt_read_long_charac_desc"""
        data = ustruct.pack(
            "<HHH",
            conn_handle, attr_handle, val_offset)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_LONG_CHARAC_DESC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_write_charac_descriptor(
            self, conn_handle=0, attr_handle=0, val_len=0, attr_val=b''):
        """aci_gatt_write_charac_descriptor"""
        data = ustruct.pack(
            "<HHB{:d}s".format(val_len),
            conn_handle, attr_handle, val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_WRITE_CHAR_DESC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_charac_desc(self, conn_handle=0, attr_handle=0):
        """aci_gatt_read_charac_desc"""
        data = ustruct.pack(
            "<HH",
            conn_handle, attr_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_CHAR_DESC,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_write_without_response(
            self, conn_handle=0, attr_handle=0, val_len=0, attr_val=b''):
        """aci_gatt_write_without_response"""
        data = ustruct.pack(
            "<HHB{:d}s".format(val_len),
            conn_handle, attr_handle, val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_WRITE_WITHOUT_RESPONSE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_signed_write_without_resp(
            self, conn_handle=0, attr_handle=0, val_len=0, attr_val=b''):
        """aci_gatt_signed_write_without_resp"""
        data = ustruct.pack(
            "<HHB{:d}s".format(val_len),
            conn_handle, attr_handle, val_len, attr_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_SIGNED_WRITE_WITHOUT_RESPONSE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_confirm_indication(self, conn_handle=0):
        """aci_gatt_confirm_indication"""
        data = ustruct.pack(
            "<H",
            conn_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_CONFIRM_INDICATION,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_write_response(
            self, conn_handle=0, attr_handle=0, write_status=False, err_code=0,
            att_val_len=0, att_val=b''):
        """aci_gatt_write_response"""
        data = ustruct.pack(
            "<HHBBB{:d}s".format(att_val_len),
            conn_handle, attr_handle, int(write_status), err_code, att_val_len,
            att_val)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_WRITE_RESPONSE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_allow_read(self, conn_handle=0):
        """aci_gatt_allow_read"""
        data = ustruct.pack(
            "<H",
            conn_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_ALLOW_READ,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_set_security_permission(
            self, service_handle=0, attr_handle=0, security_permission=0):
        """aci_gatt_set_security_permission"""
        data = ustruct.pack(
            "<HHB",
            service_handle, attr_handle, security_permission)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_SET_SECURITY_PERMISSION,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_set_desc_value(
            self, serv_handle=0, char_handle=0, char_desc_handle=0,
            char_desc_val_offset=0, char_desc_value_len=0, char_desc_value=b''):
        """aci_gatt_set_desc_value"""
        data = ustruct.pack(
            "<HHHHB{:d}s".format(char_desc_value_len),
            serv_handle, char_handle, char_desc_handle, char_desc_val_offset,
            char_desc_value_len, char_desc_value)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_SET_DESC_VAL,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_handle_value(self, attr_handle=0):
        """aci_gatt_read_handle_value"""
        data = ustruct.pack(
            "<H",
            attr_handle)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_HANDLE_VALUE,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_read_handle_value_offset_IDB05A1(
            self, attr_handle=0, offset=0):
        """aci_gatt_read_handle_value_offset_IDB05A1"""
        data = ustruct.pack(
            "<HH",
            attr_handle, offset)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_READ_HANDLE_VALUE_OFFSET,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_gatt_update_char_value_ext_IDB05A1(
            self, service_handle=0, char_handle=0, update_type=0, char_length=0,
            value_offset=0, value_length=0, value=b''):
        """aci_gatt_update_char_value_ext_IDB05A1"""
        data = ustruct.pack(
            "<HHBHHB{:d}s".format(value_length),
            service_handle, char_handle, update_type, char_length,
            value_offset, value_length, value)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GATT_UPD_CHAR_VAL_EXT,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    ###########################################################################
    #                                HAL                                      #
    ###########################################################################

    def aci_hal_get_fw_build_number(self):
        """aci_hal_get_fw_build_number"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_GET_FW_BUILD_NUMBER)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_write_config_data(self, offset=0, length=0, data=b''):
        """aci_hal_write_config_data"""
        data = ustruct.pack(
            "<BB{:d}s".format(length),
            offset, length, data)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_WRITE_CONFIG_DATA,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_read_config_data(self, offset=0):
        """aci_hal_read_config_data"""
        data = ustruct.pack(
            "<B",
            offset)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_READ_CONFIG_DATA,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_set_tx_power_level(self, en_high_power=0, pa_level=0):
        """aci_hal_set_tx_power_level"""
        data = ustruct.pack(
            "<BB",
            en_high_power, pa_level)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_SET_TX_POWER_LEVEL,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_le_tx_test_packet_number(self):
        """aci_hal_le_tx_test_packet_number"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_LE_TX_TEST_PACKET_NUMBER)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_device_standby(self):
        """aci_hal_device_standby"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_DEVICE_STANDBY)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_tone_start(self, rf_channel=0):
        """aci_hal_tone_start"""
        data = ustruct.pack(
            "<B",
            rf_channel)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_TONE_START,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_tone_stop(self):
        """aci_hal_tone_stop"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_TONE_STOP)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_get_link_status(self):
        """aci_hal_get_link_status"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_GET_LINK_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_hal_get_anchor_period(self):
        """aci_hal_get_anchor_period"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_HAL_GET_ANCHOR_PERIOD)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    ###########################################################################
    #                                L2CAP                                    #
    ###########################################################################

    def aci_l2cap_connection_parameter_update_request(
            self, conn_handle=0, interval_min=0, interval_max=0,
            slave_latency=0, timeout_multiplier=0):
        """aci_l2cap_connection_parameter_update_request"""
        data = ustruct.pack(
            "<HHHHH",
            conn_handle, interval_min, interval_max, slave_latency,
            timeout_multiplier)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_L2CAP_CONN_PARAM_UPDATE_REQ,
            data=data,
            evtcode=EVT_CMD_STATUS)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_l2cap_connection_parameter_update_response_IDB05A1(
            self, conn_handle=0, interval_min=0, interval_max=0,
            slave_latency=0, timeout_multiplier=0,
            min_ce_length=0, max_ce_length=0, id_=0, accept=False):
        """aci_l2cap_connection_parameter_update_response_IDB05A1"""
        data = ustruct.pack(
            "<HHHHHHHBB",
            conn_handle, interval_min, interval_max, slave_latency,
            timeout_multiplier, min_ce_length, max_ce_length, id_, int(accept))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_L2CAP_CONN_PARAM_UPDATE_RESP,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_l2cap_connection_parameter_update_response_IDB04A1(
            self, conn_handle=0, interval_min=0, interval_max=0,
            slave_latency=0, timeout_multiplier=0, id_=0, accept=False):
        """aci_l2cap_connection_parameter_update_response_IDB04A1"""
        data = ustruct.pack(
            "<HHHHHBB",
            conn_handle, interval_min, interval_max, slave_latency,
            timeout_multiplier, id_, int(accept))
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_L2CAP_CONN_PARAM_UPDATE_RESP,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    ###########################################################################
    #                                UPDATER                                  #
    ###########################################################################

    def aci_updater_start(self):
        """aci_updater_start"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_START)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_updater_reboot(self):
        """aci_updater_reboot"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_REBOOT)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_get_updater_version(self):
        """aci_get_updater_version"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GET_UPDATER_VERSION)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_get_updater_buffer_size(self):
        """aci_get_updater_buffer_size"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_GET_UPDATER_BUFSIZE)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_erase_blue_flag(self):
        """aci_erase_blue_flag"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_ERASE_BLUE_FLAG)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_reset_blue_flag(self):
        """aci_reset_blue_flag"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_RESET_BLUE_FLAG)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_updater_erase_sector(self, address=0):
        """aci_updater_erase_sector"""
        data = ustruct.pack(
            "<I",
            address)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_ERASE_SECTOR,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_updater_program_data_block(self, address=0, data_len=0, data=b''):
        """aci_updater_program_data_block"""
        data = ustruct.pack(
            "<IH{:d}s".format(data_len),
            address, data_len, data)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_PROG_DATA_BLOCK,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_updater_read_data_block(self, address=0, data_len=0):
        """aci_updater_read_data_block"""
        data = ustruct.pack(
            "<IH",
            address, data_len)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_READ_DATA_BLOCK,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_updater_calc_crc(self, address=0, num_sectors=0):
        """aci_updater_calc_crc"""
        data = ustruct.pack(
            "<IH",
            address, num_sectors)
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_CALC_CRC,
            data=data)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd

    def aci_updater_hw_version(self):
        """aci_updater_hw_version"""
        hci_cmd = HCI_COMMAND(
            ogf=OGF_VENDOR_CMD,
            ocf=OCF_UPDATER_HW_VERSION)
        self.hci_send_cmd(hci_cmd)
        return hci_cmd
