002f7d1ad7
Summarized this squashed PR replaces the hal/ folder in the port. This has been replaced the official HAL layer from Nordic Semiconductor; https://github.com/NordicSemiconductor/nrfx. A Git submodule has been added under lib/nrfx, for the nrfx dependency. The drivers / modules has been updated to use this new HAL layer; nrfx at v1.0.0. Also, header files and system files for nrf51/nrf52x chip variants has been deleted from the device/ folder, only keeping back the startup files written in C. All other files are now fetched from nrfx. 3 new header files in the ports/nrf/ folder has been added to configure nrfx (nrfx_config.h), logging (nrfx_log.h) and glue nrfx together with the drivers and modules from micropython (nrfx_glue.h). The PR has been a joint effort from @aykevl (Ayke van Laethem) and @glennrub. For reference, the commit log will be kept to get an overview of the changes done: * ports/nrf: Initial commit for moving hal to Nordic Semiconductor BSD-3 licensed nrfx-hal. * ports/nrf: Adding nrfx, Nordic Semiconductor BSD-3 hal layer, as git submodule checked out at lib/nrfx. * ports/nrf/modules/machine/uart: Fixing bug which set hwfc to parity excluded, always resulting in no flow control, hence corrupted output. Also adding an extra loop on uart_tx_char to prevent any tx when any ongoing tx is in progress. * ports/nrf/i2c: Moving I2C over to nrfx driver. * ports/nrf/modules/machine/i2c: Alignment. Renaming print function param 'o' to 'self_in' * ports/nrf/spi: Updating SPI machine module to use nrfx drivers. * ports/nrf: Renaming modules/machine/rtc.c/.h to rtcounter.c/.h to not confuse the peripheral with Real-Time Clock: * ports/nrf: Updating various files after renaming machine module RTC to RTCounter. * ports/nrf: Renaming RTC to RTCounter in modmachine globals dict table. Also updating object type name to reflect new module name. * ports/nrf: Fixing leftovers after renaming rtc to rtcounter. * ports/nrf: Early untested adoption of nrfx_rtc in RTCounter. Untested. * nrf/modules/machine/i2c: Improve keyword argument handling * ports/nrf/modules/temp: Updating Temp machine module to use nrfx defined hal nrf_temp.h. Moving logic of BLE stack awareness to machine module. * ports/nrf/boards/pca10040: Enable machine Temp module. * nrf/modules/machine/rtcounter: Remove magic constants. * ports/nrf: Adding base support for nrfx module logging. Adding option to disable logging of UART as it might log its own setup over UART while the peripheral is not yet set up. Logging of UART could make sense if other transport of log is used. * ports/nrf: updating nrfx_log.h with more correct parenthisis on macro grouping. * ports/nrf: Updating nrfx logging with configuration to disable logging of UART module. The pattern can be used to turn off other modules as well. However, for now UART is the only module locking itself by logging before the peripheral is configured. Logging is turned off by default, can be enabled in nrfx_config.h by setting NRFX_LOG_ENABLED=1. * ports/nrf/modules/random: Updating modrandom to use nrfx hal for rng. Not using nrfx-driver for this peripheral as its blocking mode would do the trick on RNG. Moving softdevice aware code from legacy hal to modrandom.c. * nrf: Enable Peripheral Resource Sharing. This enables TWI and SPI to be enabled at the same time. * nrf/Makefile: Define MCU sub variant (e.g. NRF51822/NRF51422) * nrf: Port TIMER peripheral to nrfx HAL. * nrf/modules/machine/uart: Optimize UART module For a nRF51, this results in a size reduction of: .text: -68 bytes .data: -56 bytes * nrf/modules/machine/uart: Don't use magic index numbers. * nrf/modules/machine/uart: Fix off-by-one error. For nrf51: .text: -40 bytes * nrf/modules/machine/rtcounter: Update for nrfx HAL. * nrf/modules/machine/i2c: Reduce RAM consumption. Reductions for the nrf51: flash: -108 bytes RAM: -72 bytes * nrf/mpconfigport: Avoid unnecessary root pointers. This saves 92 bytes of RAM. * nrf: Support SoftDevice with nrfx HAL. * nrf: Add NVMC peripheral (microbitfs) support. There is no support yet for a SoftDevice. It also fixes a potentially serious bug in start_index generation. * nrf/modules/machine/spi: Optimize SPI peripheral. nrf51: text: -340 bytes data: -72 bytes nrf52: text: -352 bytes data: -108 bytes * nrf/modules/random: Forgot to commit header file. * nrf: Make nrfx_config.h universal for all boards. * nrf: Use SoftDevice API for flash access when built for SD * nrf/drivers/bluetooth: Remove legacy HAL driver includes. These were not used anymore so can be removed. * ports/nrf/microbit: Port microbit targets to nrfx HAL Initial port of microbit modules to use nrfx HAL layer. Tested display/image and modmusic on micro:bit to verify that softpwm and ticker for nrf51 is working as expected. Changing IRQ priority on timer to priority 2, as 1 might collide if used side by side of SD110 BLE stack. The patch reserves Timer1 peripheral compile time. This is not ideal and should be resolved in seperate task. * nrf/boards/microbit: Remove custom nrfx_config.h from microbit target, adding disablement of timer1 if softpwm is enabled. * nrf/adc: Update ADC module to use nrfx * nrf/modules/machine/pwm: Updating machine PWM module to use nrfx HAL driver. examples/nrf52_pwm.py and examples/nrf52_servo.py tested on pca10040. * nrf: Removing hal folder and boards nrf5x_hal_conf.h headers. * nrf/nrfx_glue: Adding direct NVIC access for S110 BLE stack If SoftDevice s110 has not yet been initialized, the IRQ will not be forwarded to the application using the sd_nvic* function calls. Hence, direct access to cmsi nvic functions are used instead if SoftDevice is not enabled. * nrf/drivers/ticker: Setting IRQ priority 3 on Timer1 SoftDevice fails to initilize if Timer1 has been configured to priority level 2 before enabling the SD. The timer is set to priority 1, higher than BLE stack in order to provide better quality of music rendering when used with the music module. This might be too high, time will show. * nrf/examples: Updating ubluepy_temp after moving RTCounter to nrfx. * nrf: delete duplicate files from device folder which can be located in nrfx/mdk. * nrf/Makefile: Fetch system files from nrfx. Testing on each device sub-variant to figure out which system file to use. Reason for this is that nrf52.c is actually defining nrf52832. Removing NRF_DEFINES parameter setting the device in use into the same sub-variant test, as NRF52 is unique to nrf52832 when using nrfx. Without this exclusion of -DNRF52 in compilation for nrf52840, the device will be interpreted as a nrf52, hence nrf52832. Also, changing name on variable SRC_NRF_HAL to SRC_NRFX_HAL to explicitly tell the origin of the file. * nrf: Updating device #ifdefs to be more open to non-nrf51 targets. * nrf/modules/machine/uart: Removing second instance of UART for nrf52840 as it only has one non-DMA variant. * nrf/device: Removing system files as these are now used from nrfx/mdk * nrf: Moving startup files in device one level up as there is no need for deep hierarchy. * nrf: Use NRF52_SERIES defined in nrfx/mdk/nrf.h as define value when testing for both nrf52(832) and nrf52840 variants. * nrf/modules/machine/uart: Enable UART RX by default Enable rx by default after intiialization of the peripheral. Else, the nrfx driver will re-enable rx for each byte read on uart REPL, clearing the EVENT_RXDRDY before second byte, which again will make second byte get lost and read will get stuck. This happens if the bytes are transmitted nrf(51) while still processing the previous byte. Not seen on nrf52, but should also become an issue at higher speeds. This patch sets rx to always be enabled. Hence, not clearing the event between read bytes, and it will be able to detect next byte recieved upon finishing the first. * nrf/modules/machine/timer: Fixing defines excluding Timer1 if ticker/softpwm is used. * nrf: Switching import form mpconfigboard.h to mpconfigport.h in nrfx_config.h as mpconfigboard.h might define default values for defines not set by board specific header. * nrf/modules/machine/i2c: nrfx integration fixes Increasing speed to 400K. Returning Address NACK's as MP error code; MP_ENODEV. Returning MP_ETIMEOUT on all other error codes from TWI nrfx driver except the ANACK. Enabling and disabling the TWI peripheral before and after each transaction. * nrf/examples: Updating ssd1306_mod.py to split framebuffer transfer into multiple chunks * nrf/modules/machine/i2c: Return MP_EIO error if Data NACK occurs. * nrf: Addressing review comments. * nrf: Updating git submodule and users to nrfx v1.0.0. * nrf/modules/machine/adc: Update adc module to follow v1.0.0 nrfx API. * nrf/modules/machine/spi: Implement init and deinit functions Extending SPI objects with a config member such that configuration can be kept between new() and init(). Moving initialization done in new() to common init function shared between the module functions. If SPI is already configured, the SPI peripheral will be uninitialized before initalized again. Adding logic to handle initialization of polarity and phase. As well, updating default speed to 1M from 500K. * nrf/modules/machine: Removing unused nrfx includes in machine module header files
1142 lines
41 KiB
C
1142 lines
41 KiB
C
/*
|
|
* This file is part of the MicroPython project, http://micropython.org/
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2016 Glenn Ruben Bakke
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#if BLUETOOTH_SD
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "py/runtime.h"
|
|
#include "ble_drv.h"
|
|
#include "mpconfigport.h"
|
|
#include "nrf_sdm.h"
|
|
#include "ble_gap.h"
|
|
#include "ble.h" // sd_ble_uuid_encode
|
|
#include "drivers/flash.h"
|
|
#include "mphalport.h"
|
|
|
|
|
|
#define BLE_DRIVER_VERBOSE 0
|
|
#if BLE_DRIVER_VERBOSE
|
|
#define BLE_DRIVER_LOG printf
|
|
#else
|
|
#define BLE_DRIVER_LOG(...)
|
|
#endif
|
|
|
|
#define BLE_ADV_LENGTH_FIELD_SIZE 1
|
|
#define BLE_ADV_AD_TYPE_FIELD_SIZE 1
|
|
#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1
|
|
|
|
#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION))
|
|
#define UNIT_0_625_MS (625)
|
|
#define UNIT_10_MS (10000)
|
|
#define APP_CFG_NON_CONN_ADV_TIMEOUT 0 // Disable timeout.
|
|
#define NON_CONNECTABLE_ADV_INTERVAL MSEC_TO_UNITS(100, UNIT_0_625_MS)
|
|
|
|
#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_0_625_MS)
|
|
#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_0_625_MS)
|
|
#define BLE_SLAVE_LATENCY 0
|
|
#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
|
|
|
|
#if !defined(GATT_MTU_SIZE_DEFAULT) && defined(BLE_GATT_ATT_MTU_DEFAULT)
|
|
#define GATT_MTU_SIZE_DEFAULT BLE_GATT_ATT_MTU_DEFAULT
|
|
#endif
|
|
|
|
#define SD_TEST_OR_ENABLE() \
|
|
if (ble_drv_stack_enabled() == 0) { \
|
|
(void)ble_drv_stack_enable(); \
|
|
}
|
|
|
|
static volatile bool m_adv_in_progress;
|
|
static volatile bool m_tx_in_progress;
|
|
|
|
static ble_drv_gap_evt_callback_t gap_event_handler;
|
|
static ble_drv_gatts_evt_callback_t gatts_event_handler;
|
|
|
|
static mp_obj_t mp_gap_observer;
|
|
static mp_obj_t mp_gatts_observer;
|
|
|
|
#if (BLUETOOTH_SD == 130) || (BLUETOOTH_SD == 132)
|
|
static volatile bool m_primary_service_found;
|
|
static volatile bool m_characteristic_found;
|
|
static volatile bool m_write_done;
|
|
|
|
static volatile ble_drv_adv_evt_callback_t adv_event_handler;
|
|
static volatile ble_drv_gattc_evt_callback_t gattc_event_handler;
|
|
static volatile ble_drv_disc_add_service_callback_t disc_add_service_handler;
|
|
static volatile ble_drv_disc_add_char_callback_t disc_add_char_handler;
|
|
static volatile ble_drv_gattc_char_data_callback_t gattc_char_data_handle;
|
|
|
|
static mp_obj_t mp_adv_observer;
|
|
static mp_obj_t mp_gattc_observer;
|
|
static mp_obj_t mp_gattc_disc_service_observer;
|
|
static mp_obj_t mp_gattc_disc_char_observer;
|
|
static mp_obj_t mp_gattc_char_data_observer;
|
|
#endif
|
|
|
|
#if (BLUETOOTH_SD != 100) && (BLUETOOTH_SD != 110)
|
|
#include "nrf_nvic.h"
|
|
|
|
#ifdef NRF52
|
|
nrf_nvic_state_t nrf_nvic_state = {0};
|
|
#endif // NRF52
|
|
|
|
#endif // (BLUETOOTH_SD != 100)
|
|
|
|
#if (BLUETOOTH_SD == 100 ) || (BLUETOOTH_SD == 110)
|
|
void softdevice_assert_handler(uint32_t pc, uint16_t line_number, const uint8_t * p_file_name) {
|
|
BLE_DRIVER_LOG("ERROR: SoftDevice assert!!!");
|
|
}
|
|
#else
|
|
void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) {
|
|
BLE_DRIVER_LOG("ERROR: SoftDevice assert!!!");
|
|
}
|
|
#endif
|
|
uint32_t ble_drv_stack_enable(void) {
|
|
m_adv_in_progress = false;
|
|
m_tx_in_progress = false;
|
|
|
|
#if (BLUETOOTH_SD == 100) || (BLUETOOTH_SD == 110)
|
|
#if BLUETOOTH_LFCLK_RC
|
|
uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_RC_250_PPM_250MS_CALIBRATION,
|
|
softdevice_assert_handler);
|
|
#else
|
|
uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM,
|
|
softdevice_assert_handler);
|
|
#endif // BLUETOOTH_LFCLK_RC
|
|
#else
|
|
#if BLUETOOTH_LFCLK_RC
|
|
nrf_clock_lf_cfg_t clock_config = {
|
|
.source = NRF_CLOCK_LF_SRC_RC,
|
|
.rc_ctiv = 16,
|
|
.rc_temp_ctiv = 2,
|
|
#if (BLE_API_VERSION >= 4)
|
|
.accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM
|
|
#else
|
|
.xtal_accuracy = 0
|
|
#endif
|
|
};
|
|
#else
|
|
nrf_clock_lf_cfg_t clock_config = {
|
|
.source = NRF_CLOCK_LF_SRC_XTAL,
|
|
.rc_ctiv = 0,
|
|
.rc_temp_ctiv = 0,
|
|
#if (BLE_API_VERSION >= 4)
|
|
.accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM
|
|
#else
|
|
.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM
|
|
#endif
|
|
};
|
|
#endif
|
|
uint32_t err_code = sd_softdevice_enable(&clock_config,
|
|
softdevice_assert_handler);
|
|
#endif
|
|
|
|
BLE_DRIVER_LOG("SoftDevice enable status: " UINT_FMT "\n", (uint16_t)err_code);
|
|
|
|
err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn);
|
|
|
|
BLE_DRIVER_LOG("IRQ enable status: " UINT_FMT "\n", (uint16_t)err_code);
|
|
|
|
#if (BLE_API_VERSION >= 4)
|
|
|
|
ble_cfg_t ble_conf;
|
|
uint32_t app_ram_start_cfg = 0x200039c0;
|
|
ble_conf.conn_cfg.conn_cfg_tag = 1;
|
|
ble_conf.conn_cfg.params.gap_conn_cfg.conn_count = 1;
|
|
ble_conf.conn_cfg.params.gap_conn_cfg.event_length = 3;
|
|
err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_conf, app_ram_start_cfg);
|
|
|
|
memset(&ble_conf, 0, sizeof(ble_conf));
|
|
|
|
ble_conf.gap_cfg.role_count_cfg.periph_role_count = 1;
|
|
ble_conf.gap_cfg.role_count_cfg.central_role_count = 1;
|
|
ble_conf.gap_cfg.role_count_cfg.central_sec_count = 0;
|
|
err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_conf, app_ram_start_cfg);
|
|
#else
|
|
// Enable BLE stack.
|
|
ble_enable_params_t ble_enable_params;
|
|
memset(&ble_enable_params, 0x00, sizeof(ble_enable_params));
|
|
ble_enable_params.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
|
|
ble_enable_params.gatts_enable_params.service_changed = 0;
|
|
#if (BLUETOOTH_SD == 132)
|
|
ble_enable_params.gap_enable_params.periph_conn_count = 1;
|
|
ble_enable_params.gap_enable_params.central_conn_count = 1;
|
|
#endif
|
|
#endif
|
|
|
|
#if (BLUETOOTH_SD == 100) || (BLUETOOTH_SD == 110)
|
|
err_code = sd_ble_enable(&ble_enable_params);
|
|
#else
|
|
|
|
#if (BLUETOOTH_SD == 132)
|
|
uint32_t app_ram_start = 0x200039c0;
|
|
#if (BLE_API_VERSION == 2) || (BLE_API_VERSION == 3)
|
|
err_code = sd_ble_enable(&ble_enable_params, &app_ram_start); // 8K SD headroom from linker script.
|
|
#elif (BLE_API_VERSION >= 4)
|
|
err_code = sd_ble_enable(&app_ram_start); // 8K SD headroom from linker script.
|
|
#endif
|
|
BLE_DRIVER_LOG("BLE ram size: " UINT_FMT "\n", (uint16_t)app_ram_start);
|
|
#else
|
|
err_code = sd_ble_enable(&ble_enable_params, (uint32_t *)0x20001870);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
BLE_DRIVER_LOG("BLE enable status: " UINT_FMT "\n", (uint16_t)err_code);
|
|
|
|
// set up security mode
|
|
ble_gap_conn_params_t gap_conn_params;
|
|
ble_gap_conn_sec_mode_t sec_mode;
|
|
|
|
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
|
|
|
|
const char device_name[] = "micr";
|
|
|
|
if ((err_code = sd_ble_gap_device_name_set(&sec_mode,
|
|
(const uint8_t *)device_name,
|
|
strlen(device_name))) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Cannot apply GAP parameters."));
|
|
}
|
|
|
|
// set connection parameters
|
|
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
|
|
|
|
gap_conn_params.min_conn_interval = BLE_MIN_CONN_INTERVAL;
|
|
gap_conn_params.max_conn_interval = BLE_MAX_CONN_INTERVAL;
|
|
gap_conn_params.slave_latency = BLE_SLAVE_LATENCY;
|
|
gap_conn_params.conn_sup_timeout = BLE_CONN_SUP_TIMEOUT;
|
|
|
|
if (sd_ble_gap_ppcp_set(&gap_conn_params) != 0) {
|
|
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Cannot set PPCP parameters."));
|
|
}
|
|
|
|
return err_code;
|
|
}
|
|
|
|
void ble_drv_stack_disable(void) {
|
|
sd_softdevice_disable();
|
|
}
|
|
|
|
uint8_t ble_drv_stack_enabled(void) {
|
|
uint8_t is_enabled;
|
|
uint32_t err_code = sd_softdevice_is_enabled(&is_enabled);
|
|
(void)err_code;
|
|
|
|
BLE_DRIVER_LOG("Is enabled status: " UINT_FMT "\n", (uint16_t)err_code);
|
|
|
|
return is_enabled;
|
|
}
|
|
|
|
void ble_drv_address_get(ble_drv_addr_t * p_addr) {
|
|
SD_TEST_OR_ENABLE();
|
|
|
|
ble_gap_addr_t local_ble_addr;
|
|
#if (BLE_API_VERSION >= 3)
|
|
uint32_t err_code = sd_ble_gap_addr_get(&local_ble_addr);
|
|
#else
|
|
uint32_t err_code = sd_ble_gap_address_get(&local_ble_addr);
|
|
#endif
|
|
|
|
if (err_code != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not query for the device address."));
|
|
}
|
|
|
|
BLE_DRIVER_LOG("ble address, type: " HEX2_FMT ", " \
|
|
"address: " HEX2_FMT ":" HEX2_FMT ":" HEX2_FMT ":" \
|
|
HEX2_FMT ":" HEX2_FMT ":" HEX2_FMT "\n", \
|
|
local_ble_addr.addr_type, \
|
|
local_ble_addr.addr[5], local_ble_addr.addr[4], local_ble_addr.addr[3], \
|
|
local_ble_addr.addr[2], local_ble_addr.addr[1], local_ble_addr.addr[0]);
|
|
|
|
p_addr->addr_type = local_ble_addr.addr_type;
|
|
memcpy(p_addr->addr, local_ble_addr.addr, 6);
|
|
}
|
|
|
|
bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx) {
|
|
SD_TEST_OR_ENABLE();
|
|
|
|
if (sd_ble_uuid_vs_add((ble_uuid128_t const *)p_uuid, idx) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not add Vendor Specific 128-bit UUID."));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ble_drv_service_add(ubluepy_service_obj_t * p_service_obj) {
|
|
SD_TEST_OR_ENABLE();
|
|
|
|
if (p_service_obj->p_uuid->type > BLE_UUID_TYPE_BLE) {
|
|
|
|
ble_uuid_t uuid;
|
|
uuid.type = p_service_obj->p_uuid->uuid_vs_idx;
|
|
uuid.uuid = p_service_obj->p_uuid->value[0];
|
|
uuid.uuid += p_service_obj->p_uuid->value[1] << 8;
|
|
|
|
if (sd_ble_gatts_service_add(p_service_obj->type,
|
|
&uuid,
|
|
&p_service_obj->handle) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not add Service."));
|
|
}
|
|
} else if (p_service_obj->p_uuid->type == BLE_UUID_TYPE_BLE) {
|
|
BLE_DRIVER_LOG("adding service\n");
|
|
|
|
ble_uuid_t uuid;
|
|
uuid.type = p_service_obj->p_uuid->type;
|
|
uuid.uuid = p_service_obj->p_uuid->value[0];
|
|
uuid.uuid += p_service_obj->p_uuid->value[1] << 8;
|
|
|
|
if (sd_ble_gatts_service_add(p_service_obj->type,
|
|
&uuid,
|
|
&p_service_obj->handle) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not add Service."));
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj) {
|
|
ble_gatts_char_md_t char_md;
|
|
ble_gatts_attr_md_t cccd_md;
|
|
ble_gatts_attr_t attr_char_value;
|
|
ble_uuid_t uuid;
|
|
ble_gatts_attr_md_t attr_md;
|
|
|
|
memset(&char_md, 0, sizeof(char_md));
|
|
|
|
char_md.char_props.broadcast = (p_char_obj->props & UBLUEPY_PROP_BROADCAST) ? 1 : 0;
|
|
char_md.char_props.read = (p_char_obj->props & UBLUEPY_PROP_READ) ? 1 : 0;
|
|
char_md.char_props.write_wo_resp = (p_char_obj->props & UBLUEPY_PROP_WRITE_WO_RESP) ? 1 : 0;
|
|
char_md.char_props.write = (p_char_obj->props & UBLUEPY_PROP_WRITE) ? 1 : 0;
|
|
char_md.char_props.notify = (p_char_obj->props & UBLUEPY_PROP_NOTIFY) ? 1 : 0;
|
|
char_md.char_props.indicate = (p_char_obj->props & UBLUEPY_PROP_INDICATE) ? 1 : 0;
|
|
#if 0
|
|
char_md.char_props.auth_signed_wr = (p_char_obj->props & UBLUEPY_PROP_NOTIFY) ? 1 : 0;
|
|
#endif
|
|
|
|
|
|
char_md.p_char_user_desc = NULL;
|
|
char_md.p_char_pf = NULL;
|
|
char_md.p_user_desc_md = NULL;
|
|
char_md.p_sccd_md = NULL;
|
|
|
|
// if cccd
|
|
if (p_char_obj->attrs & UBLUEPY_ATTR_CCCD) {
|
|
memset(&cccd_md, 0, sizeof(cccd_md));
|
|
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
|
|
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
|
|
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
|
|
char_md.p_cccd_md = &cccd_md;
|
|
} else {
|
|
char_md.p_cccd_md = NULL;
|
|
}
|
|
|
|
uuid.type = p_char_obj->p_uuid->type;
|
|
uuid.uuid = p_char_obj->p_uuid->value[0];
|
|
uuid.uuid += p_char_obj->p_uuid->value[1] << 8;
|
|
|
|
memset(&attr_md, 0, sizeof(attr_md));
|
|
|
|
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
|
|
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
|
|
|
|
attr_md.vloc = BLE_GATTS_VLOC_STACK;
|
|
attr_md.rd_auth = 0;
|
|
attr_md.wr_auth = 0;
|
|
attr_md.vlen = 1;
|
|
|
|
memset(&attr_char_value, 0, sizeof(attr_char_value));
|
|
|
|
attr_char_value.p_uuid = &uuid;
|
|
attr_char_value.p_attr_md = &attr_md;
|
|
attr_char_value.init_len = sizeof(uint8_t);
|
|
attr_char_value.init_offs = 0;
|
|
attr_char_value.max_len = (GATT_MTU_SIZE_DEFAULT - 3);
|
|
|
|
ble_gatts_char_handles_t handles;
|
|
|
|
if (sd_ble_gatts_characteristic_add(p_char_obj->service_handle,
|
|
&char_md,
|
|
&attr_char_value,
|
|
&handles) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not add Characteristic."));
|
|
}
|
|
|
|
// apply handles to object instance
|
|
p_char_obj->handle = handles.value_handle;
|
|
p_char_obj->user_desc_handle = handles.user_desc_handle;
|
|
p_char_obj->cccd_handle = handles.cccd_handle;
|
|
p_char_obj->sccd_handle = handles.sccd_handle;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
|
|
SD_TEST_OR_ENABLE();
|
|
|
|
uint8_t byte_pos = 0;
|
|
|
|
uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE];
|
|
|
|
if (p_adv_params->device_name_len > 0) {
|
|
ble_gap_conn_sec_mode_t sec_mode;
|
|
|
|
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
|
|
|
|
if (sd_ble_gap_device_name_set(&sec_mode,
|
|
p_adv_params->p_device_name,
|
|
p_adv_params->device_name_len) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not apply device name in the stack."));
|
|
}
|
|
|
|
BLE_DRIVER_LOG("Device name applied\n");
|
|
|
|
adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + p_adv_params->device_name_len);
|
|
byte_pos += BLE_ADV_LENGTH_FIELD_SIZE;
|
|
adv_data[byte_pos] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
|
|
byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE;
|
|
memcpy(&adv_data[byte_pos], p_adv_params->p_device_name, p_adv_params->device_name_len);
|
|
// increment position counter to see if it fits, and in case more content should
|
|
// follow in this adv packet.
|
|
byte_pos += p_adv_params->device_name_len;
|
|
}
|
|
|
|
// Add FLAGS only if manually controlled data has not been used.
|
|
if (p_adv_params->data_len == 0) {
|
|
// set flags, default to disc mode
|
|
adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + BLE_AD_TYPE_FLAGS_DATA_SIZE);
|
|
byte_pos += BLE_ADV_LENGTH_FIELD_SIZE;
|
|
adv_data[byte_pos] = BLE_GAP_AD_TYPE_FLAGS;
|
|
byte_pos += BLE_AD_TYPE_FLAGS_DATA_SIZE;
|
|
adv_data[byte_pos] = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
|
|
byte_pos += 1;
|
|
}
|
|
|
|
if (p_adv_params->num_of_services > 0) {
|
|
|
|
bool type_16bit_present = false;
|
|
bool type_128bit_present = false;
|
|
|
|
for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) {
|
|
ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i];
|
|
if (p_service->p_uuid->type == UBLUEPY_UUID_16_BIT) {
|
|
type_16bit_present = true;
|
|
}
|
|
|
|
if (p_service->p_uuid->type == UBLUEPY_UUID_128_BIT) {
|
|
type_128bit_present = true;
|
|
}
|
|
}
|
|
|
|
if (type_16bit_present) {
|
|
uint8_t size_byte_pos = byte_pos;
|
|
|
|
// skip length byte for now, apply total length post calculation
|
|
byte_pos += BLE_ADV_LENGTH_FIELD_SIZE;
|
|
|
|
adv_data[byte_pos] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE;
|
|
byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE;
|
|
|
|
uint8_t uuid_total_size = 0;
|
|
uint8_t encoded_size = 0;
|
|
|
|
for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) {
|
|
ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i];
|
|
|
|
ble_uuid_t uuid;
|
|
uuid.type = p_service->p_uuid->type;
|
|
uuid.uuid = p_service->p_uuid->value[0];
|
|
uuid.uuid += p_service->p_uuid->value[1] << 8;
|
|
// calculate total size of uuids
|
|
if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not encode UUID, to check length."));
|
|
}
|
|
|
|
// do encoding into the adv buffer
|
|
if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can encode UUID into the advertisment packet."));
|
|
}
|
|
|
|
BLE_DRIVER_LOG("encoded uuid for service %u: ", 0);
|
|
for (uint8_t j = 0; j < encoded_size; j++) {
|
|
BLE_DRIVER_LOG(HEX2_FMT " ", adv_data[byte_pos + j]);
|
|
}
|
|
BLE_DRIVER_LOG("\n");
|
|
|
|
uuid_total_size += encoded_size; // size of entry
|
|
byte_pos += encoded_size; // relative to adv data packet
|
|
BLE_DRIVER_LOG("ADV: uuid size: %u, type: %u, uuid: %x%x, vs_idx: %u\n",
|
|
encoded_size, p_service->p_uuid->type,
|
|
p_service->p_uuid->value[1],
|
|
p_service->p_uuid->value[0],
|
|
p_service->p_uuid->uuid_vs_idx);
|
|
}
|
|
|
|
adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size);
|
|
}
|
|
|
|
if (type_128bit_present) {
|
|
uint8_t size_byte_pos = byte_pos;
|
|
|
|
// skip length byte for now, apply total length post calculation
|
|
byte_pos += BLE_ADV_LENGTH_FIELD_SIZE;
|
|
|
|
adv_data[byte_pos] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE;
|
|
byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE;
|
|
|
|
uint8_t uuid_total_size = 0;
|
|
uint8_t encoded_size = 0;
|
|
|
|
for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) {
|
|
ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i];
|
|
|
|
ble_uuid_t uuid;
|
|
uuid.type = p_service->p_uuid->uuid_vs_idx;
|
|
uuid.uuid = p_service->p_uuid->value[0];
|
|
uuid.uuid += p_service->p_uuid->value[1] << 8;
|
|
|
|
// calculate total size of uuids
|
|
if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not encode UUID, to check length."));
|
|
}
|
|
|
|
// do encoding into the adv buffer
|
|
if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can encode UUID into the advertisment packet."));
|
|
}
|
|
|
|
BLE_DRIVER_LOG("encoded uuid for service %u: ", 0);
|
|
for (uint8_t j = 0; j < encoded_size; j++) {
|
|
BLE_DRIVER_LOG(HEX2_FMT " ", adv_data[byte_pos + j]);
|
|
}
|
|
BLE_DRIVER_LOG("\n");
|
|
|
|
uuid_total_size += encoded_size; // size of entry
|
|
byte_pos += encoded_size; // relative to adv data packet
|
|
BLE_DRIVER_LOG("ADV: uuid size: %u, type: %x%x, uuid: %u, vs_idx: %u\n",
|
|
encoded_size, p_service->p_uuid->type,
|
|
p_service->p_uuid->value[1],
|
|
p_service->p_uuid->value[0],
|
|
p_service->p_uuid->uuid_vs_idx);
|
|
}
|
|
|
|
adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size);
|
|
}
|
|
}
|
|
|
|
if ((p_adv_params->data_len > 0) && (p_adv_params->p_data != NULL)) {
|
|
if (p_adv_params->data_len + byte_pos > BLE_GAP_ADV_MAX_SIZE) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not fit data into the advertisment packet."));
|
|
}
|
|
|
|
memcpy(adv_data, p_adv_params->p_data, p_adv_params->data_len);
|
|
byte_pos += p_adv_params->data_len;
|
|
}
|
|
|
|
// scan response data not set
|
|
uint32_t err_code;
|
|
if ((err_code = sd_ble_gap_adv_data_set(adv_data, byte_pos, NULL, 0)) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not apply advertisment data. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
BLE_DRIVER_LOG("Set Adv data size: " UINT_FMT "\n", byte_pos);
|
|
|
|
static ble_gap_adv_params_t m_adv_params;
|
|
|
|
// initialize advertising params
|
|
memset(&m_adv_params, 0, sizeof(m_adv_params));
|
|
if (p_adv_params->connectable) {
|
|
m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND;
|
|
} else {
|
|
m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND;
|
|
}
|
|
|
|
m_adv_params.p_peer_addr = NULL; // undirected advertisement
|
|
m_adv_params.fp = BLE_GAP_ADV_FP_ANY;
|
|
m_adv_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); // approx 8 ms
|
|
m_adv_params.timeout = 0; // infinite advertisment
|
|
|
|
ble_drv_advertise_stop();
|
|
#if (BLE_API_VERSION == 4)
|
|
uint8_t conf_tag = BLE_CONN_CFG_TAG_DEFAULT; // Could also be set to tag from sd_ble_cfg_set
|
|
err_code = sd_ble_gap_adv_start(&m_adv_params, conf_tag);
|
|
#else
|
|
err_code = sd_ble_gap_adv_start(&m_adv_params);
|
|
#endif
|
|
if (err_code != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not start advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
|
|
m_adv_in_progress = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ble_drv_advertise_stop(void) {
|
|
if (m_adv_in_progress == true) {
|
|
uint32_t err_code;
|
|
if ((err_code = sd_ble_gap_adv_stop()) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not stop advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
}
|
|
m_adv_in_progress = false;
|
|
}
|
|
|
|
void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) {
|
|
ble_gatts_value_t gatts_value;
|
|
memset(&gatts_value, 0, sizeof(gatts_value));
|
|
|
|
gatts_value.len = len;
|
|
gatts_value.offset = 0;
|
|
gatts_value.p_value = p_data;
|
|
|
|
uint32_t err_code = sd_ble_gatts_value_get(conn_handle,
|
|
handle,
|
|
&gatts_value);
|
|
if (err_code != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not read attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
|
|
}
|
|
|
|
void ble_drv_attr_s_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) {
|
|
ble_gatts_value_t gatts_value;
|
|
memset(&gatts_value, 0, sizeof(gatts_value));
|
|
|
|
gatts_value.len = len;
|
|
gatts_value.offset = 0;
|
|
gatts_value.p_value = p_data;
|
|
|
|
uint32_t err_code = sd_ble_gatts_value_set(conn_handle, handle, &gatts_value);
|
|
|
|
if (err_code != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not write attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
}
|
|
|
|
void ble_drv_attr_s_notify(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) {
|
|
uint16_t hvx_len = len;
|
|
ble_gatts_hvx_params_t hvx_params;
|
|
|
|
memset(&hvx_params, 0, sizeof(hvx_params));
|
|
|
|
hvx_params.handle = handle;
|
|
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
|
hvx_params.offset = 0;
|
|
hvx_params.p_len = &hvx_len;
|
|
hvx_params.p_data = p_data;
|
|
|
|
while (m_tx_in_progress) {
|
|
;
|
|
}
|
|
|
|
m_tx_in_progress = true;
|
|
uint32_t err_code;
|
|
if ((err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params)) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not notify attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
}
|
|
|
|
void ble_drv_gap_event_handler_set(mp_obj_t obj, ble_drv_gap_evt_callback_t evt_handler) {
|
|
mp_gap_observer = obj;
|
|
gap_event_handler = evt_handler;
|
|
}
|
|
|
|
void ble_drv_gatts_event_handler_set(mp_obj_t obj, ble_drv_gatts_evt_callback_t evt_handler) {
|
|
mp_gatts_observer = obj;
|
|
gatts_event_handler = evt_handler;
|
|
}
|
|
|
|
#if (BLUETOOTH_SD == 130) || (BLUETOOTH_SD == 132)
|
|
|
|
void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t evt_handler) {
|
|
mp_gattc_observer = obj;
|
|
gattc_event_handler = evt_handler;
|
|
}
|
|
|
|
void ble_drv_adv_report_handler_set(mp_obj_t obj, ble_drv_adv_evt_callback_t evt_handler) {
|
|
mp_adv_observer = obj;
|
|
adv_event_handler = evt_handler;
|
|
}
|
|
|
|
|
|
void ble_drv_attr_c_read(uint16_t conn_handle, uint16_t handle, mp_obj_t obj, ble_drv_gattc_char_data_callback_t cb) {
|
|
|
|
mp_gattc_char_data_observer = obj;
|
|
gattc_char_data_handle = cb;
|
|
|
|
uint32_t err_code = sd_ble_gattc_read(conn_handle,
|
|
handle,
|
|
0);
|
|
if (err_code != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not read attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
|
|
while (gattc_char_data_handle != NULL) {
|
|
;
|
|
}
|
|
}
|
|
|
|
void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data, bool w_response) {
|
|
|
|
ble_gattc_write_params_t write_params;
|
|
|
|
if (w_response) {
|
|
write_params.write_op = BLE_GATT_OP_WRITE_REQ;
|
|
} else {
|
|
write_params.write_op = BLE_GATT_OP_WRITE_CMD;
|
|
}
|
|
|
|
write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL;
|
|
write_params.handle = handle;
|
|
write_params.offset = 0;
|
|
write_params.len = len;
|
|
write_params.p_value = p_data;
|
|
|
|
m_write_done = !w_response;
|
|
|
|
uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params);
|
|
|
|
if (err_code != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not write attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
|
|
while (m_write_done != true) {
|
|
;
|
|
}
|
|
}
|
|
|
|
void ble_drv_scan_start(void) {
|
|
SD_TEST_OR_ENABLE();
|
|
|
|
ble_gap_scan_params_t scan_params;
|
|
scan_params.active = 1;
|
|
scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS);
|
|
scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS);
|
|
scan_params.timeout = 0; // Infinite
|
|
|
|
#if (BLUETOOTH_SD == 130)
|
|
scan_params.selective = 0;
|
|
scan_params.p_whitelist = NULL;
|
|
#elif (BLE_API_VERSION == 3 || BLE_API_VERSION == 4)
|
|
scan_params.use_whitelist = 0;
|
|
#endif
|
|
|
|
uint32_t err_code;
|
|
if ((err_code = sd_ble_gap_scan_start(&scan_params)) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not start scanning. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
}
|
|
|
|
void ble_drv_scan_stop(void) {
|
|
sd_ble_gap_scan_stop();
|
|
}
|
|
|
|
void ble_drv_connect(uint8_t * p_addr, uint8_t addr_type) {
|
|
SD_TEST_OR_ENABLE();
|
|
|
|
ble_gap_scan_params_t scan_params;
|
|
scan_params.active = 1;
|
|
scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS);
|
|
scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS);
|
|
scan_params.timeout = 0; // infinite
|
|
|
|
#if (BLUETOOTH_SD == 130)
|
|
scan_params.selective = 0;
|
|
scan_params.p_whitelist = NULL;
|
|
#elif (BLE_API_VERSION == 3 || BLE_API_VERSION == 4)
|
|
scan_params.use_whitelist = 0;
|
|
#endif
|
|
|
|
ble_gap_addr_t addr;
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.addr_type = addr_type;
|
|
memcpy(addr.addr, p_addr, 6);
|
|
|
|
BLE_DRIVER_LOG("GAP CONNECTING: "HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT", type: %d\n",
|
|
addr.addr[0], addr.addr[1], addr.addr[2], addr.addr[3], addr.addr[4], addr.addr[5], addr.addr_type);
|
|
|
|
ble_gap_conn_params_t conn_params;
|
|
|
|
// (void)sd_ble_gap_ppcp_get(&conn_params);
|
|
|
|
// set connection parameters
|
|
memset(&conn_params, 0, sizeof(conn_params));
|
|
|
|
conn_params.min_conn_interval = BLE_MIN_CONN_INTERVAL;
|
|
conn_params.max_conn_interval = BLE_MAX_CONN_INTERVAL;
|
|
conn_params.slave_latency = BLE_SLAVE_LATENCY;
|
|
conn_params.conn_sup_timeout = BLE_CONN_SUP_TIMEOUT;
|
|
|
|
uint32_t err_code;
|
|
#if (BLE_API_VERSION >= 4)
|
|
uint8_t conn_tag = BLE_CONN_CFG_TAG_DEFAULT;
|
|
if ((err_code = sd_ble_gap_connect(&addr,
|
|
&scan_params,
|
|
&conn_params,
|
|
conn_tag)) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not connect. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
#else
|
|
if ((err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params)) != 0) {
|
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
|
"Can not connect. status: 0x" HEX2_FMT, (uint16_t)err_code));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool ble_drv_discover_services(mp_obj_t obj, uint16_t conn_handle, uint16_t start_handle, ble_drv_disc_add_service_callback_t cb) {
|
|
BLE_DRIVER_LOG("Discover primary services. Conn handle: 0x" HEX2_FMT "\n",
|
|
conn_handle);
|
|
|
|
mp_gattc_disc_service_observer = obj;
|
|
disc_add_service_handler = cb;
|
|
|
|
m_primary_service_found = false;
|
|
|
|
uint32_t err_code;
|
|
err_code = sd_ble_gattc_primary_services_discover(conn_handle,
|
|
start_handle,
|
|
NULL);
|
|
if (err_code != 0) {
|
|
return false;
|
|
}
|
|
|
|
// busy loop until last service has been iterated
|
|
while (disc_add_service_handler != NULL) {
|
|
;
|
|
}
|
|
|
|
if (m_primary_service_found) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ble_drv_discover_characteristic(mp_obj_t obj,
|
|
uint16_t conn_handle,
|
|
uint16_t start_handle,
|
|
uint16_t end_handle,
|
|
ble_drv_disc_add_char_callback_t cb) {
|
|
BLE_DRIVER_LOG("Discover characteristicts. Conn handle: 0x" HEX2_FMT "\n",
|
|
conn_handle);
|
|
|
|
mp_gattc_disc_char_observer = obj;
|
|
disc_add_char_handler = cb;
|
|
|
|
ble_gattc_handle_range_t handle_range;
|
|
handle_range.start_handle = start_handle;
|
|
handle_range.end_handle = end_handle;
|
|
|
|
m_characteristic_found = false;
|
|
|
|
uint32_t err_code;
|
|
err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range);
|
|
if (err_code != 0) {
|
|
return false;
|
|
}
|
|
|
|
// busy loop until last service has been iterated
|
|
while (disc_add_char_handler != NULL) {
|
|
;
|
|
}
|
|
|
|
if (m_characteristic_found) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ble_drv_discover_descriptors(void) {
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
static void sd_evt_handler(uint32_t evt_id) {
|
|
switch (evt_id) {
|
|
#if MICROPY_HW_HAS_BUILTIN_FLASH
|
|
case NRF_EVT_FLASH_OPERATION_SUCCESS:
|
|
flash_operation_finished(FLASH_STATE_SUCCESS);
|
|
break;
|
|
case NRF_EVT_FLASH_OPERATION_ERROR:
|
|
flash_operation_finished(FLASH_STATE_ERROR);
|
|
break;
|
|
#endif
|
|
default:
|
|
// unhandled event!
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ble_evt_handler(ble_evt_t * p_ble_evt) {
|
|
// S132 event ranges.
|
|
// Common 0x01 -> 0x0F
|
|
// GAP 0x10 -> 0x2F
|
|
// GATTC 0x30 -> 0x4F
|
|
// GATTS 0x50 -> 0x6F
|
|
// L2CAP 0x70 -> 0x8F
|
|
switch (p_ble_evt->header.evt_id) {
|
|
case BLE_GAP_EVT_CONNECTED:
|
|
BLE_DRIVER_LOG("GAP CONNECT\n");
|
|
m_adv_in_progress = false;
|
|
gap_event_handler(mp_gap_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL);
|
|
|
|
ble_gap_conn_params_t conn_params;
|
|
(void)sd_ble_gap_ppcp_get(&conn_params);
|
|
(void)sd_ble_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle, &conn_params);
|
|
break;
|
|
|
|
case BLE_GAP_EVT_DISCONNECTED:
|
|
BLE_DRIVER_LOG("GAP DISCONNECT\n");
|
|
gap_event_handler(mp_gap_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL);
|
|
break;
|
|
|
|
case BLE_GATTS_EVT_HVC:
|
|
gatts_event_handler(mp_gatts_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gatts_evt.params.hvc.handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL);
|
|
break;
|
|
|
|
case BLE_GATTS_EVT_WRITE:
|
|
BLE_DRIVER_LOG("GATTS write\n");
|
|
|
|
uint16_t handle = p_ble_evt->evt.gatts_evt.params.write.handle;
|
|
uint16_t data_len = p_ble_evt->evt.gatts_evt.params.write.len;
|
|
uint8_t * p_data = &p_ble_evt->evt.gatts_evt.params.write.data[0];
|
|
|
|
gatts_event_handler(mp_gatts_observer, p_ble_evt->header.evt_id, handle, data_len, p_data);
|
|
break;
|
|
|
|
case BLE_GAP_EVT_CONN_PARAM_UPDATE:
|
|
BLE_DRIVER_LOG("GAP CONN PARAM UPDATE\n");
|
|
break;
|
|
|
|
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
|
|
// No system attributes have been stored.
|
|
(void)sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0);
|
|
break;
|
|
|
|
#if (BLE_API_VERSION >= 3)
|
|
case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
|
|
BLE_DRIVER_LOG("GATTS EVT EXCHANGE MTU REQUEST\n");
|
|
(void)sd_ble_gatts_exchange_mtu_reply(p_ble_evt->evt.gatts_evt.conn_handle, 23); // MAX MTU size
|
|
break;
|
|
#endif
|
|
|
|
#if (BLE_API_VERSION >= 4)
|
|
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
|
|
#else
|
|
case BLE_EVT_TX_COMPLETE:
|
|
#endif
|
|
BLE_DRIVER_LOG("BLE EVT TX COMPLETE\n");
|
|
m_tx_in_progress = false;
|
|
break;
|
|
|
|
case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
|
|
BLE_DRIVER_LOG("BLE EVT SEC PARAMS REQUEST\n");
|
|
// pairing not supported
|
|
(void)sd_ble_gap_sec_params_reply(p_ble_evt->evt.gatts_evt.conn_handle,
|
|
BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
|
|
NULL, NULL);
|
|
break;
|
|
|
|
#if (BLUETOOTH_SD == 130) || (BLUETOOTH_SD == 132)
|
|
case BLE_GAP_EVT_ADV_REPORT:
|
|
BLE_DRIVER_LOG("BLE EVT ADV REPORT\n");
|
|
ble_drv_adv_data_t adv_data = {
|
|
.p_peer_addr = p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr,
|
|
.addr_type = p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr_type,
|
|
.is_scan_resp = p_ble_evt->evt.gap_evt.params.adv_report.scan_rsp,
|
|
.rssi = p_ble_evt->evt.gap_evt.params.adv_report.rssi,
|
|
.data_len = p_ble_evt->evt.gap_evt.params.adv_report.dlen,
|
|
.p_data = p_ble_evt->evt.gap_evt.params.adv_report.data,
|
|
.adv_type = p_ble_evt->evt.gap_evt.params.adv_report.type
|
|
};
|
|
|
|
// TODO: Fix unsafe callback to possible undefined callback...
|
|
adv_event_handler(mp_adv_observer,
|
|
p_ble_evt->header.evt_id,
|
|
&adv_data);
|
|
break;
|
|
|
|
case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
|
|
BLE_DRIVER_LOG("BLE EVT CONN PARAM UPDATE REQUEST\n");
|
|
|
|
(void)sd_ble_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle,
|
|
&p_ble_evt->evt.gap_evt.params.conn_param_update_request.conn_params);
|
|
break;
|
|
|
|
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
|
|
BLE_DRIVER_LOG("BLE EVT PRIMARY SERVICE DISCOVERY RESPONSE\n");
|
|
BLE_DRIVER_LOG(">>> service count: %d\n", p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count);
|
|
|
|
for (uint16_t i = 0; i < p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count; i++) {
|
|
ble_gattc_service_t * p_service = &p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i];
|
|
|
|
ble_drv_service_data_t service;
|
|
service.uuid_type = p_service->uuid.type;
|
|
service.uuid = p_service->uuid.uuid;
|
|
service.start_handle = p_service->handle_range.start_handle;
|
|
service.end_handle = p_service->handle_range.end_handle;
|
|
|
|
disc_add_service_handler(mp_gattc_disc_service_observer, &service);
|
|
}
|
|
|
|
if (p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count > 0) {
|
|
m_primary_service_found = true;
|
|
}
|
|
|
|
// mark end of service discovery
|
|
disc_add_service_handler = NULL;
|
|
|
|
break;
|
|
|
|
case BLE_GATTC_EVT_CHAR_DISC_RSP:
|
|
BLE_DRIVER_LOG("BLE EVT CHAR DISCOVERY RESPONSE\n");
|
|
BLE_DRIVER_LOG(">>> characteristic count: %d\n", p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count);
|
|
|
|
for (uint16_t i = 0; i < p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count; i++) {
|
|
ble_gattc_char_t * p_char = &p_ble_evt->evt.gattc_evt.params.char_disc_rsp.chars[i];
|
|
|
|
ble_drv_char_data_t char_data;
|
|
char_data.uuid_type = p_char->uuid.type;
|
|
char_data.uuid = p_char->uuid.uuid;
|
|
char_data.decl_handle = p_char->handle_decl;
|
|
char_data.value_handle = p_char->handle_value;
|
|
|
|
char_data.props |= (p_char->char_props.broadcast) ? UBLUEPY_PROP_BROADCAST : 0;
|
|
char_data.props |= (p_char->char_props.read) ? UBLUEPY_PROP_READ : 0;
|
|
char_data.props |= (p_char->char_props.write_wo_resp) ? UBLUEPY_PROP_WRITE_WO_RESP : 0;
|
|
char_data.props |= (p_char->char_props.write) ? UBLUEPY_PROP_WRITE : 0;
|
|
char_data.props |= (p_char->char_props.notify) ? UBLUEPY_PROP_NOTIFY : 0;
|
|
char_data.props |= (p_char->char_props.indicate) ? UBLUEPY_PROP_INDICATE : 0;
|
|
#if 0
|
|
char_data.props |= (p_char->char_props.auth_signed_wr) ? UBLUEPY_PROP_NOTIFY : 0;
|
|
#endif
|
|
|
|
disc_add_char_handler(mp_gattc_disc_char_observer, &char_data);
|
|
}
|
|
|
|
if (p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count > 0) {
|
|
m_characteristic_found = true;
|
|
}
|
|
|
|
// mark end of characteristic discovery
|
|
disc_add_char_handler = NULL;
|
|
|
|
break;
|
|
|
|
case BLE_GATTC_EVT_READ_RSP:
|
|
BLE_DRIVER_LOG("BLE EVT READ RESPONSE, offset: 0x"HEX2_FMT", length: 0x"HEX2_FMT"\n",
|
|
p_ble_evt->evt.gattc_evt.params.read_rsp.offset,
|
|
p_ble_evt->evt.gattc_evt.params.read_rsp.len);
|
|
|
|
gattc_char_data_handle(mp_gattc_char_data_observer,
|
|
p_ble_evt->evt.gattc_evt.params.read_rsp.len,
|
|
p_ble_evt->evt.gattc_evt.params.read_rsp.data);
|
|
|
|
// mark end of read
|
|
gattc_char_data_handle = NULL;
|
|
|
|
break;
|
|
|
|
case BLE_GATTC_EVT_WRITE_RSP:
|
|
BLE_DRIVER_LOG("BLE EVT WRITE RESPONSE\n");
|
|
m_write_done = true;
|
|
break;
|
|
|
|
case BLE_GATTC_EVT_HVX:
|
|
BLE_DRIVER_LOG("BLE EVT HVX RESPONSE\n");
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
BLE_DRIVER_LOG(">>> unhandled evt: 0x" HEX2_FMT "\n", p_ble_evt->header.evt_id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (GATT_MTU_SIZE_DEFAULT)] __attribute__ ((aligned (4)));
|
|
|
|
#ifdef NRF51
|
|
void SWI2_IRQHandler(void) {
|
|
#else
|
|
void SWI2_EGU2_IRQHandler(void) {
|
|
#endif
|
|
|
|
uint32_t evt_id;
|
|
while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) {
|
|
sd_evt_handler(evt_id);
|
|
}
|
|
|
|
while (1) {
|
|
uint16_t evt_len = sizeof(m_ble_evt_buf);
|
|
uint32_t err_code = sd_ble_evt_get(m_ble_evt_buf, &evt_len);
|
|
if (err_code != NRF_SUCCESS) {
|
|
// Possible error conditions:
|
|
// * NRF_ERROR_NOT_FOUND: no events left, break
|
|
// * NRF_ERROR_DATA_SIZE: retry with a bigger data buffer
|
|
// (currently not handled, TODO)
|
|
// * NRF_ERROR_INVALID_ADDR: pointer is not aligned, should
|
|
// not happen.
|
|
// In all cases, it's best to simply stop now.
|
|
if (err_code == NRF_ERROR_DATA_SIZE) {
|
|
BLE_DRIVER_LOG("NRF_ERROR_DATA_SIZE\n");
|
|
}
|
|
break;
|
|
}
|
|
ble_evt_handler((ble_evt_t *)m_ble_evt_buf);
|
|
}
|
|
}
|
|
|
|
#endif // BLUETOOTH_SD
|