diff --git a/features/FEATURE_BLE/targets/TARGET_CYW4343X/HCIDriver.cpp b/features/FEATURE_BLE/targets/TARGET_CYW4343X/HCIDriver.cpp new file mode 100644 index 0000000000..532594e3fb --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CYW4343X/HCIDriver.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2018 ARM Limited + * + * 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 +#include "CordioBLE.h" +#include "CordioHCIDriver.h" +#include "hci_api.h" +#include "hci_cmd.h" +#include "hci_core.h" +#include "bstream.h" +#include +#include "hci_mbed_os_adaptation.h" +#include "H4TransportDriver.h" + +extern const int brcm_patch_ram_length; +extern const uint8_t brcm_patchram_buf[]; + +static const uint8_t pre_brcm_patchram_buf[] = { + // RESET followed by download mini driver cmd + 0x03, 0x0C, 0x00, + 0x2E, 0xFC, 0x00, +}; +static const int pre_brcm_patch_ram_length = sizeof(pre_brcm_patchram_buf); + +#define HCI_RESET_RAND_CNT 4 +#define HCI_VS_CMD_SET_SLEEP_MODE 0xFC27 + + +extern "C" uint32_t Set_GPIO_Clock(uint32_t port_idx); + +// 0: push pull +// 1: open drain +static void output_mode(PinName pin, int mode) +{ + MBED_ASSERT(pin != (PinName)NC); + uint32_t port_index = STM_PORT(pin); + uint32_t pin_index = STM_PIN(pin); + + // Enable GPIO clock + uint32_t gpio_add = Set_GPIO_Clock(port_index); + GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add; + + + /* Output mode configuration*/ + gpio->OTYPER &= ~((GPIO_OTYPER_OT_0) << ((uint16_t)pin_index)) ; + gpio->OTYPER |= (uint16_t)(((uint16_t)mode) << ((uint16_t)pin_index)); +} + +namespace ble { +namespace vendor { +namespace wise1530 { + +class HCIDriver : public cordio::CordioHCIDriver { +public: + HCIDriver( + cordio::CordioHCITransportDriver& transport_driver, + PinName bt_host_wake_name, + PinName bt_device_wake_name, + PinName bt_power_name + ) : cordio::CordioHCIDriver(transport_driver), + bt_host_wake_name(bt_host_wake_name), + bt_device_wake_name(bt_device_wake_name), + bt_power_name(bt_power_name), + bt_host_wake(bt_host_wake_name, PIN_INPUT, PullNone, 0), + bt_device_wake(bt_device_wake_name, PIN_OUTPUT, PullDefault, 1), + bt_power(bt_power_name, PIN_OUTPUT, PullUp, 0), + service_pack_index(0), + service_pack_ptr(0), + service_pack_length(0), + service_pack_next(), + service_pack_transfered(false) { + } + + virtual void do_initialize() + { + output_mode(bt_host_wake_name, 1); + output_mode(bt_device_wake_name, 0); + output_mode(bt_power_name, 1); + + wait_ms(500); + + bt_device_wake = 0; + wait_ms(500); + + bt_power = 1; + wait_ms(500); + } + + virtual void do_terminate() { } + + virtual void start_reset_sequence() + { + prepare_service_pack_transfert(); + } + + virtual void handle_reset_sequence(uint8_t *pMsg) + { + uint16_t opcode; + 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 */ + + if (service_pack_transfered == false) { + randCnt = 0; + ack_service_pack_command(opcode, pMsg); + return; + } + + /* decode opcode */ + switch (opcode) { + // Note: Reset is handled by ack_service_pack. + case HCI_VS_CMD_SET_SLEEP_MODE: + HciWriteLeHostSupport(); + break; + + case HCI_OPCODE_WRITE_LE_HOST_SUPPORT: + randCnt = 0; + /* send next command in sequence */ + HciSetEventMaskCmd((uint8_t *) hciEventMask); + break; + + case HCI_OPCODE_SET_EVENT_MASK: + randCnt = 0; + /* 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); + 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); + + // FixMe: The number of ACL buffer returned by the chip is + // incorrect. If more than two ACL packets are present in + // the controller, it may block the controller. + // Important: The ACL overflow event is **not** reported + // by the controller. + hciCoreCb.numBufs = 2; + + /* initialize ACL buffer accounting */ + 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 { + uint8_t addr[6] = { 0 }; + memcpy(addr, pMsg, sizeof(addr)); + DM_RAND_ADDR_SET(addr, DM_RAND_ADDR_STATIC); + // note: will invoke set rand address + cordio::BLE::deviceInstance().getGap().setAddress( + BLEProtocol::AddressType::RANDOM_STATIC, + addr + ); + } + break; + + case HCI_OPCODE_LE_SET_RAND_ADDR: + /* send next command in sequence */ + signal_reset_sequence_done(); + break; + + default: + break; + } + } + } + +private: + + // send pre_brcm_patchram_buf + void prepare_service_pack_transfert(void) + { + service_pack_ptr = pre_brcm_patchram_buf; + service_pack_length = pre_brcm_patch_ram_length; + service_pack_next = &HCIDriver::start_service_pack_transfert; + service_pack_index = 0; + service_pack_transfered = false; + send_service_pack_command(); + } + + // Called once pre_brcm_patchram_buf has been transferred; send brcm_patchram_buf + void start_service_pack_transfert(void) + { + service_pack_ptr = brcm_patchram_buf; + service_pack_length = brcm_patch_ram_length; + service_pack_next = &HCIDriver::terminate_service_pack_transfert; + service_pack_index = 0; + service_pack_transfered = false; + send_service_pack_command(); + } + + // Called once post_brcm_patchram_buf has been transferred; start regular initialization. + void terminate_service_pack_transfert(void) + { + service_pack_ptr = NULL; + service_pack_length = 0; + service_pack_next = NULL; + service_pack_index = 0; + service_pack_transfered = true; + wait_ms(1000); + set_sleep_mode(); + } + + void send_service_pack_command(void) + { + uint16_t cmd_len = service_pack_ptr[service_pack_index + 2]; + uint16_t cmd_opcode = (service_pack_ptr[service_pack_index + 1] << 8) | service_pack_ptr[service_pack_index + 0]; + uint8_t *pBuf = hciCmdAlloc(cmd_opcode, cmd_len); + if (pBuf) { + memcpy(pBuf + HCI_CMD_HDR_LEN, service_pack_ptr + service_pack_index + HCI_CMD_HDR_LEN, cmd_len); + hciCmdSend(pBuf); + } else { + } + } + + void ack_service_pack_command(uint16_t opcode, uint8_t* msg) + { + uint16_t cmd_opcode = (service_pack_ptr[service_pack_index + 1] << 8) | service_pack_ptr[service_pack_index + 0]; + + if (cmd_opcode != opcode) { + // DO something in case of error + + while (true); + + } + + // update service pack index + service_pack_index += (HCI_CMD_HDR_LEN + service_pack_ptr[service_pack_index + 2]); + + if (service_pack_index < service_pack_length) { + send_service_pack_command(); + } else { + (this->*service_pack_next)(); + } + } + + void set_sleep_mode() + { + uint8_t *pBuf; + if ((pBuf = hciCmdAlloc(HCI_VS_CMD_SET_SLEEP_MODE, 12)) != NULL) + { + pBuf[HCI_CMD_HDR_LEN] = 0x00; // no sleep moode + pBuf[HCI_CMD_HDR_LEN + 1] = 0x00; // no idle threshold host (N/A) + pBuf[HCI_CMD_HDR_LEN + 2] = 0x00; // no idle threshold HC (N/A) + pBuf[HCI_CMD_HDR_LEN + 3] = 0x00; // BT WAKE + pBuf[HCI_CMD_HDR_LEN + 4] = 0x00; // HOST WAKE + pBuf[HCI_CMD_HDR_LEN + 5] = 0x00; // Sleep during SCO + pBuf[HCI_CMD_HDR_LEN + 6] = 0x00; // Combining sleep mode and SCM + pBuf[HCI_CMD_HDR_LEN + 7] = 0x00; // Tristate TX + pBuf[HCI_CMD_HDR_LEN + 8] = 0x00; // Active connection handling on suspend + pBuf[HCI_CMD_HDR_LEN + 9] = 0x00; // resume timeout + pBuf[HCI_CMD_HDR_LEN + 10] = 0x00; // break to host + pBuf[HCI_CMD_HDR_LEN + 10] = 0x00; // Pulsed host wake + hciCmdSend(pBuf); + } + } + + static const uint16_t HCI_OPCODE_WRITE_LE_HOST_SUPPORT = 0x0C6D; + + void HciWriteLeHostSupport() + { + uint8_t *pBuf; + if ((pBuf = hciCmdAlloc(HCI_OPCODE_WRITE_LE_HOST_SUPPORT, 2)) != NULL) + { + pBuf[HCI_CMD_HDR_LEN] = 0x01; + pBuf[HCI_CMD_HDR_LEN + 1] = 0x00; + hciCmdSend(pBuf); + } + } + + 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(); + } + } + + 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(); + } + } + + PinName bt_host_wake_name; + PinName bt_device_wake_name; + PinName bt_power_name; + DigitalInOut bt_host_wake; + DigitalInOut bt_device_wake; + DigitalInOut bt_power; + size_t service_pack_index; + const uint8_t* service_pack_ptr; + int service_pack_length; + void (HCIDriver::*service_pack_next)(); + bool service_pack_transfered; + +}; + +} // namespace wise1530 +} // namespace vendor +} // namespace ble + +ble::vendor::cordio::CordioHCIDriver& ble_cordio_get_hci_driver() { + static ble::vendor::cordio::H4TransportDriver transport_driver( + /* TX */ PA_2, /* RX */ PA_3, /* cts */ PA_0, /* rts */ PA_1, 115200 + ); + static ble::vendor::wise1530::HCIDriver hci_driver( + transport_driver, /* host wake */ PC_0, /* device wake */ PB_8, /* bt_power */ PC_6 + ); + return hci_driver; +} diff --git a/targets/TARGET_WICED/TOOLCHAIN_ARM/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.ar b/targets/TARGET_WICED/TOOLCHAIN_ARM/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.ar new file mode 100644 index 0000000000..6831273943 Binary files /dev/null and b/targets/TARGET_WICED/TOOLCHAIN_ARM/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.ar differ diff --git a/targets/TARGET_WICED/TOOLCHAIN_ARM/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.ar b/targets/TARGET_WICED/TOOLCHAIN_ARM/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.ar new file mode 100644 index 0000000000..84459b2a3d Binary files /dev/null and b/targets/TARGET_WICED/TOOLCHAIN_ARM/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.ar differ diff --git a/targets/TARGET_WICED/TOOLCHAIN_GCC_ARM/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.a b/targets/TARGET_WICED/TOOLCHAIN_GCC_ARM/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.a new file mode 100644 index 0000000000..87bb811805 Binary files /dev/null and b/targets/TARGET_WICED/TOOLCHAIN_GCC_ARM/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.a differ diff --git a/targets/TARGET_WICED/TOOLCHAIN_GCC_ARM/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.a b/targets/TARGET_WICED/TOOLCHAIN_GCC_ARM/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.a new file mode 100644 index 0000000000..14f43b9805 Binary files /dev/null and b/targets/TARGET_WICED/TOOLCHAIN_GCC_ARM/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.a differ diff --git a/targets/TARGET_WICED/TOOLCHAIN_IAR/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.a b/targets/TARGET_WICED/TOOLCHAIN_IAR/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.a new file mode 100644 index 0000000000..82cb391041 Binary files /dev/null and b/targets/TARGET_WICED/TOOLCHAIN_IAR/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.a differ diff --git a/targets/TARGET_WICED/TOOLCHAIN_IAR/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.a b/targets/TARGET_WICED/TOOLCHAIN_IAR/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.a new file mode 100644 index 0000000000..261091deae Binary files /dev/null and b/targets/TARGET_WICED/TOOLCHAIN_IAR/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.a differ diff --git a/targets/targets.json b/targets/targets.json index 2976298d90..a3a1e6e53c 100755 --- a/targets/targets.json +++ b/targets/targets.json @@ -1174,12 +1174,14 @@ "USI_WM_BN_BM_22": { "inherits": ["FAMILY_STM32"], "core": "Cortex-M4F", - "extra_labels_add": ["STM32F4", "STM32F412xG", "STM32F412ZG"], + "extra_labels_add": ["STM32F4", "STM32F412xG", "STM32F412ZG", "WICED", "CYW4343X", "CORDIO"], + "features": ["LWIP", "BLE"], "macros_add": ["USB_STM_HAL", "USBHOST_OTHER"], - "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "TRNG", "FLASH"], + "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "TRNG", "FLASH", "EMAC"], "release_versions": ["2", "5"], "device_name": "STM32F412ZG", "bootloader_supported": true, + "public": false, "config": { "clock_source": { "help": "Mask value : USE_PLL_HSE_EXTC | USE_PLL_HSE_XTAL (need HW patch) | USE_PLL_HSI",