Ср мар 03, 2021 22:45:03
Имеется в виду событие sl_bt_evt_gatt_procedure_completed_id:? Хорошо, допустим, я получил информацию о завершении и послал следующий запрос, потом снова получил и снова послал. Т.е. весь characteristic discovery я могу делать в этом case. Но из какого события посылать первый запрос? Хотелось бы юниформности. Хотя мне еще надо над этим подумать, с учетом моего желания распихать обработчики сервисов по разным файлам, так, чтобы они без нужды не пересекались.Ser60 писал(а):В программе клиента формируется событие когда придёт ответ сервера на запрос. Дождитесь его и потом посылайте следующий.
sl_status_t sl_bt_gatt_write_characteristic_value_without_response(uint8_t connection,
uint16_t characteristic,
size_t value_len,
const uint8_t* value,
uint16_t *sent_len);
Ср мар 03, 2021 23:59:48
Чт мар 04, 2021 20:26:30
В программе клиента первым делом следует установить соединение с сервером и получить connection handle. При соединении генерируется специальное событие и первый запрос на чтение сервисов/характеристик можно сделать оттуда. Вообще, есть очень полезный документ с примером чтения клиентом сервисов и характеристик сервера. Думаю, он ответит на все Ваши вопросы выше. Он, правда, под версию стека 2.х, но для современной версии стека изменения минимальны.из какого события посылать первый запрос?
Конечно, возможно. Для этого и существуют advertisements и scan response. Вы можете там сконфигурировать передаваемую информацию о поддерживаемых сервером сервисах (или их части). Как это сделать - см. серию статей в категории KBA_BT_020x. Они, правда, тоже под старый стек и частично переписаны под новый в docs.silabs.com, однако не всегда с прежней подробностью. Если хотите, там-же в полях можно передавать какие handles у требуемых характеристик в BT DB для ускорения процедуры их чтения клиентом. Точнее, при этом можно вообще без этой процедуры обойтись.клиент узнаёт о сервисах сервера еще до соединения в событии gecko_evt_le_gap_scan_response_id:. Возможно ли это или я не понимаю?
Если делаете это для поиска своего сервера при сканировании, то можно , например, в scan response передавать уникальное поле для вашего сервера и искать устройства, содержащие это поле в scan response.Пока я фильтрую просто по "таблице моих устройств".
value_len - это входной параметр API и он должен отражать реальную длину посылаемых данных. sent_len - выходной параметр (pointer на статичекую переменную). Поскольку подавляющее большинство BT API non-blocking, то значение переменной по ссылке будет установлено только по фактическому завершению передачи данных.Не смог понять чем value_len, отличается от sent_len
Вс мар 07, 2021 11:48:59
typedef enum {
idle,
discover_service,
discover_charactristic,
enable_notification,
active
} bt_state;
/*
* serial.c
*
* Created on: 18 февр. 2021 г.
* Author: wl
*/
#include "sl_bluetooth.h"
#include "gatt_db.h"
#include "app.h"
#include "sl_app_assert.h"
#include "sl_iostream_uart.h"
#include "sl_iostream_init_usart_instances.h"
#include "printf.h"
static uint8_t connection_handler, respLen, *respData;
static uint16_t char_handle = 0xFFFF, handle, gatt_result;
static uint32_t service_handle;
unsigned int ii, char_handle_defined=0, service_discovered=0;
static uint8_t service_UUID[] = {0xe0, 0xff}, characteristic_UUID[] = {0xe1, 0xff};
bt_state serial_state = idle;
void serial_on_event(sl_bt_msg_t *evt) {
sl_status_t sc;
switch (SL_BT_MSG_ID(evt->header)) {
case sl_bt_evt_connection_opened_id:
connection_handler = evt->data.evt_connection_opened.connection;
serial_state = discover_service;
break;
case sl_bt_evt_gatt_service_id:
if (0 == memcmp(evt->data.evt_gatt_service.uuid.data,service_UUID, evt->data.evt_gatt_service.uuid.len)) {
service_handle = evt->data.evt_gatt_service.service;
service_discovered = 1;
printf("Service handler = %08x\r\n", service_handle);
}
if (evt->data.evt_gatt_service.uuid.len == 2) {
printf("Discovered service 16bit: %04x\r\n",
evt->data.evt_gatt_service.uuid.data[0] + (evt->data.evt_gatt_service.uuid.data[1] << 8));
} else {
printf("Discovered service %08x%08x%08x%08x (%02x)\r\n",
evt->data.evt_gatt_service.uuid.data[12] + (evt->data.evt_gatt_service.uuid.data[13] << 8) + (evt->data.evt_gatt_service.uuid.data[14] << 16) + (evt->data.evt_gatt_service.uuid.data[15] << 24),
evt->data.evt_gatt_service.uuid.data[8] + (evt->data.evt_gatt_service.uuid.data[9] << 8) + (evt->data.evt_gatt_service.uuid.data[10] << 16) + (evt->data.evt_gatt_service.uuid.data[11] << 24),
evt->data.evt_gatt_service.uuid.data[4] + (evt->data.evt_gatt_service.uuid.data[5] << 8) + (evt->data.evt_gatt_service.uuid.data[6] << 16) + (evt->data.evt_gatt_service.uuid.data[7] << 24),
evt->data.evt_gatt_service.uuid.data[0] + (evt->data.evt_gatt_service.uuid.data[1] << 8) + (evt->data.evt_gatt_service.uuid.data[2] << 16) + (evt->data.evt_gatt_service.uuid.data[3] << 24),
evt->data.evt_gatt_service.uuid.len);
}
break;
case sl_bt_evt_gatt_characteristic_id:
if (serial_state == discover_charactristic) {
if (0 == memcmp(evt->data.evt_gatt_characteristic.uuid.data, characteristic_UUID, evt->data.evt_gatt_characteristic.uuid.len)) {
char_handle = evt->data.evt_gatt_characteristic.characteristic;
char_handle_defined = 1;
printf("Serial characteristic handler = %04x\r\n", char_handle);
}
if (evt->data.evt_gatt_characteristic.uuid.len == 2) {
printf("Discovered serial characteristic 16bit: %04x\r\n",
evt->data.evt_gatt_characteristic.uuid.data[0] + (evt->data.evt_gatt_characteristic.uuid.data[1] << 8));
} else {
printf("Discovered serial characteristic %08x%08x%08x%08x (%02x)\r\n",
evt->data.evt_gatt_characteristic.uuid.data[12] + (evt->data.evt_gatt_characteristic.uuid.data[13] << 8) + (evt->data.evt_gatt_characteristic.uuid.data[14] << 16) + (evt->data.evt_gatt_characteristic.uuid.data[15] << 24),
evt->data.evt_gatt_characteristic.uuid.data[8] + (evt->data.evt_gatt_characteristic.uuid.data[9] << 8) + (evt->data.evt_gatt_characteristic.uuid.data[10] << 16) + (evt->data.evt_gatt_characteristic.uuid.data[11] << 24),
evt->data.evt_gatt_characteristic.uuid.data[4] + (evt->data.evt_gatt_characteristic.uuid.data[5] << 8) + (evt->data.evt_gatt_characteristic.uuid.data[6] << 16) + (evt->data.evt_gatt_characteristic.uuid.data[7] << 24),
evt->data.evt_gatt_characteristic.uuid.data[0] + (evt->data.evt_gatt_characteristic.uuid.data[1] << 8) + (evt->data.evt_gatt_characteristic.uuid.data[2] << 16) + (evt->data.evt_gatt_characteristic.uuid.data[3] << 24),
evt->data.evt_gatt_characteristic.uuid.len);
}
}
break;
case sl_bt_evt_gatt_procedure_completed_id:
gatt_result = evt->data.evt_gatt_procedure_completed.result;
sl_app_assert(gatt_result == 0, "[E: 0x%04x] gatt_procedure_completed_id\r\n", (int)gatt_result);
switch (serial_state) {
case discover_service:
if (service_discovered) {
sc = sl_bt_gatt_discover_characteristics_by_uuid(connection_handler,
service_handle, sizeof(characteristic_UUID),
characteristic_UUID);
if (sc == SL_STATUS_OK) serial_state = discover_charactristic;
// sl_app_assert(, "[E: 0x%04x] gatt_discover_characteristics_by_uuid\r\n", (int)sc);
}
break;
case discover_charactristic:
if (char_handle_defined) {
serial_state = enable_notification;
sl_bt_gatt_set_characteristic_notification(connection_handler, char_handle, sl_bt_gatt_notification);
}
break;
case enable_notification:
serial_state = active;
break;
default:
break;
}
break;
// ----------
// This event indicates that a connection was closed.
case sl_bt_evt_connection_closed_id:
char_handle_defined=0;
service_discovered=0;
char_handle = 0xFFFF;
serial_state = idle;
break;
case sl_bt_evt_gatt_characteristic_value_id:
handle = evt->data.evt_gatt_characteristic_value.characteristic;
if (handle == char_handle) {
respData = evt->data.evt_gatt_characteristic_value.value.data;
respLen = evt->data.evt_gatt_characteristic_value.value.len;
sc = sl_iostream_write(sl_iostream_vcom_handle, respData, respLen);
sl_app_assert(sc == SL_STATUS_OK, "[E: 0x04x] iostream_write\r\n", (int)sc);
}
break;
}
return;
}
Вс мар 07, 2021 19:23:42
Вт мар 23, 2021 18:40:54
void sl_bt_process_event(sl_bt_msg_t *evt)
{
sl_bt_ota_dfu_on_event(evt);
sl_bt_beacon_on_event(evt);
sl_bt_on_event(evt);
}
Ср мар 24, 2021 07:56:21
void sl_bt_on_event(sl_bt_msg_t *evt)
{
sl_status_t sc;
serial_on_event(evt); // <- ВОТ ОНО
switch (SL_BT_MSG_ID(evt->header)) {
// ----------
// This event indicates the device has started and the radio is ready.
// Do not call any stack command before receiving this boot event!
case sl_bt_evt_system_boot_id:
printf("Client started\r\n");
sc = sl_bt_sm_configure(0x03,sm_io_capability_keyboarddisplay); // allow all connections
sl_app_assert(sc == SL_STATUS_OK, "[E: 0x%04x] sl_bt_sm_configure\n", (int)sc);
sc = sl_bt_sm_set_bondable_mode(1);
sl_app_assert(sc == SL_STATUS_OK, "[E: 0x%04x] sl_bt_sm_set_bondable_mode\n", (int)sc);
sc = sl_bt_scanner_set_timing(sl_bt_gap_1m_phy, 160, 160); // set scanning period 10ms
sl_app_assert(sc == SL_STATUS_OK, "[E: 0x%04x] sl_bt_scanner_set_timing\n", (int)sc);
sc = sl_bt_scanner_set_mode(sl_bt_gap_1m_phy, 1);
sl_app_assert(sc == SL_STATUS_OK, "[E: 0x%04x] sl_bt_scanner_set_mode\n", (int)sc);
// sl_bt_connection_set_parameters(connection, 80, 100, 0, 1000, 0, 0xffff);
sc = sl_bt_scanner_start(sl_bt_gap_1m_phy, sl_bt_scanner_discover_observation);
sl_app_assert(sc == SL_STATUS_OK, "[E: 0x%04x] sl_bt_scanner_start\n", (int)sc);
break;
Чт июл 15, 2021 20:50:59
Пт июл 16, 2021 21:36:52
кто должен вызывать функцию sl_bt_sm_increase_security клиент или сервер?
они всегда передаются как 16 бит и с двумя десятичными знаками за запятой или это может зависеть от дескрипторов?
Сб июл 17, 2021 06:16:48
Ммм, умнее не стал... Вроде в дескрипторах ничего такого найти не могу. Только точность, периодичность и диапазон. Но... вот запись чата с предыдущего воркшопа:Ser60 писал(а):В каком формате передаётся характеристика от дескрипторов вообще не зависит.
19:00:44 From Alvin Schatte to Everyone : If I wanted to format temperature in deg F, I would modify that value where you showed, but would the deg C in the display have to be changed in the EFR Connect app?
...
19:03:39 From Mike Glazebrook to Everyone : @Alvin, the Unit Attribute of the characteristic would need to be modified as well. This will let the phone know that the data is in C or F
Сб июл 17, 2021 06:52:14
Чт авг 05, 2021 20:55:08
Вс авг 08, 2021 21:36:35
Пн авг 09, 2021 15:11:31
Пн авг 09, 2021 19:08:32
Если речь идёт только о передаче температуры, оба решения некудышние. Держать соединение энергозатратно, т.к. максимальный интервал соединения 4 сек и при обращении к серверу с периодом 60 сек будет много пустых пакетов, на передачу и приём которых тратится энергия. Кроме того, велика вероятность разрыва соединения. Второе решение в этом плане лучше, но если база данных сервера (хендлы) не обновляется в процессе работы, лучше считать её один раз и держать на стороне клиента. Потом просто читать интересующую характеристику по хендлу. Если заранее известен UUID характеристики, то проще найти только её хендл один раз и потом использовать. А ещё лучше в плане потребления забить в клиент хендл интересующей характеристики и читать только её.Как лучше, с точки энергоэффективности сервера
Всё правильно и виновников много, в том числе внешних и неконтролируемых. BLE изначально не предназначен для постоянного соединения. Как известно периодически с периодом connection interval производится переход на другую частоту, и если на ней помеха, то создаётся угроза соединению. С этим можно бороться, поиграв с параметрами соединения (latency и timeout), или просто пересоединиться.я наблюдаю постоянную потерю соединения
Пн авг 09, 2021 21:15:19
Пн авг 09, 2021 22:50:14
В теории ДА, вопрос насколько. Тут всё зависит от временных параметров соединения и advertisement, а также от длины advertisement пакета. Типично, период advertisement можно установить 1 сек для уменьшения нагрузки на батарею, в то время как connection interval типично около 100мс. В дефолтном приложении сенсоров, залитых в демо-платы, оба периода раз в 10 меньше, и длина advertisement близка к максимальной. Поэтому потребление больше, чем следовало-бы. Если хотите питать серверы от CR-ки, лучше увеличить оба периода как я сказал (если бикон - то только один период) и сократить длину пакета до минимума.это тоже должно повышать расход энергии?
Да. В Студио есть демо-проект iBeacon, его можно взять за основу. Для примера код app.c моего бикона. Разрабатывал его давно, поэтому там встречаются depricated API. Для дальнейшего улучшения следовало-бы изменять имя только если текущее измерение отличается от прежнего.Beacon - это просто сервер который делает адвертисмент, но который non-connectable?
#include "sl_bluetooth.h"
#include "sl_app_assert.h"
#include "gatt_db.h"
#include "app.h"
#include "sl_i2cspm_instances.h"
#include "TMP112.h"
#include "LIS2DW12.h"
#define TIMER_ID_DYN 0
#define TIMER_ID_SEN 1
#define TIMER_ID_INIT 2
#define ACC_THRESH 50 // UP/DN threschold
#define MEASURE_PERIOD 15 // sensor period is seconds
typedef struct {
uint8_t flags_len; // Length of the Flags field.
uint8_t flags_type; // Type of the Flags field.
uint8_t flags; // Flags field.
uint8_t field_len; // Length of device name.
uint8_t field_type; // Device name (9).
char beacon_data[8];
} beacon_adv_data_t;
static void bcn_setup_adv_beaconing(void);
// The advertising set handle allocated from Bluetooth stack.
static uint8_t advertising_set_handle = 0xff;
int8_t zOut;
static beacon_adv_data_t beacon_adv_data;
SL_WEAK void app_init(void)
{
TMP112_init();
LIS2DW12_init();
}
SL_WEAK void app_process_action(void)
{
}
void sl_bt_on_event(sl_bt_msg_t *evt)
{
switch (SL_BT_MSG_ID(evt->header)) {
case sl_bt_evt_system_boot_id:
// Initialize iBeacon ADV data.
bcn_setup_adv_beaconing();
sl_bt_system_set_soft_timer(32768*MEASURE_PERIOD,TIMER_ID_DYN,0); // start software timer
sl_bt_system_set_soft_timer(32768,TIMER_ID_INIT,1);
break;
case sl_bt_evt_system_soft_timer_id:
switch (evt->data.evt_system_soft_timer.handle) {
case TIMER_ID_DYN:
sl_bt_system_set_soft_timer(3276,TIMER_ID_SEN,1);
TMP112_startConversion();
LIS2DW12_startMeas();
break;
case TIMER_ID_SEN:
TMP112_getTemp();
LIS2DW12_getData();
zOut = (ACC_data[6]<<4) + (ACC_data[5]>>4);
if (-ACC_THRESH <= zOut && zOut <= ACC_THRESH) {
beacon_adv_data.beacon_data[0] = 'D';
beacon_adv_data.beacon_data[1] = 'N';
}
else {
beacon_adv_data.beacon_data[0] = 'U';
beacon_adv_data.beacon_data[1] = 'P';
}
beacon_adv_data.beacon_data[3] = '+';
if (temp < 0) {
temp = -temp;
beacon_adv_data.beacon_data[3] = '-';
}
beacon_adv_data.beacon_data[4] = (temp / 10) + '0';
beacon_adv_data.beacon_data[5] = (temp % 10) + '0';
sl_bt_advertiser_set_data(advertising_set_handle, 0, sizeof(beacon_adv_data), (uint8_t *)(&beacon_adv_data));
break;
case TIMER_ID_INIT:
TMP112_init();
LIS2DW12_init();
break;
default:
break;
}
break;
default:
break;
}
}
static void bcn_setup_adv_beaconing(void)
{
int16_t ret_min, ret_max;
beacon_adv_data.flags_len = 2; // Field length
beacon_adv_data.flags_type = 0x01; // Field type
beacon_adv_data.flags = 0x04 | 0x02; // General Discoverable Mode, BR/EDR is disabled
beacon_adv_data.field_len = 9;
beacon_adv_data.field_type = 9; // Full device name
strncpy(beacon_adv_data.beacon_data, "DN +25*C", 8);
sl_bt_system_set_tx_power(0, 0, &ret_min, &ret_max);
// Create an advertising set.
sl_bt_advertiser_create_set(&advertising_set_handle);
// Set custom advertising data.
sl_bt_advertiser_set_data(advertising_set_handle, 0, sizeof(beacon_adv_data), (uint8_t *)(&beacon_adv_data));
// Set advertising parameters. 1000ms advertisement interval.
sl_bt_advertiser_set_timing(advertising_set_handle, 1600, 1600, 0, 0);
// Start advertising in user mode and disable connections.
sl_bt_advertiser_start(advertising_set_handle, advertiser_user_data, advertiser_non_connectable);
}
Чт авг 12, 2021 13:40:10
#include "em_common.h"
#include "sl_bluetooth.h"
#include "gatt_db.h"
#include "app.h"
// The advertising set handle allocated from Bluetooth stack.
static uint8_t advertising_set_handle = 0xff;
#define ADVERTISING_NAME "TB sensor"
#define ADVERTISING_NAME_SIZE 9
#define CIPHER_MSG_SIZE 2
typedef struct{
uint8_t flags_len; // 0 Length of the Flags field
uint8_t flags_type; // 1 Type of the Flags field
uint8_t flags; // 2 Flags
uint8_t name_len; // **3** Length of the Name field
uint8_t name_type; // Type of the Name field
uint8_t name[ADVERTISING_NAME_SIZE]; // Name
uint8_t manuf_len; // 4 Length of the Manufacturer ID field
uint8_t manuf_type; // 5 Type of the Manufacturer ID field
uint8_t company_LO; // 6 Manufacturer ID lower byte
uint8_t company_HI; // 7 Manufacturer ID higher byte
uint8_t adv_data[CIPHER_MSG_SIZE]; // 8 User data field
}custom_adv_t;
static custom_adv_t beacon_adv_data;
static uint8_t device_name[ADVERTISING_NAME_SIZE] = ADVERTISING_NAME;
static sl_sleeptimer_timer_handle_t timer_handle;
static unsigned int update_temp = 0;
void req_temperature(sl_sleeptimer_timer_handle_t *handle, void *data);
void ask_temperature(void);
/**************************************************************************//**
* Application Process Action.
*****************************************************************************/
SL_WEAK void app_process_action(void) {
if (update_temp) {
update_temp = 0;
ask_temperature();
}
}
void sl_bt_on_event(sl_bt_msg_t *evt) {
bd_addr address;
uint8_t address_type;
uint8_t system_id[8];
switch (SL_BT_MSG_ID(evt->header)) {
case sl_bt_evt_system_boot_id:
// Extract unique ID from BT Address.
sl_bt_system_get_identity_address(&address, &address_type);
// Pad and reverse unique ID to get System ID.
system_id[0] = address.addr[5];
system_id[1] = address.addr[4];
system_id[2] = address.addr[3];
system_id[3] = 0xFF;
system_id[4] = 0xFE;
system_id[5] = address.addr[2];
system_id[6] = address.addr[1];
system_id[7] = address.addr[0];
sl_bt_gatt_server_write_attribute_value(gattdb_system_id,
0,
sizeof(system_id),
system_id);
// Create an advertising set.
sl_bt_advertiser_create_set(&advertising_set_handle);
beacon_adv_data.flags_len = 0x02;
beacon_adv_data.flags_type = 0x01;
beacon_adv_data.flags = 0x04 | 0x02;
beacon_adv_data.name_len = ADVERTISING_NAME_SIZE+1;
beacon_adv_data.name_type = 0x09;
memcpy(beacon_adv_data.name, device_name, ADVERTISING_NAME_SIZE);
beacon_adv_data.manuf_len = 0x05;
beacon_adv_data.manuf_type = 0xFF;
beacon_adv_data.company_LO = 0xFF;
beacon_adv_data.company_HI = 0x02;
beacon_adv_data.adv_data[0]= 0x4d;
beacon_adv_data.adv_data[1]= 0x95;
sl_bt_advertiser_set_data(advertising_set_handle,
0,
sizeof(beacon_adv_data),
(uint8_t *)(&beacon_adv_data));
// Set advertising interval to 100ms.
sl_bt_advertiser_set_timing(
advertising_set_handle,
4000, // min. adv. interval (milliseconds * 1.6)
8000, // max. adv. interval (milliseconds * 1.6)
0, // adv. duration
0); // max. num. adv. events
sl_bt_advertiser_start(
advertising_set_handle,
advertiser_user_data,
advertiser_non_connectable);
sl_sleeptimer_start_periodic_timer_ms(&timer_handle, 60000, &req_temperature, NULL, 0, 0);
update_temp = 1;
break;
default:
break;
}
}
#include "sl_i2cspm_instances.h"
#include "sl_si70xx.h"
void req_temperature(sl_sleeptimer_timer_handle_t *handle, void *data) {
(void) data;
(void) handle;
update_temp = 1;
}
void ask_temperature(void) {
static int32_t temp_data, prev_temp_data = -27315;
static uint32_t rh_data;
sl_si70xx_measure_rh_and_temp(sl_i2cspm_sensor, SI7021_ADDR, &rh_data, &temp_data);
temp_data /= 10;
if (temp_data != prev_temp_data) {
prev_temp_data = temp_data;
beacon_adv_data.adv_data[0]= (temp_data & 0x00ff) >> 0;
beacon_adv_data.adv_data[1]= (temp_data & 0xff00) >> 8;
sl_bt_advertiser_set_data(advertising_set_handle,
0,
sizeof(beacon_adv_data),
(uint8_t *)(&beacon_adv_data));
}
}
Чт авг 12, 2021 18:54:16
Пн авг 16, 2021 13:18:42