initial commit
This commit is contained in:
+1354
File diff suppressed because it is too large
Load Diff
+88
@@ -0,0 +1,88 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv_apollo3.h
|
||||
//!
|
||||
//! @brief Support functions for the Nationz BTLE radio in Apollo3.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_DRV_APOLLO3_H
|
||||
#define HCI_DRV_APOLLO3_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// NATIONZ vendor specific events
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
|
||||
// Tx power level in dBm.
|
||||
typedef enum
|
||||
{
|
||||
TX_POWER_LEVEL_MINUS_10P0_dBm = 0x3,
|
||||
TX_POWER_LEVEL_0P0_dBm = 0x8,
|
||||
TX_POWER_LEVEL_PLUS_3P0_dBm = 0xF,
|
||||
TX_POWER_LEVEL_INVALID = 0x10,
|
||||
}txPowerLevel_t;
|
||||
|
||||
|
||||
bool_t HciVsA3_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel);
|
||||
void HciVsA3_ConstantTransmission(uint8_t txchannel);
|
||||
void HciVsA3_CarrierWaveMode(uint8_t txchannel);
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Hci driver functions unique to Apollo3
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern void HciDrvHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
extern void HciDrvHandlerInit(wsfHandlerId_t handlerId);
|
||||
extern void HciDrvIntService(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // HCI_DRV_APOLLO3_H
|
||||
+565
@@ -0,0 +1,565 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv.c
|
||||
//!
|
||||
//! @brief HCI driver interface.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_cs.h"
|
||||
#include "hci_defs.h"
|
||||
#include "hci_drv.h"
|
||||
#include "hci_drv_apollo.h"
|
||||
#include "hci_tr_apollo.h"
|
||||
#include "hci_core.h"
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_util.h"
|
||||
#include "am_devices_em9304.h"
|
||||
#include "hci_drv_em9304.h"
|
||||
#include "em9304_patches.h"
|
||||
#include "em9304_init.h"
|
||||
#include "hci_apollo_config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Unless the config file overwrites this option, the HCI driver will use a
|
||||
// direct call to the HAL when it needs to sleep.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_DRV_SLEEP
|
||||
#define HCI_DRV_SLEEP am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP)
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// If the config file doesn't say anything about MAC addresses, use a EM Microelectronic
|
||||
// assigned BD address by default .
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_APOLLO_MAC
|
||||
#define HCI_APOLLO_MAC {0x01, 0x00, 0x00, 0xEE, 0xF3, 0x0C}
|
||||
#endif
|
||||
|
||||
// HCI_APOLLO_USE_CUSTOMER_OWN_MAC should be defined to true if customer
|
||||
// supply their own BD address.
|
||||
|
||||
#ifndef HCI_APOLLO_USE_CUSTOMER_OWN_MAC
|
||||
#define HCI_APOLLO_USE_CUSTOMER_OWN_MAC false
|
||||
#endif
|
||||
|
||||
uint8_t radio_boot_complete = 0;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Mac address for the EM.
|
||||
//
|
||||
//*****************************************************************************
|
||||
static uint8_t g_pui8BLEMacAddress[6] = HCI_APOLLO_MAC;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// HCI RX packet buffer for EM9304 Driver.
|
||||
//
|
||||
//*****************************************************************************
|
||||
static uint32_t g_pui32HCIRXBuffer[64];
|
||||
static uint32_t g_ui32HCIPacketSize;
|
||||
static uint8_t g_consumed_bytes;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Static record of the EM9304 vendor specific events
|
||||
//
|
||||
//*****************************************************************************
|
||||
g_EMVSEvent_t g_EMVendorSpecificEvents = {0,0,0,0,0,0,0};
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Workaround for Keil memcpy()
|
||||
//
|
||||
// Keil's version of memcpy() contains an optimization that allows it to copy
|
||||
// data more efficiently when both the source and destination pointers are well
|
||||
// aligned. Unforunately, some of exactLE's complex callback structures confuse
|
||||
// Keil's memcpy implementation. Left unchecked, this can lead to intermittent
|
||||
// hard-faults.
|
||||
//
|
||||
// This function definition will intercept calls to this optimized version of
|
||||
// memcpy and avoid the problem when the pointers are unexpectedly unaligned.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#if defined(__ARMCC_VERSION)
|
||||
|
||||
void $Super$$__aeabi_memcpy4(void *dest, const void *src, size_t n);
|
||||
|
||||
void
|
||||
$Sub$$__aeabi_memcpy4(void *dest, const void *src, size_t n)
|
||||
{
|
||||
//
|
||||
// If the pointers are aligned, we can use Keil's normal memcpy.
|
||||
//
|
||||
if ((((uint32_t)dest % 4) == 0) && (((uint32_t)src % 4) == 0))
|
||||
{
|
||||
$Super$$__aeabi_memcpy4(dest, src, n);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise, make sure we use 8-bit pointers.
|
||||
//
|
||||
uint8_t *tempSrc = (uint8_t *)(src);
|
||||
uint8_t *tempDest = (uint8_t *)(dest);
|
||||
|
||||
//
|
||||
// Copy from src to dest, one byte at a time.
|
||||
//
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
*tempDest++ = *tempSrc++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Get the EM9304 vendor specific event counters.
|
||||
//!
|
||||
//! @return Returns a pointer to the EM9304 vendor specific event counters.
|
||||
//
|
||||
//*****************************************************************************
|
||||
g_EMVSEvent_t *getEM9304VSEventCounters(void)
|
||||
{
|
||||
return &g_EMVendorSpecificEvents;
|
||||
}
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Write data the driver.
|
||||
//!
|
||||
//! @param type HCI packet type
|
||||
//! @param len Number of bytes to write
|
||||
//! @param pData Byte array to write
|
||||
//!
|
||||
//! @return Returns the number of bytes written.
|
||||
//
|
||||
//*****************************************************************************
|
||||
uint16_t
|
||||
hciDrvWrite(uint8_t type, uint16_t len, uint8_t *pData)
|
||||
{
|
||||
//
|
||||
// Turn on the IOM for this operation.
|
||||
//
|
||||
am_devices_em9304_spi_awake(g_sEm9304.ui32IOMModule);
|
||||
|
||||
//
|
||||
// Write the HCI packet.
|
||||
//
|
||||
am_devices_em9304_block_write(&g_sEm9304, type, pData, len );
|
||||
|
||||
//
|
||||
// Disable IOM SPI pins and turn off the IOM after operation
|
||||
//
|
||||
am_devices_em9304_spi_sleep(g_sEm9304.ui32IOMModule);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// hciDrvReadyToSleep - Stub provided to allow other layers to run correctly.
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool_t
|
||||
hciDrvReadyToSleep(void)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool_t
|
||||
HciDataReadyISR(void)
|
||||
{
|
||||
//
|
||||
// If the radio boot has not yet completed, then do not process HCI packets
|
||||
if (!radio_boot_complete)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// check if there's pending HCI data from last time
|
||||
if (g_ui32HCIPacketSize > g_consumed_bytes)
|
||||
{
|
||||
g_consumed_bytes += hciTrSerialRxIncoming(
|
||||
((uint8_t *)g_pui32HCIRXBuffer) + g_consumed_bytes,
|
||||
g_ui32HCIPacketSize - g_consumed_bytes);
|
||||
|
||||
if (g_consumed_bytes == g_ui32HCIPacketSize) {
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Turn on the IOM for this operation.
|
||||
//
|
||||
am_devices_em9304_spi_awake(g_sEm9304.ui32IOMModule);
|
||||
|
||||
g_ui32HCIPacketSize = am_devices_em9304_block_read(&g_sEm9304, g_pui32HCIRXBuffer, 0);
|
||||
|
||||
// Check for EM9304 Vendor Specific events and record them.
|
||||
if ( (g_ui32HCIPacketSize > 3) && (0x0001FF04 == (g_pui32HCIRXBuffer[0] & 0x00FFFFFF)) )
|
||||
{
|
||||
switch((g_pui32HCIRXBuffer[0] & 0xFF000000) >> 24)
|
||||
{
|
||||
case 0x01:
|
||||
g_EMVendorSpecificEvents.EM_ActiveStateEntered++;
|
||||
am_util_debug_printf("Received EM_ActiveStateEntered Event\n");
|
||||
break;
|
||||
case 0x03:
|
||||
g_EMVendorSpecificEvents.EM_TestModeEntered++;
|
||||
am_util_debug_printf("Received EM_TestModeEntered Event\n");
|
||||
break;
|
||||
case 0x04:
|
||||
g_EMVendorSpecificEvents.EM_HalNotification++;
|
||||
am_util_debug_printf("Received EM_HalNotification Event\n");
|
||||
break;
|
||||
default:
|
||||
am_util_debug_printf("Received Unknown Vendor Specific Event from EM9304\n");
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the packet size to 0 so that this packet will not be processed by the host stack.
|
||||
//
|
||||
g_ui32HCIPacketSize = 0;
|
||||
}
|
||||
|
||||
if (g_ui32HCIPacketSize > 0)
|
||||
{
|
||||
g_consumed_bytes += hciTrSerialRxIncoming((uint8_t *)g_pui32HCIRXBuffer, g_ui32HCIPacketSize);
|
||||
if (g_consumed_bytes == g_ui32HCIPacketSize) {
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Disable IOM SPI pins and turn off the IOM after operation
|
||||
//
|
||||
am_devices_em9304_spi_sleep(g_sEm9304.ui32IOMModule);
|
||||
|
||||
return (g_ui32HCIPacketSize == 0);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Configure the necessary pins and start the EM9304 radio.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
HciDrvRadioBoot(uint32_t ui32UartModule)
|
||||
{
|
||||
uint32_t patch_dest_memory = DEST_MEMORY_IRAM;
|
||||
|
||||
uint32_t ui32PN;
|
||||
|
||||
// disable interrupt during EM9304 initialization.
|
||||
am_devices_em9304_disable_interrupt();
|
||||
|
||||
radio_boot_complete = 0;
|
||||
|
||||
//
|
||||
// Enable the radio pins.
|
||||
//
|
||||
#ifdef HCI_APOLLO_POWER_PIN
|
||||
|
||||
//
|
||||
// Insert a power on reset to TLSR8269
|
||||
// (with TLSR8269 EVK, this is only done via power pin)
|
||||
//
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_POWER_PIN, HCI_APOLLO_POWER_CFG);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_POWER_PIN);
|
||||
am_util_delay_ms(100);
|
||||
am_hal_gpio_out_bit_set(HCI_APOLLO_POWER_PIN);
|
||||
am_util_delay_ms(100);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Device identification
|
||||
//
|
||||
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
|
||||
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
|
||||
|
||||
// Currently only enable this for Apollo2-Blue
|
||||
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
|
||||
{
|
||||
am_hal_gpio_pin_config(30, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(30);
|
||||
am_hal_gpio_pin_config(35, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(35);
|
||||
am_hal_gpio_pin_config(36, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(36);
|
||||
|
||||
}
|
||||
//
|
||||
// Assert RESET to the EM9304 device.
|
||||
//
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
//
|
||||
// Setup SPI interface for EM9304
|
||||
//
|
||||
am_devices_em9304_config_pins();
|
||||
am_devices_em9304_spi_init(g_sEm9304.ui32IOMModule, &g_sEm9304IOMConfigSPI);
|
||||
|
||||
//
|
||||
// Enable the IOM and GPIO interrupt handlers.
|
||||
//
|
||||
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
//
|
||||
// Delay for 20ms to make sure the em device gets ready for commands.
|
||||
//
|
||||
am_util_delay_ms(20);
|
||||
|
||||
//
|
||||
// Initialize the EM9304.
|
||||
//
|
||||
patch_dest_memory = initEM9304();
|
||||
|
||||
//
|
||||
// Delay for 20ms to make sure the em device completes initialization.
|
||||
//
|
||||
am_util_delay_ms(20);
|
||||
|
||||
if (patch_dest_memory == DEST_MEMORY_OTP)
|
||||
{
|
||||
|
||||
//
|
||||
// Completed the patching process by cycling RESET to the EM9304 device.
|
||||
//
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
|
||||
am_util_delay_ms(20);
|
||||
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
// delay here to make sure EM9304 is ready for operation after
|
||||
// patch is loaded.
|
||||
am_util_delay_ms(20);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Set the MAC address if customer provides their own BD address
|
||||
//
|
||||
if (HCI_APOLLO_USE_CUSTOMER_OWN_MAC)
|
||||
{
|
||||
//
|
||||
// currently just use the default one, customer either update g_pui8BLEMacAddress
|
||||
// directly or call HciDrvAssignBDAddress() with a pointer of assigned BD address.
|
||||
HciDrvAssignBDAddress(g_pui8BLEMacAddress);
|
||||
}
|
||||
|
||||
// Initialization of the EM9304 is complete.
|
||||
radio_boot_complete = 1;
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
am_util_debug_printf("HciDrvRadioBoot complete\n");
|
||||
|
||||
// enable interrupt after EM9304 initialization is done.
|
||||
am_devices_em9304_enable_interrupt();
|
||||
}
|
||||
|
||||
void
|
||||
HciDrvRadioShutdown(void)
|
||||
{
|
||||
uint32_t ui32PN;
|
||||
|
||||
radio_boot_complete = 0;
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
|
||||
am_devices_em9304_disable_interrupt();
|
||||
AM_HAL_GPIO_MASKCREATE(GpioIntMask);
|
||||
am_hal_gpio_int_clear(AM_HAL_GPIO_MASKBIT(pGpioIntMask, AM_BSP_GPIO_EM9304_INT));
|
||||
|
||||
am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_CS, AM_HAL_PIN_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_CS);
|
||||
|
||||
am_hal_clkgen_clkout_disable();
|
||||
|
||||
//
|
||||
// Device identification
|
||||
//
|
||||
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
|
||||
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
|
||||
|
||||
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
|
||||
{
|
||||
// Currently clear pin 24 only for Apollo2-Blue
|
||||
am_hal_gpio_pin_config(24, AM_HAL_PIN_24_CLKOUT);
|
||||
am_hal_gpio_out_bit_clear(24);
|
||||
}
|
||||
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_PIN_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
|
||||
am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_INT, AM_HAL_PIN_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_INT);
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsSetRfPowerLevelEx
|
||||
*
|
||||
* \brief Vendor-specific command for settting Radio transmit power level
|
||||
* for EM9304.
|
||||
*
|
||||
* \param txPowerlevel valid range from 0 to 17 in decimal.
|
||||
*
|
||||
* \return true when success, otherwise false
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t HciVsEM_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel)
|
||||
{
|
||||
// make sure it's 8 bit
|
||||
uint8_t tx_power_level = (uint8_t)txPowerlevel;
|
||||
|
||||
if(tx_power_level < TX_POWER_LEVEL_INVALID) {
|
||||
HciVendorSpecificCmd(0xFC26, sizeof(tx_power_level), &tx_power_level);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsEM_TransmitterTest
|
||||
*
|
||||
* \brief Vendor-specific command for start transmitter testing
|
||||
*
|
||||
* \param test_mode refer to em9304 datasheet
|
||||
* \param channel_number refer to em9304 datasheet
|
||||
* \param packet_len refer to em9304 datasheet
|
||||
* \param packet_payload_type refer to em9304 datasheet
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsEM_TransmitterTest(uint8_t test_mode, uint8_t channel_number, uint8_t packet_len, uint8_t packet_payload_type)
|
||||
{
|
||||
uint8_t params[4] = {
|
||||
test_mode,
|
||||
channel_number,
|
||||
packet_len,
|
||||
packet_payload_type
|
||||
};
|
||||
|
||||
HciVendorSpecificCmd(0xFC11, sizeof(params), ¶ms[0]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsEM_TransmitterTestEnd
|
||||
*
|
||||
* \brief Vendor-specific command for ending Radio transmitter testing.
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsEM_TransmitterTestEnd(void)
|
||||
{
|
||||
HciVendorSpecificCmd(0xFC12, 0, NULL);
|
||||
}
|
||||
|
||||
void HciVsEM_ReadAtAddress(uint32_t addr)
|
||||
{
|
||||
uint8_t ReadAtAddress[5];
|
||||
|
||||
// only read 4 bytes
|
||||
memcpy(ReadAtAddress, &addr, 4);
|
||||
ReadAtAddress[4] = 4;
|
||||
HciVendorSpecificCmd(0xFC20, sizeof(ReadAtAddress), ReadAtAddress);
|
||||
}
|
||||
|
||||
void HciVsEM_WriteAtAddress(uint32_t addr, uint32_t value)
|
||||
{
|
||||
uint8_t WriteAtAddress[8];
|
||||
|
||||
// only write 4 bytes
|
||||
memcpy(WriteAtAddress, &addr, 4);
|
||||
memcpy(WriteAtAddress+4, &value, 4);
|
||||
HciVendorSpecificCmd(0xFC22, sizeof(WriteAtAddress), WriteAtAddress);
|
||||
}
|
||||
|
||||
void HciDrvAssignBDAddress(uint8_t * customer_unique_bd_address)
|
||||
{
|
||||
if (customer_unique_bd_address)
|
||||
{
|
||||
memcpy(g_pui8BLEMacAddress, customer_unique_bd_address, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void HciVsEM_SetBDAddress(void)
|
||||
{
|
||||
if (HCI_APOLLO_USE_CUSTOMER_OWN_MAC)
|
||||
{
|
||||
HciVendorSpecificCmd(0xFC02, 6, g_pui8BLEMacAddress);
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv_em9304.h
|
||||
//!
|
||||
//! @brief Support functions for the EM Micro EM9304 BTLE radio.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_DRV_EM9304_H
|
||||
#define HCI_DRV_EM9304_H
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// EM9304 vendor specific events
|
||||
//
|
||||
//*****************************************************************************
|
||||
typedef struct
|
||||
{
|
||||
uint32_t EM_ActiveStateEntered;
|
||||
uint32_t EM_TestModeEntered;
|
||||
uint32_t EM_HalNotification;
|
||||
uint32_t EM_DebugPrint;
|
||||
uint32_t EM_DebugStackUsage;
|
||||
uint32_t EM_DebugBacktrace;
|
||||
uint32_t EM_DebugAssert;
|
||||
} g_EMVSEvent_t;
|
||||
|
||||
// Tx power level in dBm.
|
||||
typedef enum
|
||||
{
|
||||
TX_POWER_LEVEL_MINOR_33P5_dBm, // 0, not compliant with BT spec
|
||||
TX_POWER_LEVEL_MINOR_29P0_dBm, // 1, not compliant with BT spec
|
||||
TX_POWER_LEVEL_MINOR_17P9_dBm, // 2
|
||||
TX_POWER_LEVEL_MINOR_16P4_dBm, // 3
|
||||
TX_POWER_LEVEL_MINOR_14P6_dBm, // 4
|
||||
TX_POWER_LEVEL_MINOR_13P1_dBm, // 5
|
||||
TX_POWER_LEVEL_MINOR_11P4_dBm, // 6
|
||||
TX_POWER_LEVEL_MINOR_9P9_dBm, // 7
|
||||
TX_POWER_LEVEL_MINOR_8P4_dBm, // 8
|
||||
TX_POWER_LEVEL_MINOR_6P9_dBm, // 9
|
||||
TX_POWER_LEVEL_MINOR_5P5_dBm, // 10
|
||||
TX_POWER_LEVEL_MINOR_4P0_dBm, // 11
|
||||
TX_POWER_LEVEL_MINOR_2P6_dBm, // 12
|
||||
TX_POWER_LEVEL_MINOR_1P4_dBm, // 13
|
||||
TX_POWER_LEVEL_PLUS_0P4_dBm, // 14
|
||||
TX_POWER_LEVEL_PLUS_2P5_dBm, // 15
|
||||
TX_POWER_LEVEL_PLUS_4P6_dBm, // 16
|
||||
TX_POWER_LEVEL_PLUS_6P2_dBm, // 17
|
||||
TX_POWER_LEVEL_INVALID
|
||||
}txPowerLevel_t;
|
||||
|
||||
extern g_EMVSEvent_t *getEM9304VSEventCounters(void);
|
||||
extern uint32_t HciVsEM_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel);
|
||||
extern void HciVsEM_TransmitterTest(uint8_t test_mode, uint8_t channel_number, uint8_t packet_len, uint8_t packet_payload_type);
|
||||
extern void HciVsEM_TransmitterTestEnd(void);
|
||||
extern void HciVsEM_ReadAtAddress(uint32_t addr);
|
||||
extern void HciVsEM_WriteAtAddress(uint32_t addr, uint32_t value);
|
||||
extern void HciDrvAssignBDAddress(uint8_t * customer_unique_bd_address);
|
||||
extern void HciVsEM_SetBDAddress(void);
|
||||
|
||||
|
||||
#endif // HCI_DRV_EM9304_H
|
||||
+1626
File diff suppressed because it is too large
Load Diff
Vendored
+703
@@ -0,0 +1,703 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI Advertising Extensions (AE) command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set advertising set random device address command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param pAddr Random device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetAdvSetRandAddrCmd(uint8_t advHandle, const uint8_t *pAddr)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_ADV_SET_RAND_ADDR, HCI_LEN_LE_SET_ADV_SET_RAND_ADDR)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
BDA_TO_BSTREAM(p, pAddr);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended advertising parameters command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param pExtAdvParam Extended advertising parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtAdvParamCmd(uint8_t advHandle, hciExtAdvParam_t *pExtAdvParam)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_PARAM, HCI_LEN_LE_SET_EXT_ADV_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT16_TO_BSTREAM(p, pExtAdvParam->advEventProp);
|
||||
UINT24_TO_BSTREAM(p, pExtAdvParam->priAdvInterMin);
|
||||
UINT24_TO_BSTREAM(p, pExtAdvParam->priAdvInterMax);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->priAdvChanMap);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->ownAddrType);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->peerAddrType);
|
||||
BDA_TO_BSTREAM(p, pExtAdvParam->pPeerAddr);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->advFiltPolicy);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->advTxPwr);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->priAdvPhy);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->secAdvMaxSkip);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->secAdvPhy);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->advSetId);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->scanReqNotifEna);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended advertising data command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Operation.
|
||||
* \param fragPref Fragment preference.
|
||||
* \param len Data buffer length.
|
||||
* \param pData Advertising data buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtAdvDataCmd(uint8_t advHandle, uint8_t op, uint8_t fragPref, uint8_t len,
|
||||
const uint8_t *pData)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if (len > HCI_EXT_ADV_DATA_LEN)
|
||||
{
|
||||
len = HCI_EXT_ADV_DATA_LEN;
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_DATA, HCI_LEN_LE_SET_EXT_ADV_DATA(len))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT8_TO_BSTREAM(p, op);
|
||||
UINT8_TO_BSTREAM(p, fragPref);
|
||||
UINT8_TO_BSTREAM(p, len);
|
||||
memcpy(p, pData, len);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended scan response data command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Operation.
|
||||
* \param fragPref Fragment preference.
|
||||
* \param len Data buffer length.
|
||||
* \param pData Scan response data buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtScanRespDataCmd(uint8_t advHandle, uint8_t op, uint8_t fragPref, uint8_t len,
|
||||
const uint8_t *pData)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if (len > HCI_EXT_ADV_DATA_LEN)
|
||||
{
|
||||
len = HCI_EXT_ADV_DATA_LEN;
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_RESP_DATA,
|
||||
HCI_LEN_LE_SET_EXT_SCAN_RESP_DATA(len))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT8_TO_BSTREAM(p, op);
|
||||
UINT8_TO_BSTREAM(p, fragPref);
|
||||
UINT8_TO_BSTREAM(p, len);
|
||||
memcpy(p, pData, len);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended advertising enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable advertising, FALSE to disable advertising.
|
||||
* \param numSets Number of advertising sets.
|
||||
* \param pScanParam Advertising enable parameter array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtAdvEnableCmd(uint8_t enable, uint8_t numSets, hciExtAdvEnableParam_t *pEnableParam)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_ENABLE, HCI_LEN_LE_EXT_ADV_ENABLE(numSets))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT8_TO_BSTREAM(p, numSets);
|
||||
|
||||
for (i = 0; i < numSets; i++)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pEnableParam[i].advHandle);
|
||||
UINT16_TO_BSTREAM(p, pEnableParam[i].duration);
|
||||
UINT8_TO_BSTREAM(p, pEnableParam[i].maxEaEvents);
|
||||
}
|
||||
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read maximum advertising data length command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadMaxAdvDataLen(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN, HCI_LEN_LE_READ_MAX_ADV_DATA_LEN)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read number of supported advertising sets command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadNumSupAdvSets(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS, HCI_LEN_LE_READ_NUM_OF_SUP_ADV_SETS)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE remove advertising set command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return Status error code.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeRemoveAdvSet(uint8_t advHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_REMOVE_ADV_SET, HCI_LEN_LE_REMOVE_ADV_SET)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE clear advertising sets command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeClearAdvSets(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CLEAR_ADV_SETS, HCI_LEN_LE_CLEAR_ADV_SETS)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising parameters command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param advIntervalMin Periodic advertising interval minimum.
|
||||
* \param advIntervalMax Periodic advertising interval maximum.
|
||||
* \param advProps Periodic advertising properties.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvParamCmd(uint8_t advHandle, uint16_t advIntervalMin, uint16_t advIntervalMax,
|
||||
uint16_t advProps)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_PARAM, HCI_LEN_LE_SET_PER_ADV_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT16_TO_BSTREAM(p, advIntervalMin);
|
||||
UINT16_TO_BSTREAM(p, advIntervalMax);
|
||||
UINT16_TO_BSTREAM(p, advProps);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising data command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Operation.
|
||||
* \param len Data buffer length.
|
||||
* \param pData Advertising data buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvDataCmd(uint8_t advHandle, uint8_t op, uint8_t len, const uint8_t *pData)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if (len > HCI_PER_ADV_DATA_LEN)
|
||||
{
|
||||
len = HCI_PER_ADV_DATA_LEN;
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_DATA, HCI_LEN_LE_SET_PER_ADV_DATA(len))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT8_TO_BSTREAM(p, op);
|
||||
UINT8_TO_BSTREAM(p, len);
|
||||
memcpy(p, pData, len);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable advertising, FALSE to disable advertising.
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvEnableCmd(uint8_t enable, uint8_t advHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_ENABLE, HCI_LEN_LE_SET_PER_ADV_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended scanning parameters command.
|
||||
*
|
||||
* \param ownAddrType Address type used by this device.
|
||||
* \param scanFiltPolicy Scan filter policy.
|
||||
* \param scanPhys Scanning PHYs.
|
||||
* \param pScanParam Scanning parameter array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtScanParamCmd(uint8_t ownAddrType, uint8_t scanFiltPolicy, uint8_t scanPhys,
|
||||
hciExtScanParam_t *pScanParam)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
uint8_t numPhys;
|
||||
|
||||
/* find out number of scanning PHYs */
|
||||
for (i = 0, numPhys = 0; (i < 8) && (numPhys <= HCI_MAX_NUM_PHYS); i++)
|
||||
{
|
||||
if (scanPhys & (1 << i))
|
||||
{
|
||||
numPhys++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_PARAM, HCI_LEN_LE_SET_EXT_SCAN_PARAM(numPhys))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, ownAddrType);
|
||||
UINT8_TO_BSTREAM(p, scanFiltPolicy);
|
||||
UINT8_TO_BSTREAM(p, scanPhys);
|
||||
|
||||
for (i = 0; i < numPhys; i++)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pScanParam[i].scanType);
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanInterval);
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanWindow)
|
||||
}
|
||||
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE extended scan enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable scanning, FALSE to disable scanning.
|
||||
* \param filterDup Set to TRUE to filter duplicates.
|
||||
* \param duration Duration.
|
||||
* \param period Period.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeExtScanEnableCmd(uint8_t enable, uint8_t filterDup, uint16_t duration, uint16_t period)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_ENABLE, HCI_LEN_LE_SET_EXT_SCAN_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT8_TO_BSTREAM(p, filterDup);
|
||||
UINT16_TO_BSTREAM(p, duration);
|
||||
UINT16_TO_BSTREAM(p, period);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE extended create connection command.
|
||||
*
|
||||
* \param pInitParam Initiating parameters.
|
||||
* \param pScanParam Initiating scan parameters.
|
||||
* \param pConnSpec Connection specification.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeExtCreateConnCmd(hciExtInitParam_t *pInitParam, hciExtInitScanParam_t *pScanParam,
|
||||
hciConnSpec_t *pConnSpec)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
uint8_t numPhys;
|
||||
|
||||
/* find out number of initiating PHYs */
|
||||
for (i = 0, numPhys = 0; (i < 8) && (numPhys <= HCI_MAX_NUM_PHYS); i++)
|
||||
{
|
||||
if (pInitParam->initPhys & (1 << i))
|
||||
{
|
||||
numPhys++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_EXT_CREATE_CONN, HCI_LEN_LE_EXT_CREATE_CONN(numPhys))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, pInitParam->filterPolicy);
|
||||
UINT8_TO_BSTREAM(p, pInitParam->ownAddrType);
|
||||
UINT8_TO_BSTREAM(p, pInitParam->peerAddrType);
|
||||
BDA_TO_BSTREAM(p, pInitParam->pPeerAddr);
|
||||
UINT8_TO_BSTREAM(p, pInitParam->initPhys);
|
||||
|
||||
for (i = 0; i < numPhys; i++)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanInterval);
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanWindow);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].connIntervalMin);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].connIntervalMax);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].connLatency);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].supTimeout);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].minCeLen);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].maxCeLen);
|
||||
}
|
||||
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising create sync command.
|
||||
*
|
||||
* \param options Options.
|
||||
* \param advSid Advertising SID.
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param skip Number of periodic advertising packets that can be skipped after
|
||||
* successful receive.
|
||||
* \param syncTimeout Synchronization timeout.
|
||||
* \param unused Reserved for future use (must be zero).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvCreateSyncCmd(uint8_t options, uint8_t advSid, uint8_t advAddrType,
|
||||
uint8_t *pAdvAddr, uint16_t skip, uint16_t syncTimeout, uint8_t unused)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_CREATE_SYNC, HCI_LEN_LE_PER_ADV_CREATE_SYNC)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, options);
|
||||
UINT8_TO_BSTREAM(p, advSid);
|
||||
UINT8_TO_BSTREAM(p, advAddrType);
|
||||
BDA_TO_BSTREAM(p, pAdvAddr);
|
||||
UINT16_TO_BSTREAM(p, skip);
|
||||
UINT16_TO_BSTREAM(p, syncTimeout);
|
||||
UINT8_TO_BSTREAM(p, unused);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising create sync cancel command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvCreateSyncCancelCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_CREATE_SYNC_CANCEL, HCI_LEN_LE_PER_ADV_CREATE_SYNC_CANCEL)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising terminate sync command.
|
||||
*
|
||||
* \param syncHandle Sync handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvTerminateSyncCmd(uint16_t syncHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_TERMINATE_SYNC, HCI_LEN_LE_PER_ADV_TERMINATE_SYNC)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, syncHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE add device to periodic advertiser list command.
|
||||
*
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param advSid Advertising SID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeAddDeviceToPerAdvListCmd(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_ADD_DEV_PER_ADV_LIST, HCI_LEN_LE_ADD_DEV_PER_ADV_LIST)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advAddrType);
|
||||
BDA_TO_BSTREAM(p, pAdvAddr);
|
||||
UINT8_TO_BSTREAM(p, advSid);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE remove device from periodic advertiser list command.
|
||||
*
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param advSid Advertising SID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeRemoveDeviceFromPerAdvListCmd(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_REMOVE_DEV_PER_ADV_LIST, HCI_LEN_LE_REMOVE_DEV_PER_ADV_LIST)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advAddrType);
|
||||
BDA_TO_BSTREAM(p, pAdvAddr);
|
||||
UINT8_TO_BSTREAM(p, advSid);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE clear periodic advertiser list command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeClearPerAdvListCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CLEAR_PER_ADV_LIST, HCI_LEN_LE_CLEAR_PER_ADV_LIST)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read periodic advertiser size command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadPerAdvListSizeCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE, HCI_LEN_LE_READ_PER_ADV_LIST_SIZE)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read transmit power command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadTxPower(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_TX_POWER, HCI_LEN_LE_READ_TX_POWER)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read RF path compensation command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadRfPathComp(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_RF_PATH_COMP, HCI_LEN_LE_READ_RF_PATH_COMP)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE write RF path compensation command.
|
||||
*
|
||||
* \param txPathComp RF transmit path compensation value.
|
||||
* \param rxPathComp RF receive path compensation value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeWriteRfPathComp(int16_t txPathComp, int16_t rxPathComp)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_WRITE_RF_PATH_COMP, HCI_LEN_LE_WRITE_RF_PATH_COMP)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, txPathComp);
|
||||
UINT16_TO_BSTREAM(p, rxPathComp);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
Vendored
+165
@@ -0,0 +1,165 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI Constant Tone Extension (CTE) command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set connection CTE receive parameters command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param samplingEnable TRUE to enable Connection IQ sampling, FALSE to disable it.
|
||||
* \param slotDurations Switching and sampling slot durations to be used while receiving CTE.
|
||||
* \param switchPatternLen Number of Antenna IDs in switching pattern.
|
||||
* \param pAntennaIDs List of Antenna IDs in switching pattern.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetConnCteRxParamsCmd(uint16_t connHandle, uint8_t samplingEnable, uint8_t slotDurations,
|
||||
uint8_t switchPatternLen, uint8_t *pAntennaIDs)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_CONN_CTE_RX_PARAMS,
|
||||
HCI_LEN_LE_SET_CONN_CTE_RX_PARAMS(switchPatternLen))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, samplingEnable);
|
||||
UINT8_TO_BSTREAM(p, slotDurations);
|
||||
UINT8_TO_BSTREAM(p, switchPatternLen);
|
||||
memcpy(p, pAntennaIDs, switchPatternLen);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set connection CTE transmit parameters command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param cteTypeBits Permitted CTE type bits used for transmitting CTEs requested by peer.
|
||||
* \param switchPatternLen Number of Antenna IDs in switching pattern.
|
||||
* \param pAntennaIDs List of Antenna IDs in switching pattern.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetConnCteTxParamsCmd(uint16_t connHandle, uint8_t cteTypeBits, uint8_t switchPatternLen,
|
||||
uint8_t *pAntennaIDs)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_CONN_CTE_TX_PARAMS,
|
||||
HCI_LEN_LE_SET_CONN_CTE_TX_PARAMS(switchPatternLen))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, cteTypeBits);
|
||||
UINT8_TO_BSTREAM(p, switchPatternLen);
|
||||
memcpy(p, pAntennaIDs, switchPatternLen);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE connection CTE request enable command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param enable TRUE to enable CTE request for connection, FALSE to disable it.
|
||||
* \param cteReqInt CTE request interval.
|
||||
* \param reqCteLen Minimum length of CTE being requested in 8 us units.
|
||||
* \param reqCteType Requested CTE type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeConnCteReqEnableCmd(uint16_t connHandle, uint8_t enable, uint16_t cteReqInt,
|
||||
uint8_t reqCteLen, uint8_t reqCteType)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CONN_CTE_REQ_ENABLE,
|
||||
HCI_LEN_LE_CONN_CTE_REQ_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT16_TO_BSTREAM(p, cteReqInt);
|
||||
UINT8_TO_BSTREAM(p, reqCteLen);
|
||||
UINT8_TO_BSTREAM(p, reqCteType);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE connection CTE response enable command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param enable TRUE to enable CTE response for connection, FALSE to disable it.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeConnCteRspEnableCmd(uint16_t connHandle, uint8_t enable)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CONN_CTE_RSP_ENABLE,
|
||||
HCI_LEN_LE_CONN_CTE_RSP_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read antenna information command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadAntennaInfoCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_ANTENNA_INFO, HCI_LEN_LE_READ_ANTENNA_INFO)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
Vendored
+171
@@ -0,0 +1,171 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI Periodic Advertising Sync Transfer (PAST) command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising receive enable command.
|
||||
*
|
||||
* \param syncHandle Periodic sync handle.
|
||||
* \param enable TRUE to enable reports, FALSE to disable reports.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvRcvEnableCmd(uint16_t syncHandle, uint8_t enable)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_RCV_ENABLE,
|
||||
HCI_LEN_LE_SET_PER_ADV_RCV_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, syncHandle);
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising sync transfer command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param serviceData Service data provided by the host.
|
||||
* \param syncHandle Periodic sync handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvSyncTrsfCmd(uint16_t connHandle, uint16_t serviceData, uint16_t syncHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_SYNC_TRANSFER,
|
||||
HCI_LEN_LE_PER_ADV_SYNC_TRANSFER)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT16_TO_BSTREAM(p, serviceData);
|
||||
UINT16_TO_BSTREAM(p, syncHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising set info transfer command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param serviceData Service data provided by the host.
|
||||
* \param advHandle Handle to identify an advertising set.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvSetInfoTrsfCmd(uint16_t connHandle, uint16_t serviceData, uint8_t advHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_SET_INFO_TRANSFER,
|
||||
HCI_LEN_LE_PER_ADV_SET_INFO_TRANSFER)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT16_TO_BSTREAM(p, serviceData);
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising sync transfer parameters command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param mode Periodic sync advertising sync transfer mode.
|
||||
* \param skip The number of periodic advertising packets that can be skipped after
|
||||
* a successful receive.
|
||||
* \param syncTimeout Synchronization timeout for the periodic advertising.
|
||||
* \param cteType Constant tone extension type(Used in AoD/AoA).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvSyncTrsfParamsCmd(uint16_t connHandle, uint8_t mode, uint16_t skip,
|
||||
uint16_t syncTimeout, uint8_t cteType)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PAST_PARAM, HCI_LEN_LE_SET_PAST_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, mode);
|
||||
UINT16_TO_BSTREAM(p, skip);
|
||||
UINT16_TO_BSTREAM(p, syncTimeout);
|
||||
UINT8_TO_BSTREAM(p, cteType);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set default periodic advertising sync transfer parameters command.
|
||||
*
|
||||
* \param mode Periodic sync advertising sync transfer mode.
|
||||
* \param skip The number of periodic advertising packets that can be skipped after
|
||||
* a successful receive.
|
||||
* \param syncTimeout Synchronization timeout for the periodic advertising.
|
||||
* \param cteType Constant tone extension type(Used in AoD/AoA).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetDefaultPerAdvSyncTrsfParamsCmd(uint8_t mode, uint16_t skip, uint16_t syncTimeout,
|
||||
uint8_t cteType)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_DEFAULT_PAST_PARAM,
|
||||
HCI_LEN_LE_SET_DEFAULT_PAST_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, mode);
|
||||
UINT16_TO_BSTREAM(p, skip);
|
||||
UINT16_TO_BSTREAM(p, syncTimeout);
|
||||
UINT8_TO_BSTREAM(p, cteType);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
Vendored
+94
@@ -0,0 +1,94 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI PHY command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI read PHY command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadPhyCmd(uint16_t handle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_PHY, HCI_LEN_LE_READ_PHY)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI set default PHY command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetDefaultPhyCmd(uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_DEF_PHY, HCI_LEN_LE_SET_DEF_PHY)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, allPhys);
|
||||
UINT8_TO_BSTREAM(p, txPhys);
|
||||
UINT8_TO_BSTREAM(p, rxPhys);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI set PHY command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPhyCmd(uint16_t handle, uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys, uint16_t phyOptions)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PHY, HCI_LEN_LE_SET_PHY)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
UINT8_TO_BSTREAM(p, allPhys);
|
||||
UINT8_TO_BSTREAM(p, txPhys);
|
||||
UINT8_TO_BSTREAM(p, rxPhys);
|
||||
UINT16_TO_BSTREAM(p, phyOptions);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
+924
@@ -0,0 +1,924 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_core.c
|
||||
*
|
||||
* \brief HCI core module, platform independent functions.
|
||||
*
|
||||
* $Date: 2017-03-10 14:08:37 -0600 (Fri, 10 Mar 2017) $
|
||||
* $Revision: 11501 $
|
||||
*
|
||||
* Copyright (c) 2009-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "bda.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
#include "l2c_defs.h"
|
||||
#include "am_mcu_apollo.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Default ACL buffer flow control watermark levels */
|
||||
#ifndef HCI_ACL_QUEUE_HI
|
||||
#define HCI_ACL_QUEUE_HI 5 /* Disable flow when this many buffers queued */
|
||||
#endif
|
||||
#ifndef HCI_ACL_QUEUE_LO
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
#define HCI_ACL_QUEUE_LO 3 /* Enable flow when this many buffers queued */
|
||||
#else
|
||||
#define HCI_ACL_QUEUE_LO 1 /* Enable flow when this many buffers queued */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Default maximum ACL packet size for reassembly */
|
||||
#ifndef HCI_MAX_RX_ACL_LEN
|
||||
#define HCI_MAX_RX_ACL_LEN HCI_ACL_DEFAULT_LEN
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Event mask */
|
||||
const uint8_t hciEventMask[HCI_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_DISCONNECT_CMPL | /* Byte 0 */
|
||||
HCI_EVT_MASK_ENC_CHANGE, /* Byte 0 */
|
||||
HCI_EVT_MASK_READ_REMOTE_VER_INFO_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_HW_ERROR, /* Byte 1 */
|
||||
0, /* Byte 2 */
|
||||
HCI_EVT_MASK_DATA_BUF_OVERFLOW, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
HCI_EVT_MASK_ENC_KEY_REFRESH_CMPL, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
HCI_EVT_MASK_LE_META /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE event mask */
|
||||
const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_LE_CONN_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_ADV_REPORT_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_CONN_UPDATE_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_REMOTE_FEAT_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_LTK_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_REMOTE_CONN_PARAM_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_DATA_LEN_CHANGE_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_LOCAL_P256_PUB_KEY_CMPL, /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_GENERATE_DHKEY_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_ENHANCED_CONN_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_DIRECT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PHY_UPDATE_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_EXT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_EST_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_LOST_EVT, /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_SCAN_TIMEOUT_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_ADV_SET_TERM_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_SCAN_REQ_RCVD_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CH_SEL_ALGO_EVT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* event mask page 2 */
|
||||
const uint8_t hciEventMaskPage2[HCI_EVT_MASK_PAGE_2_LEN] =
|
||||
{
|
||||
0, /* Byte 0 */
|
||||
0, /* Byte 1 */
|
||||
HCI_EVT_MASK_AUTH_PAYLOAD_TIMEOUT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE supported features configuration mask */
|
||||
uint32_t hciLeSupFeatCfg =
|
||||
HCI_LE_SUP_FEAT_ENCRYPTION | /* LE Encryption */
|
||||
HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC | /* Connection Parameters Request Procedure */
|
||||
HCI_LE_SUP_FEAT_EXT_REJECT_IND | /* Extended Reject Indication */
|
||||
HCI_LE_SUP_FEAT_SLV_INIT_FEAT_EXCH | /* Slave-initiated Features Exchange */
|
||||
HCI_LE_SUP_FEAT_LE_PING | /* LE Ping */
|
||||
HCI_LE_SUP_FEAT_DATA_LEN_EXT | /* LE Data Packet Length Extension */
|
||||
HCI_LE_SUP_FEAT_PRIVACY | /* LL Privacy */
|
||||
HCI_LE_SUP_FEAT_EXT_SCAN_FILT_POLICY | /* Extended Scanner Filter Policies */
|
||||
HCI_LE_SUP_FEAT_LE_2M_PHY | /* LE 2M PHY supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_TRANSMITTER | /* Stable Modulation Index - Transmitter supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_RECEIVER | /* Stable Modulation Index - Receiver supported */
|
||||
HCI_LE_SUP_FEAT_LE_EXT_ADV | /* LE Extended Advertising */
|
||||
HCI_LE_SUP_FEAT_LE_PER_ADV; /* LE Periodic Advertising */
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
hciCoreCb_t hciCoreCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnAlloc
|
||||
*
|
||||
* \brief Allocate a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnAlloc(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == HCI_HANDLE_NONE)
|
||||
{
|
||||
/* allocate and initialize */
|
||||
pConn->handle = handle;
|
||||
pConn->flowDisabled = FALSE;
|
||||
pConn->outBufs = 0;
|
||||
pConn->queuedBufs = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN0("HCI conn struct alloc failure");
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnFree
|
||||
*
|
||||
* \brief Free a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnFree(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
/* free any fragmenting ACL packet */
|
||||
if (pConn->pTxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
}
|
||||
pConn->fragmenting = FALSE;
|
||||
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
|
||||
/* free structure */
|
||||
pConn->handle = HCI_HANDLE_NONE;
|
||||
|
||||
/* optional: iterate through tx ACL queue and free any buffers with this handle */
|
||||
|
||||
/* outstanding buffers are now available; service TX data path */
|
||||
hciCoreTxReady(pConn->outBufs);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreConnFree handle not found:%u", handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnByHandle
|
||||
*
|
||||
* \brief Get a connection structure by handle
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreNextConnFragment
|
||||
*
|
||||
* \brief Get the next connection structure with a packet fragment to send.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static hciCoreConn_t *hciCoreNextConnFragment(void)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle != HCI_HANDLE_NONE && pConn->fragmenting)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnOpen
|
||||
*
|
||||
* \brief Perform internal processing on HCI connection open.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnOpen(uint16_t handle)
|
||||
{
|
||||
/* allocate connection structure */
|
||||
hciCoreConnAlloc(handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnClose
|
||||
*
|
||||
* \brief Perform internal processing on HCI connection close.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnClose(uint16_t handle)
|
||||
{
|
||||
/* free connection structure */
|
||||
hciCoreConnFree(handle);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreSendAclData
|
||||
*
|
||||
* \brief Send ACL data to transport.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* increment outstanding buf count for handle */
|
||||
pConn->outBufs++;
|
||||
|
||||
/* send to transport */
|
||||
hciTrSendAclData(pConn, pData);
|
||||
|
||||
/* decrement available buffer count */
|
||||
if (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs--;
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN0("hciCoreSendAclData availBufs=0");
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxReady
|
||||
*
|
||||
* \brief Service the TX data path.
|
||||
*
|
||||
* \param bufs Number of new buffers now available.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxReady(uint8_t bufs)
|
||||
{
|
||||
uint8_t *pData;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* increment available buffers, with ceiling */
|
||||
if (bufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs += bufs;
|
||||
if (hciCoreCb.availBufs > hciCoreCb.numBufs)
|
||||
{
|
||||
hciCoreCb.availBufs = hciCoreCb.numBufs;
|
||||
}
|
||||
}
|
||||
|
||||
/* service ACL data queue and send as many buffers as we can */
|
||||
while (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send continuation of any fragments first */
|
||||
if (hciCoreTxAclContinue(NULL) == FALSE)
|
||||
{
|
||||
/* if no fragments then check for any queued ACL data */
|
||||
if ((pData = WsfMsgDeq(&hciCoreCb.aclQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up conn structure and send data */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
/* handle not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreTxReady discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragments or queued data to send; we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclStart
|
||||
*
|
||||
* \brief Send ACL packets, start of packet.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param len ACL packet length.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData)
|
||||
{
|
||||
uint16_t hciLen;
|
||||
|
||||
/* make sure not already fragmenting on this connection */
|
||||
WSF_ASSERT(pConn->fragmenting == FALSE);
|
||||
|
||||
hciLen = HciGetBufSize();
|
||||
|
||||
HCI_TRACE_INFO1("hciCoreTxAclStart len=%u", len);
|
||||
|
||||
/* if acl len > controller acl buf len */
|
||||
if (len > hciLen)
|
||||
{
|
||||
/* store remaining acl len = acl len - hci acl buf len */
|
||||
pConn->txAclRemLen = len - hciLen;
|
||||
|
||||
/* store position for next fragment */
|
||||
pConn->pNextTxFrag = pData + hciLen;
|
||||
|
||||
/* store information required for fragmentation */
|
||||
pConn->pTxAclPkt = pData;
|
||||
pConn->fragmenting = TRUE;
|
||||
|
||||
/* set acl len in packet to hci acl buf len */
|
||||
UINT16_TO_BUF(&pData[2], hciLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
|
||||
/* send additional fragments while there are HCI buffers available */
|
||||
while ((hciCoreCb.availBufs > 0) && hciCoreTxAclContinue(pConn));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragmentation, just send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclContinue
|
||||
*
|
||||
* \brief Send ACL packets, continuation of fragmented packets.
|
||||
*
|
||||
* \param pConn Pointer to connection structure. If set non-NULL, then a fragment is
|
||||
* sent from this connection structure. If NULL the function finds the next
|
||||
* connection structure with a fragment to be sent.
|
||||
*
|
||||
* \return TRUE if packet sent, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn)
|
||||
{
|
||||
uint16_t aclLen;
|
||||
|
||||
if (pConn == NULL)
|
||||
{
|
||||
pConn = hciCoreNextConnFragment();
|
||||
}
|
||||
|
||||
if (pConn != NULL)
|
||||
{
|
||||
/* get next fragment length */
|
||||
aclLen = (pConn->txAclRemLen < HciGetBufSize()) ? pConn->txAclRemLen : HciGetBufSize();
|
||||
|
||||
if (aclLen > 0)
|
||||
{
|
||||
/* decrement remaining length */
|
||||
pConn->txAclRemLen -= aclLen;
|
||||
|
||||
/* set handle in packet with continuation bit set */
|
||||
UINT16_TO_BUF(pConn->pNextTxFrag, (pConn->handle | HCI_PB_CONTINUE));
|
||||
|
||||
/* set acl len in packet */
|
||||
UINT16_TO_BUF(&(pConn->pNextTxFrag[2]), aclLen);
|
||||
|
||||
HCI_TRACE_INFO2("hciCoreTxAclContinue aclLen=%u remLen=%u", aclLen, pConn->txAclRemLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pConn->pNextTxFrag);
|
||||
|
||||
/* set up pointer to next fragment */
|
||||
if (pConn->txAclRemLen > 0)
|
||||
{
|
||||
pConn->pNextTxFrag += aclLen;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclComplete
|
||||
*
|
||||
* \brief This function is called from the HCI transport layer when transmission of an ACL
|
||||
* packet is complete.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* if fragmenting */
|
||||
if (pConn->fragmenting)
|
||||
{
|
||||
/* check if all fragments sent */
|
||||
if (pConn->txAclRemLen == 0)
|
||||
{
|
||||
/* free original buffer */
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
pConn->fragmenting = FALSE;
|
||||
HCI_TRACE_INFO0("hciCoreTxAclComplete free pTxAclPkt");
|
||||
}
|
||||
}
|
||||
else if (pData != NULL)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreAclReassembly
|
||||
*
|
||||
* \brief Reassemble an ACL packet.
|
||||
*
|
||||
* \param pData Input ACL packet.
|
||||
*
|
||||
* \return pointer to ACL packet to send, or NULL if no packet to send.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *hciCoreAclReassembly(uint8_t *pData)
|
||||
{
|
||||
hciCoreConn_t *pConn;
|
||||
uint8_t *pDataRtn = NULL;
|
||||
uint16_t handle;
|
||||
uint16_t aclLen;
|
||||
uint16_t l2cLen;
|
||||
uint16_t pbf;
|
||||
bool_t freeData = TRUE;
|
||||
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
pbf = handle & HCI_PB_FLAG_MASK;
|
||||
handle &= HCI_HANDLE_MASK;
|
||||
BYTES_TO_UINT16(aclLen, &pData[2]);
|
||||
|
||||
/* look up connection */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if this is a start packet */
|
||||
if (pbf == HCI_PB_START_C2H)
|
||||
{
|
||||
/* if currently reassembled packet not complete */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
/* discard currently reassembled packet */
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
HCI_TRACE_WARN1("disarded hci rx pkt handle=0x%04x", handle);
|
||||
}
|
||||
|
||||
/* read l2cap length */
|
||||
if (aclLen >= L2C_HDR_LEN)
|
||||
{
|
||||
BYTES_TO_UINT16(l2cLen, &pData[4]);
|
||||
|
||||
/* check length vs. configured maximum */
|
||||
if ((l2cLen + L2C_HDR_LEN) > hciCoreCb.maxRxAclLen)
|
||||
{
|
||||
HCI_TRACE_WARN1("l2c len=0x%04x to large for reassembly", l2cLen);
|
||||
}
|
||||
/* if reassembly required */
|
||||
else if ((l2cLen + L2C_HDR_LEN) > aclLen)
|
||||
{
|
||||
/* allocate buffer to store complete l2cap packet */
|
||||
if ((pConn->pRxAclPkt = WsfMsgDataAlloc(l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN, 0)) != NULL)
|
||||
{
|
||||
/* store buffer for reassembly */
|
||||
pConn->pNextRxFrag = pConn->pRxAclPkt;
|
||||
|
||||
/* build acl header and copy data */
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, handle);
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, l2cLen + L2C_HDR_LEN);
|
||||
memcpy(pConn->pNextRxFrag, &pData[4], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* store remaining length */
|
||||
pConn->rxAclRemLen = l2cLen + L2C_HDR_LEN - aclLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* alloc failed; discard */
|
||||
HCI_TRACE_WARN1("reassembly alloc failed len=%u", (l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no reassembly required, pData is ready to go */
|
||||
pDataRtn = pData;
|
||||
freeData = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid l2cap packet; discard */
|
||||
HCI_TRACE_WARN1("invalid l2c pkt aclLen=%u", aclLen);
|
||||
}
|
||||
}
|
||||
/* else if this is a continuation packet */
|
||||
else if (pbf == HCI_PB_CONTINUE)
|
||||
{
|
||||
/* if expecting a continuation */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
if (aclLen <= pConn->rxAclRemLen)
|
||||
{
|
||||
/* copy data to start of next fragment */
|
||||
memcpy(pConn->pNextRxFrag, &pData[HCI_ACL_HDR_LEN], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* update remaining length */
|
||||
pConn->rxAclRemLen -= aclLen;
|
||||
|
||||
/* if reassembly complete return reassembled packet */
|
||||
if (pConn->rxAclRemLen == 0)
|
||||
{
|
||||
pDataRtn = pConn->pRxAclPkt;
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN2("continuation pkt too long len=%u RemLen=%u", aclLen, pConn->rxAclRemLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unexpected continuation pkt handle=0x%04x", handle);
|
||||
}
|
||||
}
|
||||
/* else unknown packet type */
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unknown pb flags=0x%04x", pbf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* connection not found */
|
||||
HCI_TRACE_WARN1("pkt rcvd on unknown handle=0x%04x", (handle & HCI_HANDLE_MASK));
|
||||
}
|
||||
|
||||
if (freeData)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
|
||||
return pDataRtn;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclDataFragmented
|
||||
*
|
||||
* \brief Check if a TX ACL packet is being fragmented.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
*
|
||||
* \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn)
|
||||
{
|
||||
return pConn->fragmenting;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciCoreInit
|
||||
*
|
||||
* \brief HCI core initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciCoreInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
WSF_QUEUE_INIT(&hciCoreCb.aclQueue);
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
hciCoreCb.conn[i].handle = HCI_HANDLE_NONE;
|
||||
}
|
||||
|
||||
hciCoreCb.maxRxAclLen = HCI_MAX_RX_ACL_LEN;
|
||||
hciCoreCb.aclQueueHi = HCI_ACL_QUEUE_HI;
|
||||
hciCoreCb.aclQueueLo = HCI_ACL_QUEUE_LO;
|
||||
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
if (APOLLO3_GE_B0)
|
||||
{
|
||||
// B0 has only less internal ACL buffers
|
||||
hciCoreCb.aclQueueHi--;
|
||||
hciCoreCb.aclQueueLo--;
|
||||
}
|
||||
#endif
|
||||
hciCoreCb.extResetSeq = NULL;
|
||||
|
||||
hciCoreInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciResetSequence
|
||||
*
|
||||
* \brief Initiate an HCI reset sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciResetSequence(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
wsfHandlerId_t handlerId;
|
||||
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
// free any pending incoming packets
|
||||
while ((pBuf = WsfMsgDeq(&hciCb.rxQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* Free buffer */
|
||||
WsfMsgFree(pBuf);
|
||||
}
|
||||
|
||||
HCI_TRACE_INFO0("reset sequence");
|
||||
// free any pending tx packets
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
/* free any fragmenting ACL packet */
|
||||
if (pConn->pTxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
}
|
||||
pConn->fragmenting = FALSE;
|
||||
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
|
||||
/* free structure */
|
||||
pConn->handle = HCI_HANDLE_NONE;
|
||||
|
||||
/* optional: iterate through tx ACL queue and free any buffers with this handle */
|
||||
|
||||
/* outstanding buffers are now available; service TX data path */
|
||||
hciCoreTxReady(pConn->outBufs);
|
||||
|
||||
}
|
||||
|
||||
/* set resetting state */
|
||||
hciCb.resetting = TRUE;
|
||||
|
||||
/* start the reset sequence */
|
||||
hciCoreResetStart();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSetMaxRxAclLen
|
||||
*
|
||||
* \brief Set the maximum reassembled RX ACL packet length. Minimum value is 27.
|
||||
*
|
||||
* \param len ACL packet length.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetMaxRxAclLen(uint16_t len)
|
||||
{
|
||||
hciCoreCb.maxRxAclLen = len;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSetAclQueueWatermarks
|
||||
*
|
||||
* \brief Set TX ACL queue high and low watermarks.
|
||||
*
|
||||
* \param queueHi Disable flow on a connection when this many ACL buffers are queued.
|
||||
* queueLo Disable flow on a connection when this many ACL buffers are queued.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetAclQueueWatermarks(uint8_t queueHi, uint8_t queueLo)
|
||||
{
|
||||
hciCoreCb.aclQueueHi = queueHi;
|
||||
hciCoreCb.aclQueueLo = queueLo;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSetLeSupFeat
|
||||
*
|
||||
* \brief Set LE supported features configuration mask.
|
||||
*
|
||||
* \param feat Feature bit to set or clear
|
||||
* \param flag TRUE to set feature bit and FALSE to clear it
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetLeSupFeat(uint32_t feat, bool_t flag)
|
||||
{
|
||||
/* if asked to include feature */
|
||||
if (flag)
|
||||
{
|
||||
/* set feature bit */
|
||||
hciLeSupFeatCfg |= feat;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clear feature bit */
|
||||
hciLeSupFeatCfg &= ~feat;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSendAclData
|
||||
*
|
||||
* \brief Send data from the stack to HCI.
|
||||
*
|
||||
* \param pData WSF buffer containing an ACL packet
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSendAclData(uint8_t *pData)
|
||||
{
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up connection structure */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if queue empty and buffers available */
|
||||
if (WsfQueueEmpty(&hciCoreCb.aclQueue) && hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send data */
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* queue data - message handler ID 'handerId' not used */
|
||||
WsfMsgEnq(&hciCoreCb.aclQueue, 0, pData);
|
||||
}
|
||||
|
||||
/* increment buffer queue count for this connection with consideration for HCI fragmentation */
|
||||
pConn->queuedBufs += ((len - 1) / HciGetBufSize()) + 1;
|
||||
|
||||
/* manage flow control to stack */
|
||||
if (pConn->queuedBufs >= hciCoreCb.aclQueueHi && pConn->flowDisabled == FALSE)
|
||||
{
|
||||
pConn->flowDisabled = TRUE;
|
||||
(*hciCb.flowCback)(handle, TRUE);
|
||||
}
|
||||
}
|
||||
/* connection not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("HciSendAclData discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
Vendored
+391
@@ -0,0 +1,391 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_core_ps.c
|
||||
*
|
||||
* \brief HCI core platform-specific module for dual-chip.
|
||||
*
|
||||
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
|
||||
* $Revision: 10805 $
|
||||
*
|
||||
* Copyright (c) 2009-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "bda.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_evt.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreInit
|
||||
*
|
||||
* \brief HCI core initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreInit(void)
|
||||
{
|
||||
hciCmdInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreNumCmplPkts
|
||||
*
|
||||
* \brief Handle an HCI Number of Completed Packets event.
|
||||
*
|
||||
* \param pMsg Message containing the HCI Number of Completed Packets event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreNumCmplPkts(uint8_t *pMsg)
|
||||
{
|
||||
uint8_t numHandles;
|
||||
uint16_t bufs;
|
||||
uint16_t handle;
|
||||
uint8_t availBufs = 0;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* parse number of handles */
|
||||
BSTREAM_TO_UINT8(numHandles, pMsg);
|
||||
|
||||
/* for each handle in event */
|
||||
while (numHandles-- > 0)
|
||||
{
|
||||
/* parse handle and number of buffers */
|
||||
BSTREAM_TO_UINT16(handle, pMsg);
|
||||
BSTREAM_TO_UINT16(bufs, pMsg);
|
||||
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* decrement outstanding buffer count to controller */
|
||||
pConn->outBufs -= (uint8_t) bufs;
|
||||
|
||||
/* decrement queued buffer count for this connection */
|
||||
pConn->queuedBufs -= (uint8_t) bufs;
|
||||
|
||||
/* increment available buffer count */
|
||||
availBufs += (uint8_t) bufs;
|
||||
|
||||
/* call flow control callback */
|
||||
if (pConn->flowDisabled && pConn->queuedBufs <= hciCoreCb.aclQueueLo)
|
||||
{
|
||||
pConn->flowDisabled = FALSE;
|
||||
(*hciCb.flowCback)(handle, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* service TX data path */
|
||||
hciCoreTxReady(availBufs);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreRecv
|
||||
*
|
||||
* \brief Send a received HCI event or ACL packet to the HCI event handler.
|
||||
*
|
||||
* \param msgType Message type: HCI_ACL_TYPE or HCI_EVT_TYPE.
|
||||
* \param pCoreRecvMsg Pointer to received message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreRecv(uint8_t msgType, uint8_t *pCoreRecvMsg)
|
||||
{
|
||||
/* dump event for protocol analysis */
|
||||
if (msgType == HCI_EVT_TYPE)
|
||||
{
|
||||
HCI_PDUMP_EVT(*(pCoreRecvMsg + 1) + HCI_EVT_HDR_LEN, pCoreRecvMsg);
|
||||
}
|
||||
else if (msgType == HCI_ACL_TYPE)
|
||||
{
|
||||
HCI_PDUMP_RX_ACL(*(pCoreRecvMsg + 2) + HCI_ACL_HDR_LEN, pCoreRecvMsg);
|
||||
}
|
||||
|
||||
/* queue buffer */
|
||||
WsfMsgEnq(&hciCb.rxQueue, (wsfHandlerId_t) msgType, pCoreRecvMsg);
|
||||
|
||||
/* set event */
|
||||
WsfSetEvent(hciCb.handlerId, HCI_EVT_RX);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciCoreHandler
|
||||
*
|
||||
* \brief WSF event handler for core HCI.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciCoreHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
wsfHandlerId_t handlerId;
|
||||
|
||||
/* Handle message */
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
/* Handle HCI command timeout */
|
||||
if (pMsg->event == HCI_MSG_CMD_TIMEOUT)
|
||||
{
|
||||
hciCmdTimeout(pMsg);
|
||||
}
|
||||
}
|
||||
/* Handle events */
|
||||
else if (event & HCI_EVT_RX)
|
||||
{
|
||||
/* Process rx queue */
|
||||
while ((pBuf = WsfMsgDeq(&hciCb.rxQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* Handle incoming HCI events */
|
||||
if (handlerId == HCI_EVT_TYPE)
|
||||
{
|
||||
/* Parse/process events */
|
||||
hciEvtProcessMsg(pBuf);
|
||||
|
||||
/* Handle events during reset sequence */
|
||||
if (hciCb.resetting)
|
||||
{
|
||||
hciCoreResetSequence(pBuf);
|
||||
}
|
||||
|
||||
/* Free buffer */
|
||||
WsfMsgFree(pBuf);
|
||||
}
|
||||
/* Handle ACL data */
|
||||
else
|
||||
{
|
||||
/* Reassemble */
|
||||
if ((pBuf = hciCoreAclReassembly(pBuf)) != NULL)
|
||||
{
|
||||
/* Call ACL callback; client will free buffer */
|
||||
hciCb.aclCback(pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetBdAddr
|
||||
*
|
||||
* \brief Return a pointer to the BD address of this device.
|
||||
*
|
||||
* \return Pointer to the BD address.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *HciGetBdAddr(void)
|
||||
{
|
||||
return hciCoreCb.bdAddr;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetWhiteListSize
|
||||
*
|
||||
* \brief Return the white list size.
|
||||
*
|
||||
* \return White list size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetWhiteListSize(void)
|
||||
{
|
||||
return hciCoreCb.whiteListSize;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetAdvTxPwr
|
||||
*
|
||||
* \brief Return the advertising transmit power.
|
||||
*
|
||||
* \return Advertising transmit power.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
int8_t HciGetAdvTxPwr(void)
|
||||
{
|
||||
return hciCoreCb.advTxPwr;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetBufSize
|
||||
*
|
||||
* \brief Return the ACL buffer size supported by the controller.
|
||||
*
|
||||
* \return ACL buffer size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t HciGetBufSize(void)
|
||||
{
|
||||
return hciCoreCb.bufSize;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetNumBufs
|
||||
*
|
||||
* \brief Return the number of ACL buffers supported by the controller.
|
||||
*
|
||||
* \return Number of ACL buffers.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetNumBufs(void)
|
||||
{
|
||||
return hciCoreCb.numBufs;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetSupStates
|
||||
*
|
||||
* \brief Return the states supported by the controller.
|
||||
*
|
||||
* \return Pointer to the supported states array.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *HciGetSupStates(void)
|
||||
{
|
||||
return hciCoreCb.leStates;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetLeSupFeat
|
||||
*
|
||||
* \brief Return the LE supported features supported by the controller.
|
||||
*
|
||||
* \return Supported features.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t HciGetLeSupFeat(void)
|
||||
{
|
||||
// disable LL connection parameter update feature for a better
|
||||
// interoperability with Android phones (especially older Android OS).
|
||||
return hciCoreCb.leSupFeat & ~HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetMaxRxAclLen
|
||||
*
|
||||
* \brief Get the maximum reassembled RX ACL packet length.
|
||||
*
|
||||
* \return ACL packet length.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t HciGetMaxRxAclLen(void)
|
||||
{
|
||||
return hciCoreCb.maxRxAclLen;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetResolvingListSize
|
||||
*
|
||||
* \brief Return the resolving list size.
|
||||
*
|
||||
* \return resolving list size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetResolvingListSize(void)
|
||||
{
|
||||
return hciCoreCb.resListSize;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciLlPrivacySupported
|
||||
*
|
||||
* \brief Whether LL Privacy is supported.
|
||||
*
|
||||
* \return TRUE if LL Privacy is supported. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t HciLlPrivacySupported(void)
|
||||
{
|
||||
return (hciCoreCb.resListSize > 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetMaxAdvDataLen
|
||||
*
|
||||
* \brief Get the maximum advertisement (or scan response) data length supported by the Controller.
|
||||
*
|
||||
* \return Maximum advertisement data length.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t HciGetMaxAdvDataLen(void)
|
||||
{
|
||||
return hciCoreCb.maxAdvDataLen;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetNumSupAdvSets
|
||||
*
|
||||
* \brief Get the maximum number of advertising sets supported by the Controller.
|
||||
*
|
||||
* \return Maximum number of advertising sets.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetNumSupAdvSets(void)
|
||||
{
|
||||
return hciCoreCb.numSupAdvSets;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciLeAdvExtSupported
|
||||
*
|
||||
* \brief Whether LE Advertising Extensions is supported.
|
||||
*
|
||||
* \return TRUE if LE Advertising Extensions is supported. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t HciLeAdvExtSupported(void)
|
||||
{
|
||||
return (hciCoreCb.numSupAdvSets > 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetPerAdvListSize
|
||||
*
|
||||
* \brief Return the periodic advertising list size.
|
||||
*
|
||||
* \return periodic advertising list size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetPerAdvListSize(void)
|
||||
{
|
||||
return hciCoreCb.perAdvListSize;
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_core_ps.h
|
||||
*
|
||||
* \brief HCI core platform-specific interfaces for dual-chip.
|
||||
*
|
||||
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
|
||||
* $Revision: 10805 $
|
||||
*
|
||||
* Copyright (c) 2013-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef HCI_CORE_PS_H
|
||||
#define HCI_CORE_PS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
void hciCoreResetSequence(uint8_t *pMsg);
|
||||
void hciCoreNumCmplPkts(uint8_t *pMsg);
|
||||
void hciCoreRecv(uint8_t msgType, uint8_t *pCoreRecvMsg);
|
||||
uint8_t hciCoreVsCmdCmplRcvd(uint16_t opcode, uint8_t *pMsg, uint8_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_CORE_PS_H */
|
||||
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv_apollo.h
|
||||
//!
|
||||
//! @brief Additional header information for the Apollo implementation of HCI.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef HCI_DRV_APOLLO_H
|
||||
#define HCI_DRV_APOLLO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Errors
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define HCI_DRV_SPECIFIC_ERROR_START 0x09000000
|
||||
typedef enum
|
||||
{
|
||||
HCI_DRV_TRANSMIT_QUEUE_FULL = HCI_DRV_SPECIFIC_ERROR_START,
|
||||
HCI_DRV_TX_PACKET_TOO_LARGE,
|
||||
HCI_DRV_RX_PACKET_TOO_LARGE,
|
||||
HCI_DRV_BLE_STACK_UNABLE_TO_ACCEPT_PACKET,
|
||||
HCI_DRV_PACKET_TRANSMIT_FAILED,
|
||||
HCI_DRV_IRQ_STUCK_HIGH,
|
||||
HCI_DRV_TOO_MANY_PACKETS,
|
||||
}
|
||||
hci_drv_error_t;
|
||||
|
||||
typedef void (*hci_drv_error_handler_t)(uint32_t ui32Error);
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Function prototypes.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern void HciDrvUartEnable(void);
|
||||
extern void HciDrvUartDisable(void);
|
||||
extern void HciDrvUartFlowOff(void);
|
||||
extern void HciDrvUartFlowOn(void);
|
||||
extern void HciDrvUartPause(void);
|
||||
extern void HciDrvUartUnpause(void);
|
||||
extern bool HciDrvUartSafeShutdown(void);
|
||||
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
extern void HciDrvRadioBoot(bool bColdBoot);
|
||||
#else
|
||||
extern void HciDrvRadioBoot(uint32_t ui32UartModule);
|
||||
#endif
|
||||
|
||||
extern void HciDrvRadioShutdown(void);
|
||||
extern void HciDrvUartISR(uint32_t ui32Status);
|
||||
extern bool_t HciDataReadyISR(void);
|
||||
extern void HciDrvIntService(void);
|
||||
extern void HciDrvGPIOService(void);
|
||||
extern void HciDrvHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
extern void HciDrvErrorHandlerSet(hci_drv_error_handler_t pfnErrorHandler);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // HCI_DRV_APOLLO_H
|
||||
+2081
File diff suppressed because it is too large
Load Diff
+304
@@ -0,0 +1,304 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_tr.c
|
||||
*
|
||||
* \brief HCI transport module.
|
||||
*
|
||||
* $Date: 2017-03-10 14:08:37 -0600 (Fri, 10 Mar 2017) $
|
||||
* $Revision: 11501 $
|
||||
*
|
||||
* Copyright (c) 2011-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_drv.h"
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
State variable
|
||||
**************************************************************************************************/
|
||||
static volatile bool_t g_bHCIReceivingPacket = FALSE;
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
#define HCI_HDR_LEN_MAX HCI_ACL_HDR_LEN
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HCI_RX_STATE_IDLE,
|
||||
HCI_RX_STATE_HEADER,
|
||||
HCI_RX_STATE_DATA,
|
||||
HCI_RX_STATE_COMPLETE
|
||||
} hciRxState_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciTrSendAclData
|
||||
*
|
||||
* \brief Send a complete HCI ACL packet to the transport.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
* \param pData WSF msg buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendAclData(void *pContext, uint8_t *pData)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
/* get 16-bit length */
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
len += HCI_ACL_HDR_LEN;
|
||||
|
||||
/* dump event for protocol analysis */
|
||||
HCI_PDUMP_TX_ACL(len, pData);
|
||||
|
||||
/* transmit ACL header and data */
|
||||
if (hciDrvWrite(HCI_ACL_TYPE, len, pData) == len)
|
||||
{
|
||||
/* free buffer */
|
||||
hciCoreTxAclComplete(pContext, pData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciTrSendCmd
|
||||
*
|
||||
* \brief Send a complete HCI command to the transport.
|
||||
*
|
||||
* \param pData WSF msg buffer containing an HCI command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendCmd(uint8_t *pData)
|
||||
{
|
||||
uint8_t len;
|
||||
|
||||
/* get length */
|
||||
len = pData[2] + HCI_CMD_HDR_LEN;
|
||||
|
||||
/* dump event for protocol analysis */
|
||||
HCI_PDUMP_CMD(len, pData);
|
||||
|
||||
/* transmit ACL header and data */
|
||||
if (hciDrvWrite(HCI_CMD_TYPE, len, pData) == len)
|
||||
{
|
||||
/* free buffer */
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciSerialRxIncoming
|
||||
*
|
||||
* \brief Receive function. Gets called by external code when bytes are received.
|
||||
*
|
||||
* \param pBuf Pointer to buffer of incoming bytes.
|
||||
* \param len Number of bytes in incoming buffer.
|
||||
*
|
||||
* \return The number of bytes consumed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t hciTrSerialRxIncoming(uint8_t *pBuf, uint16_t len)
|
||||
{
|
||||
static uint8_t stateRx = HCI_RX_STATE_IDLE;
|
||||
static uint8_t pktIndRx;
|
||||
static uint16_t iRx;
|
||||
static uint8_t hdrRx[HCI_HDR_LEN_MAX];
|
||||
static uint8_t *pPktRx;
|
||||
static uint8_t *pDataRx;
|
||||
|
||||
uint8_t dataByte;
|
||||
uint16_t consumed_bytes;
|
||||
|
||||
consumed_bytes = 0;
|
||||
/* loop until all bytes of incoming buffer are handled */
|
||||
while (len)
|
||||
{
|
||||
/* read single byte from incoming buffer and advance to next byte */
|
||||
dataByte = *pBuf;
|
||||
|
||||
/* --- Idle State --- */
|
||||
if (stateRx == HCI_RX_STATE_IDLE)
|
||||
{
|
||||
/* save the packet type */
|
||||
pktIndRx = dataByte;
|
||||
iRx = 0;
|
||||
stateRx = HCI_RX_STATE_HEADER;
|
||||
g_bHCIReceivingPacket = TRUE;
|
||||
pBuf++;
|
||||
consumed_bytes++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* --- Header State --- */
|
||||
else if (stateRx == HCI_RX_STATE_HEADER)
|
||||
{
|
||||
uint8_t hdrLen = 0;
|
||||
uint16_t dataLen = 0;
|
||||
|
||||
/* determine header length based on packet type */
|
||||
if (pktIndRx == HCI_EVT_TYPE)
|
||||
{
|
||||
hdrLen = HCI_EVT_HDR_LEN;
|
||||
}
|
||||
else if (pktIndRx == HCI_ACL_TYPE)
|
||||
{
|
||||
hdrLen = HCI_ACL_HDR_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid packet type */
|
||||
WSF_ASSERT(0);
|
||||
return consumed_bytes;
|
||||
}
|
||||
|
||||
if (iRx != hdrLen) {
|
||||
/* copy current byte into the temp header buffer */
|
||||
hdrRx[iRx++] = dataByte;
|
||||
pBuf++;
|
||||
consumed_bytes++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* see if entire header has been read */
|
||||
if (iRx == hdrLen)
|
||||
{
|
||||
/* extract data length from header */
|
||||
if (pktIndRx == HCI_EVT_TYPE)
|
||||
{
|
||||
dataLen = hdrRx[1];
|
||||
}
|
||||
else if (pktIndRx == HCI_ACL_TYPE)
|
||||
{
|
||||
BYTES_TO_UINT16(dataLen, &hdrRx[2]);
|
||||
}
|
||||
|
||||
/* allocate data buffer to hold entire packet */
|
||||
if (pktIndRx == HCI_ACL_TYPE)
|
||||
{
|
||||
pPktRx = (uint8_t*)WsfMsgDataAlloc(hdrLen + dataLen, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPktRx = (uint8_t*)WsfMsgAlloc(hdrLen + dataLen);
|
||||
}
|
||||
|
||||
if (pPktRx != NULL)
|
||||
{
|
||||
pDataRx = pPktRx;
|
||||
|
||||
/* copy header into data packet (note: memcpy is not so portable) */
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < hdrLen; i++)
|
||||
{
|
||||
*pDataRx++ = hdrRx[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* save number of bytes left to read */
|
||||
iRx = dataLen;
|
||||
if (iRx == 0)
|
||||
{
|
||||
stateRx = HCI_RX_STATE_COMPLETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
stateRx = HCI_RX_STATE_DATA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WSF_ASSERT(0); /* allocate falied */
|
||||
return consumed_bytes;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Data State --- */
|
||||
else if (stateRx == HCI_RX_STATE_DATA)
|
||||
{
|
||||
/* write incoming byte to allocated buffer */
|
||||
*pDataRx++ = dataByte;
|
||||
|
||||
/* determine if entire packet has been read */
|
||||
iRx--;
|
||||
if (iRx == 0)
|
||||
{
|
||||
stateRx = HCI_RX_STATE_COMPLETE;
|
||||
}
|
||||
pBuf++;
|
||||
consumed_bytes++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* --- Complete State --- */
|
||||
/* ( Note Well! There is no else-if construct by design. ) */
|
||||
if (stateRx == HCI_RX_STATE_COMPLETE)
|
||||
{
|
||||
g_bHCIReceivingPacket = FALSE;
|
||||
|
||||
/* deliver data */
|
||||
if (pPktRx != NULL)
|
||||
{
|
||||
//am_hal_gpio_out_bit_set(13);
|
||||
hciCoreRecv(pktIndRx, pPktRx);
|
||||
//am_hal_gpio_out_bit_clear(13);
|
||||
}
|
||||
|
||||
/* reset state machine */
|
||||
stateRx = HCI_RX_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
return consumed_bytes;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Check to see if the state machine has received part of a packet.
|
||||
//!
|
||||
//! This function checks the HCI packet-receive state machine to see if it is
|
||||
//! in the middle of receiving a packet. This information can be useful in
|
||||
//! determining whether the serial interface should remain enabled.
|
||||
//!
|
||||
//! @return TRUE if there is a packet in progress.
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool_t
|
||||
hciTrReceivingPacket(void)
|
||||
{
|
||||
return g_bHCIReceivingPacket;
|
||||
}
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_tr_apollo.h
|
||||
//!
|
||||
//! @brief Additional header information for the Apollo implementation of HCI.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef HCI_TR_APOLLO_H
|
||||
#define HCI_TR_APOLLO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Function prototypes.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern bool_t hciTrReceivingPacket(void);
|
||||
extern uint16_t hciTrSerialRxIncoming(uint8_t *pBuf, uint16_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // HCI_TR_APOLLO_H
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_vs.c
|
||||
*
|
||||
* \brief HCI vendor specific functions for generic controllers.
|
||||
*
|
||||
* $Date: 2017-02-28 11:31:38 -0600 (Tue, 28 Feb 2017) $
|
||||
* $Revision: 11299 $
|
||||
*
|
||||
* Copyright (c) 2011-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "bda.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_apollo_config.h"
|
||||
#include "am_mcu_apollo.h"
|
||||
|
||||
#if HCI_VS_TARGET == HCI_VS_GENERIC
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void hciCoreReadResolvingListSize(void);
|
||||
static void hciCoreReadMaxDataLen(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreReadResolvingListSize
|
||||
*
|
||||
* \brief Read resolving list command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadResolvingListSize(void)
|
||||
{
|
||||
/* if LL Privacy is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_PRIVACY) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_PRIVACY))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadResolvingListSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.resListSize = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadMaxDataLen();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreReadMaxDataLen
|
||||
*
|
||||
* \brief Read maximum data length command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadMaxDataLen(void)
|
||||
{
|
||||
/* if LE Data Packet Length Extensions is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_DATA_LEN_EXT) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_DATA_LEN_EXT))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadMaxDataLen();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreResetStart
|
||||
*
|
||||
* \brief Start the HCI reset sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreResetStart(void)
|
||||
{
|
||||
/* send an HCI Reset command to start the sequence */
|
||||
HciResetCmd();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreResetSequence
|
||||
*
|
||||
* \brief Implement the HCI reset sequence.
|
||||
*
|
||||
* \param pMsg HCI event message from previous command in the sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreResetSequence(uint8_t *pMsg)
|
||||
{
|
||||
uint16_t opcode;
|
||||
wsfMsgHdr_t hdr;
|
||||
static uint8_t randCnt;
|
||||
|
||||
/* if event is a command complete event */
|
||||
if (*pMsg == HCI_CMD_CMPL_EVT)
|
||||
{
|
||||
/* parse parameters */
|
||||
pMsg += HCI_EVT_HDR_LEN;
|
||||
pMsg++; /* skip num packets */
|
||||
BSTREAM_TO_UINT16(opcode, pMsg);
|
||||
pMsg++; /* skip status */
|
||||
|
||||
/* decode opcode */
|
||||
switch (opcode)
|
||||
{
|
||||
case HCI_OPCODE_RESET:
|
||||
/* initialize rand command count */
|
||||
randCnt = 0;
|
||||
|
||||
#ifdef AM_BSP_GPIO_EM9304_RESET
|
||||
// set the BD address after HCI reset for EM device
|
||||
extern void HciVsEM_SetBDAddress(void);
|
||||
|
||||
HciVsEM_SetBDAddress();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AM_BSP_NATIONZ_IOM
|
||||
extern uint8_t g_BLEMacAddress[6];
|
||||
HciVendorSpecificCmd(0xFC32, 6, g_BLEMacAddress);
|
||||
#endif
|
||||
|
||||
/* send next command in sequence */
|
||||
HciSetEventMaskCmd((uint8_t *) hciEventMask);
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_SET_EVENT_MASK:
|
||||
/* send next command in sequence */
|
||||
HciLeSetEventMaskCmd((uint8_t *) hciLeEventMask);
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_SET_EVENT_MASK:
|
||||
/* send next command in sequence */
|
||||
HciSetEventMaskPage2Cmd((uint8_t *) hciEventMaskPage2);
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_SET_EVENT_MASK_PAGE2:
|
||||
/* send next command in sequence */
|
||||
HciReadBdAddrCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_READ_BD_ADDR:
|
||||
/* parse and store event parameters */
|
||||
BdaCpy(hciCoreCb.bdAddr, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadBufSizeCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_BUF_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT16(hciCoreCb.bufSize, pMsg);
|
||||
BSTREAM_TO_UINT8(hciCoreCb.numBufs, pMsg);
|
||||
|
||||
|
||||
/* initialize ACL buffer accounting */
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
// B0 has less data buffer compared to A1 and A0
|
||||
if (!APOLLO3_GE_B0)
|
||||
{
|
||||
hciCoreCb.numBufs--;
|
||||
}
|
||||
#endif
|
||||
hciCoreCb.availBufs = hciCoreCb.numBufs;
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadSupStatesCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_SUP_STATES:
|
||||
/* parse and store event parameters */
|
||||
memcpy(hciCoreCb.leStates, pMsg, HCI_LE_STATES_LEN);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadWhiteListSizeCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_WHITE_LIST_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.whiteListSize, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadLocalSupFeatCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_LOCAL_SUP_FEAT:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT16(hciCoreCb.leSupFeat, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadResolvingListSize();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_RES_LIST_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.resListSize, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadMaxDataLen();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_MAX_DATA_LEN:
|
||||
{
|
||||
uint16_t maxTxOctets;
|
||||
uint16_t maxTxTime;
|
||||
|
||||
BSTREAM_TO_UINT16(maxTxOctets, pMsg);
|
||||
BSTREAM_TO_UINT16(maxTxTime, pMsg);
|
||||
|
||||
/* use Controller's maximum supported payload octets and packet duration times
|
||||
* for transmission as Host's suggested values for maximum transmission number
|
||||
* of payload octets and maximum packet transmission time for new connections.
|
||||
*/
|
||||
HciLeWriteDefDataLen(maxTxOctets, maxTxTime);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_WRITE_DEF_DATA_LEN:
|
||||
if (hciCoreCb.extResetSeq)
|
||||
{
|
||||
/* send first extended command */
|
||||
(*hciCoreCb.extResetSeq)(pMsg, opcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* initialize extended parameters */
|
||||
hciCoreCb.maxAdvDataLen = 0;
|
||||
hciCoreCb.numSupAdvSets = 0;
|
||||
hciCoreCb.perAdvListSize = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN:
|
||||
case HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS:
|
||||
case HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE:
|
||||
if (hciCoreCb.extResetSeq)
|
||||
{
|
||||
/* send next extended command in sequence */
|
||||
(*hciCoreCb.extResetSeq)(pMsg, opcode);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_RAND:
|
||||
/* check if need to send second rand command */
|
||||
if (randCnt < (HCI_RESET_RAND_CNT-1))
|
||||
{
|
||||
randCnt++;
|
||||
HciLeRandCmd();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* last command in sequence; set resetting state and call callback */
|
||||
hciCb.resetting = FALSE;
|
||||
hdr.param = 0;
|
||||
hdr.event = HCI_RESET_SEQ_CMPL_CBACK_EVT;
|
||||
(*hciCb.evtCback)((hciEvt_t *) &hdr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreVsCmdCmplRcvd
|
||||
*
|
||||
* \brief Perform internal HCI processing of vendor specific command complete events.
|
||||
*
|
||||
* \param opcode HCI command opcode.
|
||||
* \param pMsg Pointer to input HCI event parameter byte stream.
|
||||
* \param len Parameter byte stream length.
|
||||
*
|
||||
* \return HCI callback event code or zero.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t hciCoreVsCmdCmplRcvd(uint16_t opcode, uint8_t *pMsg, uint8_t len)
|
||||
{
|
||||
return HCI_VENDOR_SPEC_CMD_CMPL_CBACK_EVT;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreVsEvtRcvd
|
||||
*
|
||||
* \brief Perform internal HCI processing of vendor specific HCI events.
|
||||
*
|
||||
* \param p Pointer to input HCI event parameter byte stream.
|
||||
* \param len Parameter byte stream length.
|
||||
*
|
||||
* \return HCI callback event code or zero.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t hciCoreVsEvtRcvd(uint8_t *p, uint8_t len)
|
||||
{
|
||||
return HCI_VENDOR_SPEC_EVT;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreHwErrorRcvd
|
||||
*
|
||||
* \brief Perform internal HCI processing of hardware error event.
|
||||
*
|
||||
* \param p Pointer to input HCI event parameter byte stream.
|
||||
*
|
||||
* \return HCI callback event code or zero.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t hciCoreHwErrorRcvd(uint8_t *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsInit
|
||||
*
|
||||
* \brief Vendor-specific controller initialization function.
|
||||
*
|
||||
* \param param Vendor-specific parameter.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsInit(uint8_t param)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
Vendored
+174
@@ -0,0 +1,174 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI vendor specific AE functions for generic controllers.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_core.h"
|
||||
|
||||
#if HCI_VS_TARGET == HCI_VS_GENERIC
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void hciCoreReadMaxAdvDataLen(void);
|
||||
static void hciCoreReadNumSupAdvSets(void);
|
||||
static void hciCoreReadPerAdvListSize(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read maximum advertising data length command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadMaxAdvDataLen(void)
|
||||
{
|
||||
/* if LE Extended Advertising is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_LE_EXT_ADV) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_LE_EXT_ADV))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadMaxAdvDataLen();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.maxAdvDataLen = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadNumSupAdvSets();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read read number of supported advertising sets command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadNumSupAdvSets(void)
|
||||
{
|
||||
/* if LE Extended Advertising is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_LE_EXT_ADV) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_LE_EXT_ADV))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadNumSupAdvSets();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.numSupAdvSets = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadPerAdvListSize();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read periodic advertiser list size command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadPerAdvListSize(void)
|
||||
{
|
||||
/* if LE Extended Advertising is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_LE_PER_ADV) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_LE_PER_ADV))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadPerAdvListSizeCmd();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.perAdvListSize = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Implement the HCI extended reset sequence.
|
||||
*
|
||||
* \param pMsg HCI event message from previous command in the sequence.
|
||||
* \param opcode HCI event message opcode.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreExtResetSequence(uint8_t *pMsg, uint16_t opcode)
|
||||
{
|
||||
/* decode opcode */
|
||||
switch (opcode)
|
||||
{
|
||||
case HCI_OPCODE_READ_LOCAL_VER_INFO:
|
||||
/* send next command in sequence */
|
||||
hciCoreReadMaxAdvDataLen();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN:
|
||||
BSTREAM_TO_UINT16(hciCoreCb.maxAdvDataLen, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadNumSupAdvSets();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.numSupAdvSets, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadPerAdvListSize();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.perAdvListSize, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Vendor-specific controller AE initialization function.
|
||||
*
|
||||
* \param param Vendor-specific parameter.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsAeInit(uint8_t param)
|
||||
{
|
||||
hciCoreCb.extResetSeq = hciCoreExtResetSequence;
|
||||
}
|
||||
|
||||
#endif
|
||||
Vendored
+838
@@ -0,0 +1,838 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief HCI core module, platform independent functions.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This module implements core platform independent HCI features for transmit data path,
|
||||
* fragmentation, reassembly, and connection management.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "util/bda.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
#include "l2c_defs.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Default ACL buffer flow control watermark levels */
|
||||
#ifndef HCI_ACL_QUEUE_HI
|
||||
#define HCI_ACL_QUEUE_HI 5 /* Disable flow when this many buffers queued */
|
||||
#endif
|
||||
#ifndef HCI_ACL_QUEUE_LO
|
||||
#define HCI_ACL_QUEUE_LO 1 /* Enable flow when this many buffers queued */
|
||||
#endif
|
||||
|
||||
/* Default maximum ACL packet size for reassembly */
|
||||
#ifndef HCI_MAX_RX_ACL_LEN
|
||||
#define HCI_MAX_RX_ACL_LEN HCI_ACL_DEFAULT_LEN
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Event mask */
|
||||
const uint8_t hciEventMask[HCI_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_DISCONNECT_CMPL | /* Byte 0 */
|
||||
HCI_EVT_MASK_ENC_CHANGE, /* Byte 0 */
|
||||
HCI_EVT_MASK_READ_REMOTE_VER_INFO_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_HW_ERROR, /* Byte 1 */
|
||||
0, /* Byte 2 */
|
||||
HCI_EVT_MASK_DATA_BUF_OVERFLOW, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
HCI_EVT_MASK_ENC_KEY_REFRESH_CMPL, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
HCI_EVT_MASK_LE_META /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE event mask */
|
||||
const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_LE_CONN_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_ADV_REPORT_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_CONN_UPDATE_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_REMOTE_FEAT_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_LTK_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_REMOTE_CONN_PARAM_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_DATA_LEN_CHANGE_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_LOCAL_P256_PUB_KEY_CMPL, /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_GENERATE_DHKEY_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_ENHANCED_CONN_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_DIRECT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PHY_UPDATE_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_EXT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_EST_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_LOST_EVT, /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_SCAN_TIMEOUT_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_ADV_SET_TERM_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_SCAN_REQ_RCVD_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CH_SEL_ALGO_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CONN_IQ_REPORT_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CTE_REQ_FAILED_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_PER_SYNC_TRSF_RCVT_EVT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* event mask page 2 */
|
||||
const uint8_t hciEventMaskPage2[HCI_EVT_MASK_PAGE_2_LEN] =
|
||||
{
|
||||
0, /* Byte 0 */
|
||||
0, /* Byte 1 */
|
||||
HCI_EVT_MASK_AUTH_PAYLOAD_TIMEOUT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE supported features configuration mask */
|
||||
uint32_t hciLeSupFeatCfg =
|
||||
HCI_LE_SUP_FEAT_ENCRYPTION | /* LE Encryption */
|
||||
HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC | /* Connection Parameters Request Procedure */
|
||||
HCI_LE_SUP_FEAT_EXT_REJECT_IND | /* Extended Reject Indication */
|
||||
HCI_LE_SUP_FEAT_SLV_INIT_FEAT_EXCH | /* Slave-initiated Features Exchange */
|
||||
HCI_LE_SUP_FEAT_LE_PING | /* LE Ping */
|
||||
HCI_LE_SUP_FEAT_DATA_LEN_EXT | /* LE Data Packet Length Extension */
|
||||
HCI_LE_SUP_FEAT_PRIVACY | /* LL Privacy */
|
||||
HCI_LE_SUP_FEAT_EXT_SCAN_FILT_POLICY | /* Extended Scanner Filter Policies */
|
||||
HCI_LE_SUP_FEAT_LE_2M_PHY | /* LE 2M PHY supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_TRANSMITTER | /* Stable Modulation Index - Transmitter supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_RECEIVER | /* Stable Modulation Index - Receiver supported */
|
||||
HCI_LE_SUP_FEAT_LE_EXT_ADV | /* LE Extended Advertising */
|
||||
HCI_LE_SUP_FEAT_LE_PER_ADV; /* LE Periodic Advertising */
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
hciCoreCb_t hciCoreCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnAlloc(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == HCI_HANDLE_NONE)
|
||||
{
|
||||
/* allocate and initialize */
|
||||
pConn->handle = handle;
|
||||
pConn->flowDisabled = FALSE;
|
||||
pConn->outBufs = 0;
|
||||
pConn->queuedBufs = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN0("HCI conn struct alloc failure");
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnFree(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
/* free any fragmenting ACL packet */
|
||||
if (pConn->pTxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
}
|
||||
pConn->fragmenting = FALSE;
|
||||
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
|
||||
/* free structure */
|
||||
pConn->handle = HCI_HANDLE_NONE;
|
||||
|
||||
/* optional: iterate through tx ACL queue and free any buffers with this handle */
|
||||
|
||||
/* outstanding buffers are now available; service TX data path */
|
||||
hciCoreTxReady(pConn->outBufs);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreConnFree handle not found:%u", handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get a connection structure by handle
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next connection structure with a packet fragment to send.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static hciCoreConn_t *hciCoreNextConnFragment(void)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle != HCI_HANDLE_NONE && pConn->fragmenting)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform internal processing on HCI connection open.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnOpen(uint16_t handle)
|
||||
{
|
||||
/* allocate connection structure */
|
||||
hciCoreConnAlloc(handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform internal processing on HCI connection close.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnClose(uint16_t handle)
|
||||
{
|
||||
/* free connection structure */
|
||||
hciCoreConnFree(handle);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL data to transport.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* increment outstanding buf count for handle */
|
||||
pConn->outBufs++;
|
||||
|
||||
/* send to transport */
|
||||
hciTrSendAclData(pConn, pData);
|
||||
|
||||
/* decrement available buffer count */
|
||||
if (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs--;
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN0("hciCoreSendAclData availBufs=0");
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Service the TX data path.
|
||||
*
|
||||
* \param bufs Number of new buffers now available.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxReady(uint8_t bufs)
|
||||
{
|
||||
uint8_t *pData;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* increment available buffers, with ceiling */
|
||||
if (bufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs += bufs;
|
||||
if (hciCoreCb.availBufs > hciCoreCb.numBufs)
|
||||
{
|
||||
hciCoreCb.availBufs = hciCoreCb.numBufs;
|
||||
}
|
||||
}
|
||||
|
||||
/* service ACL data queue and send as many buffers as we can */
|
||||
while (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send continuation of any fragments first */
|
||||
if (hciCoreTxAclContinue(NULL) == FALSE)
|
||||
{
|
||||
/* if no fragments then check for any queued ACL data */
|
||||
if ((pData = WsfMsgDeq(&hciCoreCb.aclQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up conn structure and send data */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
/* handle not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreTxReady discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragments or queued data to send; we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL packets, start of packet.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param len ACL packet length.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData)
|
||||
{
|
||||
uint16_t hciLen;
|
||||
|
||||
/* make sure not already fragmenting on this connection */
|
||||
WSF_ASSERT(pConn->fragmenting == FALSE);
|
||||
|
||||
hciLen = HciGetBufSize();
|
||||
|
||||
HCI_TRACE_INFO1("hciCoreTxAclStart len=%u", len);
|
||||
|
||||
/* if acl len > controller acl buf len */
|
||||
if (len > hciLen)
|
||||
{
|
||||
/* store remaining acl len = acl len - hci acl buf len */
|
||||
pConn->txAclRemLen = len - hciLen;
|
||||
|
||||
/* store position for next fragment */
|
||||
pConn->pNextTxFrag = pData + hciLen;
|
||||
|
||||
/* store information required for fragmentation */
|
||||
pConn->pTxAclPkt = pData;
|
||||
pConn->fragmenting = TRUE;
|
||||
|
||||
/* set acl len in packet to hci acl buf len */
|
||||
UINT16_TO_BUF(&pData[2], hciLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
|
||||
/* send additional fragments while there are HCI buffers available */
|
||||
while ((hciCoreCb.availBufs > 0) && hciCoreTxAclContinue(pConn));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragmentation, just send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL packets, continuation of fragmented packets.
|
||||
*
|
||||
* \param pConn Pointer to connection structure. If set non-NULL, then a fragment is
|
||||
* sent from this connection structure. If NULL the function finds the next
|
||||
* connection structure with a fragment to be sent.
|
||||
*
|
||||
* \return TRUE if packet sent, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn)
|
||||
{
|
||||
uint16_t aclLen;
|
||||
|
||||
if (pConn == NULL)
|
||||
{
|
||||
pConn = hciCoreNextConnFragment();
|
||||
}
|
||||
|
||||
if (pConn != NULL)
|
||||
{
|
||||
/* get next fragment length */
|
||||
aclLen = (pConn->txAclRemLen < HciGetBufSize()) ? pConn->txAclRemLen : HciGetBufSize();
|
||||
|
||||
if (aclLen > 0)
|
||||
{
|
||||
/* decrement remaining length */
|
||||
pConn->txAclRemLen -= aclLen;
|
||||
|
||||
/* set handle in packet with continuation bit set */
|
||||
UINT16_TO_BUF(pConn->pNextTxFrag, (pConn->handle | HCI_PB_CONTINUE));
|
||||
|
||||
/* set acl len in packet */
|
||||
UINT16_TO_BUF(&(pConn->pNextTxFrag[2]), aclLen);
|
||||
|
||||
HCI_TRACE_INFO2("hciCoreTxAclContinue aclLen=%u remLen=%u", aclLen, pConn->txAclRemLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pConn->pNextTxFrag);
|
||||
|
||||
/* set up pointer to next fragment */
|
||||
if (pConn->txAclRemLen > 0)
|
||||
{
|
||||
pConn->pNextTxFrag += aclLen;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called from the HCI transport layer when transmission of an ACL
|
||||
* packet is complete.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* if fragmenting */
|
||||
if (pConn->fragmenting)
|
||||
{
|
||||
/* check if all fragments sent */
|
||||
if (pConn->txAclRemLen == 0)
|
||||
{
|
||||
/* free original buffer */
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
pConn->fragmenting = FALSE;
|
||||
HCI_TRACE_INFO0("hciCoreTxAclComplete free pTxAclPkt");
|
||||
}
|
||||
}
|
||||
else if (pData != NULL)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reassemble an ACL packet.
|
||||
*
|
||||
* \param pData Input ACL packet.
|
||||
*
|
||||
* \return pointer to ACL packet to send, or NULL if no packet to send.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *hciCoreAclReassembly(uint8_t *pData)
|
||||
{
|
||||
hciCoreConn_t *pConn;
|
||||
uint8_t *pDataRtn = NULL;
|
||||
uint16_t handle;
|
||||
uint16_t aclLen;
|
||||
uint16_t l2cLen;
|
||||
uint16_t pbf;
|
||||
bool_t freeData = TRUE;
|
||||
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
pbf = handle & HCI_PB_FLAG_MASK;
|
||||
handle &= HCI_HANDLE_MASK;
|
||||
BYTES_TO_UINT16(aclLen, &pData[2]);
|
||||
|
||||
/* look up connection */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if this is a start packet */
|
||||
if (pbf == HCI_PB_START_C2H)
|
||||
{
|
||||
/* if currently reassembled packet not complete */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
/* discard currently reassembled packet */
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
HCI_TRACE_WARN1("disarded hci rx pkt handle=0x%04x", handle);
|
||||
}
|
||||
|
||||
/* read l2cap length */
|
||||
if (aclLen >= L2C_HDR_LEN)
|
||||
{
|
||||
BYTES_TO_UINT16(l2cLen, &pData[4]);
|
||||
|
||||
/* check length vs. configured maximum */
|
||||
if ((l2cLen + L2C_HDR_LEN) > hciCoreCb.maxRxAclLen)
|
||||
{
|
||||
HCI_TRACE_WARN1("l2c len=0x%04x to large for reassembly", l2cLen);
|
||||
}
|
||||
/* if reassembly required */
|
||||
else if ((l2cLen + L2C_HDR_LEN) > aclLen)
|
||||
{
|
||||
/* allocate buffer to store complete l2cap packet */
|
||||
if ((pConn->pRxAclPkt = WsfMsgDataAlloc(l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN, 0)) != NULL)
|
||||
{
|
||||
/* store buffer for reassembly */
|
||||
pConn->pNextRxFrag = pConn->pRxAclPkt;
|
||||
|
||||
/* build acl header and copy data */
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, handle);
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, l2cLen + L2C_HDR_LEN);
|
||||
memcpy(pConn->pNextRxFrag, &pData[4], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* store remaining length */
|
||||
pConn->rxAclRemLen = l2cLen + L2C_HDR_LEN - aclLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* alloc failed; discard */
|
||||
HCI_TRACE_WARN1("reassembly alloc failed len=%u", (l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no reassembly required, pData is ready to go */
|
||||
pDataRtn = pData;
|
||||
freeData = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid l2cap packet; discard */
|
||||
HCI_TRACE_WARN1("invalid l2c pkt aclLen=%u", aclLen);
|
||||
}
|
||||
}
|
||||
/* else if this is a continuation packet */
|
||||
else if (pbf == HCI_PB_CONTINUE)
|
||||
{
|
||||
/* if expecting a continuation */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
if (aclLen <= pConn->rxAclRemLen)
|
||||
{
|
||||
/* copy data to start of next fragment */
|
||||
memcpy(pConn->pNextRxFrag, &pData[HCI_ACL_HDR_LEN], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* update remaining length */
|
||||
pConn->rxAclRemLen -= aclLen;
|
||||
|
||||
/* if reassembly complete return reassembled packet */
|
||||
if (pConn->rxAclRemLen == 0)
|
||||
{
|
||||
pDataRtn = pConn->pRxAclPkt;
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN2("continuation pkt too long len=%u RemLen=%u", aclLen, pConn->rxAclRemLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unexpected continuation pkt handle=0x%04x", handle);
|
||||
}
|
||||
}
|
||||
/* else unknown packet type */
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unknown pb flags=0x%04x", pbf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* connection not found */
|
||||
HCI_TRACE_WARN1("pkt rcvd on unknown handle=0x%04x", (handle & HCI_HANDLE_MASK));
|
||||
}
|
||||
|
||||
if (freeData)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
|
||||
return pDataRtn;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if a TX ACL packet is being fragmented.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
*
|
||||
* \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn)
|
||||
{
|
||||
return pConn->fragmenting;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI core initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciCoreInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
WSF_QUEUE_INIT(&hciCoreCb.aclQueue);
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
hciCoreCb.conn[i].handle = HCI_HANDLE_NONE;
|
||||
}
|
||||
|
||||
hciCoreCb.maxRxAclLen = HCI_MAX_RX_ACL_LEN;
|
||||
hciCoreCb.aclQueueHi = HCI_ACL_QUEUE_HI;
|
||||
hciCoreCb.aclQueueLo = HCI_ACL_QUEUE_LO;
|
||||
hciCoreCb.extResetSeq = NULL;
|
||||
|
||||
hciCoreInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an HCI reset sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciResetSequence(void)
|
||||
{
|
||||
/* set resetting state */
|
||||
hciCb.resetting = TRUE;
|
||||
|
||||
/* start the reset sequence */
|
||||
hciCoreResetStart();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the maximum reassembled RX ACL packet length. Minimum value is 27.
|
||||
*
|
||||
* \param len ACL packet length.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetMaxRxAclLen(uint16_t len)
|
||||
{
|
||||
hciCoreCb.maxRxAclLen = len;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set TX ACL queue high and low watermarks.
|
||||
*
|
||||
* \param queueHi Disable flow on a connection when this many ACL buffers are queued.
|
||||
* queueLo Disable flow on a connection when this many ACL buffers are queued.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetAclQueueWatermarks(uint8_t queueHi, uint8_t queueLo)
|
||||
{
|
||||
hciCoreCb.aclQueueHi = queueHi;
|
||||
hciCoreCb.aclQueueLo = queueLo;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set LE supported features configuration mask.
|
||||
*
|
||||
* \param feat Feature bit to set or clear
|
||||
* \param flag TRUE to set feature bit and FALSE to clear it
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetLeSupFeat(uint32_t feat, bool_t flag)
|
||||
{
|
||||
/* if asked to include feature */
|
||||
if (flag)
|
||||
{
|
||||
/* set feature bit */
|
||||
hciLeSupFeatCfg |= feat;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clear feature bit */
|
||||
hciLeSupFeatCfg &= ~feat;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send data from the stack to HCI.
|
||||
*
|
||||
* \param pData WSF buffer containing an ACL packet
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSendAclData(uint8_t *pData)
|
||||
{
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up connection structure */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if queue empty and buffers available */
|
||||
if (WsfQueueEmpty(&hciCoreCb.aclQueue) && hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send data */
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* queue data - message handler ID 'handerId' not used */
|
||||
WsfMsgEnq(&hciCoreCb.aclQueue, 0, pData);
|
||||
}
|
||||
|
||||
/* increment buffer queue count for this connection with consideration for HCI fragmentation */
|
||||
pConn->queuedBufs += ((len - 1) / HciGetBufSize()) + 1;
|
||||
|
||||
/* manage flow control to stack */
|
||||
if (pConn->queuedBufs >= hciCoreCb.aclQueueHi && pConn->flowDisabled == FALSE)
|
||||
{
|
||||
pConn->flowDisabled = TRUE;
|
||||
(*hciCb.flowCback)(handle, TRUE);
|
||||
}
|
||||
}
|
||||
/* connection not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("HciSendAclData discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_tr.c
|
||||
*
|
||||
* \brief HCI transport module.
|
||||
*
|
||||
* Copyright (c) 2011-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "ll_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciTrSendAclData
|
||||
*
|
||||
* \brief Send a complete HCI ACL packet to the transport.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
* \param pData WSF msg buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendAclData(void *pContext, uint8_t *pData)
|
||||
{
|
||||
uint16_t len;
|
||||
uint8_t *p;
|
||||
|
||||
/* if fragmenting */
|
||||
if (hciCoreTxAclDataFragmented(pContext))
|
||||
{
|
||||
/* get 16-bit length */
|
||||
BYTES_TO_UINT16(len, (pData + 2))
|
||||
len += HCI_ACL_HDR_LEN;
|
||||
|
||||
/* allocate LL buffer */
|
||||
if ((p = WsfMsgDataAlloc(len, HCI_TX_DATA_TAILROOM)) != NULL)
|
||||
{
|
||||
/* copy data */
|
||||
memcpy(p, pData, len);
|
||||
|
||||
/* send to LL */
|
||||
LlSendAclData(p);
|
||||
|
||||
/* free HCI buffer */
|
||||
hciCoreTxAclComplete(pContext, pData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send to LL */
|
||||
LlSendAclData(pData);
|
||||
|
||||
/* LL will free HCI buffer */
|
||||
hciCoreTxAclComplete(pContext, NULL);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user