KT24-1110_65E-HA-651B/apps/soundbox/smartbox/tuya/tuya_demo.c

1146 lines
34 KiB
C
Raw Normal View History

2024-11-10 10:44:17 +00:00
/*********************************************************************************************
* Filename : tuya_demo.c
* Description :
* Author :
* Email : zh-jieli.com
* Last modifiled : 2017-01-17 11:14
* Copyright:(c)JIELI 2011-2016 @ , All Rights Reserved.
*********************************************************************************************/
// *****************************************************************************
/* EXAMPLE_START(le_counter): LE Peripheral - Heartbeat Counter over GATT
*
* @text All newer operating systems provide GATT Client functionality.
* The LE Counter examples demonstrates how to specify a minimal GATT Database
* with a custom GATT Service and a custom Characteristic that sends periodic
* notifications.
*/
// *****************************************************************************
#include "system/app_core.h"
#include "system/includes.h"
#include "app_config.h"
#include "app_action.h"
#include "btstack/btstack_task.h"
#include "btstack/bluetooth.h"
#include "user_cfg.h"
#include "vm.h"
#include "btcontroller_modules.h"
#include "bt_common.h"
#include "3th_profile_api.h"
#include "le_common.h"
#include "rcsp_bluetooth.h"
#include "JL_rcsp_api.h"
#include "custom_cfg.h"
#include "tuya_demo.h"
#include "tuya_ble_api.h"
#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_TUYA)
//TRANS ANCS
#define TRANS_ANCS_EN 0
#if TRANS_ANCS_EN
#include "btstack/btstack_event.h"
#endif
#define TEST_SEND_HANDLE_VAL ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE
/* #define TEST_SEND_HANDLE_VAL ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE */
#define EXT_ADV_MODE_EN 0
#define TEST_AUDIO_DATA_UPLOAD 0 //测试文件上传
#if 1//LE_DEBUG_PRINT_EN
extern void printf_buf(u8 *buf, u32 len);
/* #define log_info printf */
#define log_info(x, ...) printf("[tuya_demo]" x " ", ## __VA_ARGS__)
#define log_info_hexdump printf_buf
#else
#define log_info(...)
#define log_info_hexdump(...)
#endif
/* #define LOG_TAG_CONST BT_BLE */
/* #define LOG_TAG "[LE_S_DEMO]" */
/* #define LOG_ERROR_ENABLE */
/* #define LOG_DEBUG_ENABLE */
/* #define LOG_INFO_ENABLE */
/* #define LOG_DUMP_ENABLE */
/* #define LOG_CLI_ENABLE */
/* #include "debug.h" */
//------
//ATT发送的包长, note: 20 <=need >= MTU
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
#define ATT_LOCAL_MTU_SIZE (246) //
//ATT缓存的buffer大小, note: need >= 20,可修改
#define ATT_SEND_CBUF_SIZE (246) //
#else
#define ATT_LOCAL_MTU_SIZE (23) //
//ATT缓存的buffer大小, note: need >= 20,可修改
#define ATT_SEND_CBUF_SIZE (246) //
#endif
//共配置的RAM
#define ATT_RAM_BUFSIZE 2 * (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
//---------------
/*
使,使 att_server_flow_enable
使 att_server_flow_hold
:使READ/WRITE等命令方式
:ATT_WRITE_REQUEST = 0x12
*/
#define ATT_DATA_RECIEVT_FLOW 0//流控功能使能
//---------------
// 广播周期 (unit:0.625ms)
#define ADV_INTERVAL_MIN (160)
#define HOLD_LATENCY_CNT_MIN (3) //(0~0xffff)
#define HOLD_LATENCY_CNT_MAX (15) //(0~0xffff)
#define HOLD_LATENCY_CNT_ALL (0xffff)
static volatile hci_con_handle_t con_handle;
//加密设置
/* static const uint8_t sm_min_key_size = 7; */
//连接参数更新请求设置
//是否使能参数请求更新,0--disable, 1--enable
static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
//当前请求的参数表index
static uint8_t connection_update_cnt = 0; //
//参数表
static const struct conn_update_param_t connection_param_table[] = {
{16, 24, 10, 600},//11
{12, 28, 10, 600},//3.7
{8, 20, 10, 600},
/* {12, 28, 4, 600},//3.7 */
/* {12, 24, 30, 600},//3.05 */
};
//共可用的参数组数
#define CONN_PARAM_TABLE_CNT (sizeof(connection_param_table)/sizeof(struct conn_update_param_t))
#if (ATT_RAM_BUFSIZE < 64)
#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
#endif
//用户可配对的这是样机跟客户开发的app配对的秘钥
/* const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b}; */
#define EIR_TAG_STRING 0xd6, 0x05, 0x08, 0x00, 'J', 'L', 'A', 'I', 'S', 'D','K'
static const char user_tag_string[] = {EIR_TAG_STRING};
static u8 adv_data_len;
static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31
static u8 scan_rsp_data_len;
static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
/* #define adv_data &att_ram_buffer[0] */
/* #define scan_rsp_data &att_ram_buffer[32] */
static char gap_device_name[BT_NAME_LEN_MAX] = "jl_ble_test";
static u8 gap_device_name_len = 0; //名字长度,不包含结束符
static u8 ble_work_state = 0; //ble 状态变化
static u8 adv_ctrl_en; //广播控制
static u8 test_read_write_buf[4];
static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
static void (*ble_resume_send_wakeup)(void) = NULL;
static u32 channel_priv;
static int app_send_user_data_check(u16 len);
int tuya_app_send_user_data_do(void *priv, u8 *data, u16 len);
static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type);
// Complete Local Name 默认的蓝牙名字
//------------------------------------------------------
//广播参数设置
static void advertisements_setup_init();
static int set_adv_enable(void *priv, u32 en);
static int get_buffer_vaild_len(void *priv);
extern const char *bt_get_local_name();
extern void clr_wdt(void);
extern void sys_auto_shut_down_disable(void);
extern void sys_auto_shut_down_enable(void);
extern u8 get_total_connect_dev(void);
extern u8 JL_tuya_ble_gatt_receive_data(u8 *p_data, u16 len);
extern const uint8_t tuya_mac_addr[6];
//------------------------------------------------------
//NACS
#if TRANS_ANCS_EN
#define ANCS_SUBEVENT_CLIENT_NOTIFICATION 0xF1
void ancs_client_init(void);
void ancs_client_register_callback(btstack_packet_handler_t callback);
const char *ancs_client_attribute_name_for_id(int id);
void ancs_set_notification_buffer(u8 *buffer, u16 buffer_size);
//ancs info buffer
#define ANCS_INFO_BUFFER_SIZE (1024)
static u8 ancs_info_buffer[ANCS_INFO_BUFFER_SIZE];
#endif
//------------------------------------------------------
static void send_request_connect_parameter(u8 table_index)
{
struct conn_update_param_t *param = (void *)&connection_param_table[table_index];//static ram
log_info("update_request:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
if (con_handle) {
ble_op_conn_param_request(con_handle, param);
}
}
static void check_connetion_updata_deal(void)
{
if (connection_update_enable) {
if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
send_request_connect_parameter(connection_update_cnt);
}
}
}
static void connection_update_complete_success(u8 *packet)
{
int con_handle, conn_interval, conn_latency, conn_timeout;
con_handle = hci_subevent_le_connection_update_complete_get_connection_handle(packet);
conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
log_info("conn_interval = %d\n", conn_interval);
log_info("conn_latency = %d\n", conn_latency);
log_info("conn_timeout = %d\n", conn_timeout);
}
static void set_ble_work_state(ble_state_e state)
{
if (state != ble_work_state) {
log_info("ble_work_st:%x->%x\n", ble_work_state, state);
ble_work_state = state;
if (app_ble_state_callback) {
app_ble_state_callback((void *)channel_priv, state);
}
}
}
static ble_state_e get_ble_work_state(void)
{
return ble_work_state;
}
static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
sm_just_event_t *event = (void *)packet;
u32 tmp32;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
case SM_EVENT_JUST_WORKS_REQUEST:
sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
log_info("Just Works Confirmed.\n");
break;
case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
log_info_hexdump(packet, size);
memcpy(&tmp32, event->data, 4);
log_info("Passkey display: %06u.\n", tmp32);
break;
}
break;
}
}
static void can_send_now_wakeup(void)
{
/* putchar('E'); */
if (ble_resume_send_wakeup) {
ble_resume_send_wakeup();
}
}
static void ble_auto_shut_down_enable(u8 enable)
{
#if TCFG_AUTO_SHUT_DOWN_TIME
if (enable) {
if (get_total_connect_dev() == 0) { //已经没有设备连接
sys_auto_shut_down_enable();
}
} else {
sys_auto_shut_down_disable();
}
#endif
}
const char *const phy_result[] = {
"None",
"1M",
"2M",
"Coded",
};
static void set_connection_data_length(u16 tx_octets, u16 tx_time)
{
if (con_handle) {
ble_op_set_data_length(con_handle, tx_octets, tx_time);
}
}
static void set_connection_data_phy(u8 tx_phy, u8 rx_phy)
{
if (0 == con_handle) {
return;
}
u8 all_phys = 0;
u16 phy_options = CONN_SET_PHY_OPTIONS_S8;
ble_op_set_ext_phy(con_handle, all_phys, tx_phy, rx_phy, phy_options);
}
static void server_profile_start(u16 con_handle)
{
#if BT_FOR_APP_EN
set_app_connect_type(TYPE_BLE);
#endif
ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
set_ble_work_state(BLE_ST_CONNECT);
ble_auto_shut_down_enable(0);
/* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
}
_WEAK_
u8 ble_update_get_ready_jump_flag(void)
{
return 0;
}
/*
* @section Packet Handler
*
* @text The packet handler is used to:
* - stop the counter after a disconnect
* - send a notification when the requested ATT_EVENT_CAN_SEND_NOW is received
*/
/* LISTING_START(packetHandler): Packet Handler */
static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
int mtu;
u32 tmp;
u8 status;
const char *attribute_name;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
/* case DAEMON_EVENT_HCI_PACKET_SENT: */
/* break; */
case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
case ATT_EVENT_CAN_SEND_NOW:
can_send_now_wakeup();
break;
case HCI_EVENT_LE_META:
switch (hci_event_le_meta_get_subevent_code(packet)) {
case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE:
status = hci_subevent_le_enhanced_connection_complete_get_status(packet);
if (status) {
log_info("LE_SLAVE CONNECTION FAIL!!! %0x\n", status);
set_ble_work_state(BLE_ST_DISCONN);
break;
}
con_handle = hci_subevent_le_enhanced_connection_complete_get_connection_handle(packet);
log_info("HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE : %0x\n", con_handle);
log_info("conn_interval = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_interval(packet));
log_info("conn_latency = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_latency(packet));
log_info("conn_timeout = %d\n", hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(packet));
server_profile_start(con_handle);
break;
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE: %0x\n", con_handle);
connection_update_complete_success(packet + 8);
server_profile_start(con_handle);
log_info("ble remote rssi= %d\n", ble_vendor_get_peer_rssi(con_handle));
log_info("tuya_ble_connection_handler\n");
tuya_ble_connected_handler();
break;
case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
printf("HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE");
connection_update_complete_success(packet);
break;
case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE\n");
/* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
break;
case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
log_info("APP HCI_SUBEVENT_LE_PHY_UPDATE %s\n", hci_event_le_meta_get_phy_update_complete_status(packet) ? "Fail" : "Succ");
log_info("Tx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_tx_phy(packet)]);
log_info("Rx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_rx_phy(packet)]);
break;
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
con_handle = 0;
ble_op_att_send_init(con_handle, 0, 0, 0);
set_ble_work_state(BLE_ST_DISCONN);
connection_update_cnt = 0;
#if BT_FOR_APP_EN
set_app_connect_type(TYPE_NULL);
#endif
ble_auto_shut_down_enable(1);
log_info("tuya_ble_disconnection_handler\n");
tuya_ble_disconnected_handler();
extern void tuya_ble_adv_change(void);
tuya_ble_adv_change();
break;
case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
log_info("ATT MTU = %u\n", mtu);
ble_op_att_set_send_mtu(mtu);
/* set_connection_data_length(251, 2120); */
break;
case HCI_EVENT_VENDOR_REMOTE_TEST:
log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
break;
case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
tmp = little_endian_read_16(packet, 4);
log_info("-update_rsp: %02x\n", tmp);
if (tmp) {
connection_update_cnt++;
log_info("remoter reject!!!\n");
check_connetion_updata_deal();
} else {
connection_update_cnt = CONN_PARAM_TABLE_CNT;
}
break;
case HCI_EVENT_ENCRYPTION_CHANGE:
log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
break;
#if TRANS_ANCS_EN
case HCI_EVENT_ANCS_META:
switch (hci_event_ancs_meta_get_subevent_code(packet)) {
case ANCS_SUBEVENT_CLIENT_NOTIFICATION:
printf("ANCS_SUBEVENT_CLIENT_NOTIFICATION \n");
attribute_name = ancs_client_attribute_name_for_id(ancs_subevent_client_notification_get_attribute_id(packet));
if (!attribute_name) {
printf("ancs unknow attribute_id :%d \n", ancs_subevent_client_notification_get_attribute_id(packet));
break;
} else {
u16 attribute_strlen = little_endian_read_16(packet, 7);
u8 *attribute_str = (void *)little_endian_read_32(packet, 9);
printf("Notification: %s - %s \n", attribute_name, attribute_str);
}
break;
default:
break;
}
break;
#endif
}
break;
}
}
/* LISTING_END */
/*
* @section ATT Read
*
* @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
* att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
* with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
* See Listing attRead.
*/
/* LISTING_END */
/*
* @section ATT Write
*
* @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
* and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
* in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
*/
/* LISTING_START(attWrite): ATT Write */
static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
{
int result = 0;
u16 tmp16;
u8 *tmp_buf = NULL;
u16 handle = att_handle;
//log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
//put_buf(buffer, buffer_size);
switch (handle) {
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x03)
case ATT_CHARACTERISTIC_2b10_01_CLIENT_CONFIGURATION_HANDLE:
set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
check_connetion_updata_deal();
printf("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
att_set_ccc_config(handle, buffer[0]);
break;
case ATT_CHARACTERISTIC_2b11_01_VALUE_HANDLE:
printf("TUYA msg receive, handle = 0x%x, size = %d\n", handle, buffer_size);
JL_tuya_ble_gatt_receive_data(buffer, buffer_size);
break;
#endif
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
case ATT_CHARACTERISTIC_00000002_0000_1001_8001_00805F9B07D0_01_CLIENT_CONFIGURATION_HANDLE:
set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
check_connetion_updata_deal();
printf("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
att_set_ccc_config(handle, buffer[0]);
break;
case ATT_CHARACTERISTIC_00000001_0000_1001_8001_00805F9B07D0_01_VALUE_HANDLE:
printf("\nTUYA msg receive, handle = 0x%x, size = %d\n", handle, buffer_size);
JL_tuya_ble_gatt_receive_data(buffer, buffer_size);
break;
case ATT_CHARACTERISTIC_00000003_0000_1001_8001_00805F9B07D0_01_VALUE_HANDLE:
printf("\nTUYA read msg, handle = 0x%x, size = %d\n", handle, buffer_size);
put_buf(buffer, buffer_size);
break;
#endif
default:
printf("\n\nunknow handle:%d\n\n", handle);
break;
}
return 0;
}
static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type)
{
u32 ret = APP_BLE_NO_ERROR;
if (!con_handle) {
return APP_BLE_OPERATION_ERROR;
}
if (!att_get_ccc_config(handle + 1)) {
log_info("fail,no write ccc!!!,%04x\n", handle + 1);
return APP_BLE_NO_WRITE_CCC;
}
ret = ble_op_att_send_data(handle, data, len, handle_type);
if (ret == BLE_BUFFER_FULL) {
ret = APP_BLE_BUFF_FULL;
}
if (ret) {
log_info("app_send_fail:%d !!!!!!\n", ret);
}
return ret;
}
//------------------------------------------------------
static int make_set_adv_data(void)
{
u8 offset = 0;
u8 *buf = adv_data;
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x03)
u8 service_data[11] = {0x01, 0xA2, 0x00, 0x65, 0x36, 0x6A, 0x6C, 0x6C, 0x70, 0x79, 0x37};
offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_MORE_16BIT_SERVICE_UUIDS, 0xA201, 2);
offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_SERVICE_DATA, (void *)service_data, 11);
#endif
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
u8 service_data[22] = {0x50, 0XFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 1);
offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_MORE_16BIT_SERVICE_UUIDS, 0x50FD, 2);
offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_SERVICE_DATA, (void *)service_data, 22);
#endif
if (offset > ADV_RSP_PACKET_MAX) {
puts("***adv_data overflow!!!!!!\n");
return -1;
}
log_info("adv_data(%d):", offset);
log_info_hexdump(buf, offset);
adv_data_len = offset;
ble_op_set_adv_data(offset, buf);
return 0;
}
static int make_set_rsp_data(void)
{
u8 offset = 0;
u8 *buf = scan_rsp_data;
u8 name_len = gap_device_name_len;
u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
if (name_len > vaild_len) {
name_len = vaild_len;
}
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x03)
u8 ble_specific_data[24] = {0xD0, 0x07, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x38, 0xD1, 0x4B, 0xE7, 0xF3, 0x61, 0xB8, 0xB3, 0xFA, 0x4E, 0x8C, 0x70, 0xD5, 0xEB, 0x25, 0x7E};
offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, 0x5954, 2);
offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)ble_specific_data, 24);
#endif
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
u8 ble_specific_data[22] = {0xD0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, 0x5954, 2);
offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)ble_specific_data, 24);
#endif
if (offset > ADV_RSP_PACKET_MAX) {
puts("***rsp_data overflow!!!!!!\n");
return -1;
}
log_info("rsp_data(%d):", offset);
log_info_hexdump(buf, offset);
scan_rsp_data_len = offset;
ble_op_set_rsp_data(offset, buf);
return 0;
}
//广播参数设置
static void advertisements_setup_init()
{
uint8_t adv_type = ADV_IND;
uint8_t adv_channel = ADV_CHANNEL_ALL;
int ret = 0;
ble_op_set_adv_param(ADV_INTERVAL_MIN, adv_type, adv_channel);
ret |= make_set_adv_data();
ret |= make_set_rsp_data();
if (ret) {
puts("advertisements_setup_init fail !!!!!!\n");
return;
}
}
#define PASSKEY_ENTER_ENABLE 0 //输入passkey使能可修改passkey
//重设passkey回调函数在这里可以重新设置passkey
//passkey为6个数字组成十万位、万位。。。。个位 各表示一个数字 高位不够为0
static void reset_passkey_cb(u32 *key)
{
#if 1
u32 newkey = rand32();//获取随机数
newkey &= 0xfffff;
if (newkey > 999999) {
newkey = newkey - 999999; //不能大于999999
}
*key = newkey; //小于或等于六位数
printf("set new_key= %06u\n", *key);
#else
*key = 123456; //for debug
#endif
}
void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
{
//setup SM: Display only
sm_init();
sm_set_io_capabilities(io_type);
sm_set_authentication_requirements(auth_req);
sm_set_encryption_key_size_range(min_key_size, 16);
sm_set_request_security(security_en);
sm_event_callback_set(&cbk_sm_packet_handler);
if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
reset_PK_cb_register(reset_passkey_cb);
}
}
void ble_profile_init(void)
{
printf("TUYA ble profile init\n");
le_device_db_init();
#if PASSKEY_ENTER_ENABLE
ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_MITM_PROTECTION, 7, TCFG_BLE_SECURITY_EN);
#else
/* ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_BONDING, 7, TCFG_BLE_SECURITY_EN); */
ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_BONDING, 7, 0);
#endif
/* setup ATT server */
att_server_init(profile_data, NULL, att_write_callback);
att_server_register_packet_handler(cbk_packet_handler);
/* gatt_client_register_packet_handler(packet_cbk); */
// register for HCI events
hci_event_callback_set(&cbk_packet_handler);
/* ble_l2cap_register_packet_handler(packet_cbk); */
/* sm_event_packet_handler_register(packet_cbk); */
le_l2cap_register_packet_handler(&cbk_packet_handler);
#if TRANS_ANCS_EN
//setup GATT client
gatt_client_init();
//setup ANCS clent
ancs_client_init();
ancs_set_notification_buffer(ancs_info_buffer, sizeof(ancs_info_buffer));
ancs_client_register_callback(&cbk_packet_handler);
#endif
extern u16 ble_vendor_set_default_att_mtu(u16 mtu_size);
ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
}
#if EXT_ADV_MODE_EN
#define EXT_ADV_NAME 'J', 'L', '_', 'E', 'X', 'T', '_', 'A', 'D', 'V'
/* #define EXT_ADV_NAME "JL_EXT_ADV" */
#define BYTE_LEN(x...) sizeof((u8 []) {x})
#define EXT_ADV_DATA \
0x02, 0x01, 0x06, \
0x03, 0x02, 0xF0, 0xFF, \
BYTE_LEN(EXT_ADV_NAME) + 1, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, EXT_ADV_NAME
struct ext_advertising_param {
u8 Advertising_Handle;
u16 Advertising_Event_Properties;
u8 Primary_Advertising_Interval_Min[3];
u8 Primary_Advertising_Interval_Max[3];
u8 Primary_Advertising_Channel_Map;
u8 Own_Address_Type;
u8 Peer_Address_Type;
u8 Peer_Address[6];
u8 Advertising_Filter_Policy;
u8 Advertising_Tx_Power;
u8 Primary_Advertising_PHY;
u8 Secondary_Advertising_Max_Skip;
u8 Secondary_Advertising_PHY;
u8 Advertising_SID;
u8 Scan_Request_Notification_Enable;
} _GNU_PACKED_;
struct ext_advertising_data {
u8 Advertising_Handle;
u8 Operation;
u8 Fragment_Preference;
u8 Advertising_Data_Length;
u8 Advertising_Data[BYTE_LEN(EXT_ADV_DATA)];
} _GNU_PACKED_;
struct ext_advertising_enable {
u8 Enable;
u8 Number_of_Sets;
u8 Advertising_Handle;
u16 Duration;
u8 Max_Extended_Advertising_Events;
} _GNU_PACKED_;
const struct ext_advertising_param ext_adv_param = {
.Advertising_Handle = 0,
.Advertising_Event_Properties = 1,
.Primary_Advertising_Interval_Min = {30, 0, 0},
.Primary_Advertising_Interval_Max = {30, 0, 0},
.Primary_Advertising_Channel_Map = 7,
.Primary_Advertising_PHY = ADV_SET_1M_PHY,
.Secondary_Advertising_PHY = ADV_SET_1M_PHY,
};
const struct ext_advertising_data ext_adv_data = {
.Advertising_Handle = 0,
.Operation = 3,
.Fragment_Preference = 0,
.Advertising_Data_Length = BYTE_LEN(EXT_ADV_DATA),
.Advertising_Data = EXT_ADV_DATA,
};
const struct ext_advertising_enable ext_adv_enable = {
.Enable = 1,
.Number_of_Sets = 1,
.Advertising_Handle = 0,
.Duration = 0,
.Max_Extended_Advertising_Events = 0,
};
const struct ext_advertising_enable ext_adv_disable = {
.Enable = 0,
.Number_of_Sets = 1,
.Advertising_Handle = 0,
.Duration = 0,
.Max_Extended_Advertising_Events = 0,
};
#endif /* EXT_ADV_MODE_EN */
void tuya_set_adv_enable()
{
if (con_handle) {
printf("connect is exist return\n");
return;
}
if (!adv_ctrl_en) {
printf("!adv_ctrl_en return\n");
return;
}
ble_op_adv_enable(1);
}
static int set_adv_enable(void *priv, u32 en)
{
ble_state_e next_state, cur_state;
if (!adv_ctrl_en) {
return APP_BLE_OPERATION_ERROR;
}
if (con_handle) {
return APP_BLE_OPERATION_ERROR;
}
if (en) {
next_state = BLE_ST_ADV;
} else {
next_state = BLE_ST_IDLE;
}
cur_state = get_ble_work_state();
switch (cur_state) {
case BLE_ST_ADV:
case BLE_ST_IDLE:
case BLE_ST_INIT_OK:
case BLE_ST_NULL:
case BLE_ST_DISCONN:
break;
default:
return APP_BLE_OPERATION_ERROR;
break;
}
if (cur_state == next_state) {
return APP_BLE_NO_ERROR;
}
log_info("adv_en:%d\n", en);
set_ble_work_state(next_state);
#if EXT_ADV_MODE_EN
if (en) {
ble_op_set_ext_adv_param(&ext_adv_param, sizeof(ext_adv_param));
log_info_hexdump(&ext_adv_data, sizeof(ext_adv_data));
ble_op_set_ext_adv_data(&ext_adv_data, sizeof(ext_adv_data));
ble_op_set_ext_adv_enable(&ext_adv_enable, sizeof(ext_adv_enable));
} else {
ble_op_set_ext_adv_enable(&ext_adv_disable, sizeof(ext_adv_disable));
}
#else
if (en) {
advertisements_setup_init();
}
ble_op_adv_enable(en);
#endif /* EXT_ADV_MODE_EN */
return APP_BLE_NO_ERROR;
}
static int ble_disconnect(void *priv)
{
if (con_handle) {
if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
log_info(">>>tuya ble send disconnect\n");
set_ble_work_state(BLE_ST_SEND_DISCONN);
ble_op_disconnect(con_handle);
} else {
log_info(">>>tuya ble wait disconnect...\n");
}
return APP_BLE_NO_ERROR;
} else {
return APP_BLE_OPERATION_ERROR;
}
}
static int get_buffer_vaild_len(void *priv)
{
u32 vaild_len = 0;
ble_op_att_get_remain(&vaild_len);
return vaild_len;
}
int tuya_app_send_user_data_do(void *priv, u8 *data, u16 len)
{
#if PRINT_DMA_DATA_EN
if (len < 128) {
log_info("-le_tx(%d):");
log_info_hexdump(data, len);
} else {
putchar('L');
}
#endif
att_set_ccc_config(ATT_CHARACTERISTIC_00000002_0000_1001_8001_00805F9B07D0_01_VALUE_HANDLE + 1, ATT_OP_NOTIFY);
return app_send_user_data(ATT_CHARACTERISTIC_00000002_0000_1001_8001_00805F9B07D0_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
return 0;
//return app_send_user_data(ATT_CHARACTERISTIC_2b10_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
}
static int app_send_user_data_check(u16 len)
{
u32 buf_space = get_buffer_vaild_len(0);
if (len <= buf_space) {
return 1;
}
return 0;
}
static int regiest_wakeup_send(void *priv, void *cbk)
{
ble_resume_send_wakeup = cbk;
return APP_BLE_NO_ERROR;
}
static int regiest_recieve_cbk(void *priv, void *cbk)
{
channel_priv = (u32)priv;
app_recieve_callback = cbk;
return APP_BLE_NO_ERROR;
}
static int regiest_state_cbk(void *priv, void *cbk)
{
channel_priv = (u32)priv;
app_ble_state_callback = cbk;
return APP_BLE_NO_ERROR;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
u8 *ble_get_scan_rsp_ptr(u16 *len)
{
if (len) {
*len = scan_rsp_data_len;
}
return scan_rsp_data;
}
u8 *ble_get_adv_data_ptr(u16 *len)
{
if (len) {
*len = adv_data_len;
}
return adv_data;
}
u8 *ble_get_gatt_profile_data(u16 *len)
{
*len = sizeof(profile_data);
return (u8 *)profile_data;
}
void bt_ble_adv_enable(u8 enable)
{
set_adv_enable(0, enable);
}
u16 bt_ble_is_connected(void)
{
return con_handle;
}
void ble_module_enable(u8 en)
{
if (en) {
adv_ctrl_en = 1;
bt_ble_adv_enable(1);
} else {
if (con_handle) {
adv_ctrl_en = 0;
ble_disconnect(NULL);
} else {
bt_ble_adv_enable(0);
adv_ctrl_en = 0;
}
}
}
//流控使能 EN: 1-停止收数 or 0-继续收数
int ble_trans_flow_enable(u8 en)
{
int ret = -1;
#if ATT_DATA_RECIEVT_FLOW
if (con_handle) {
att_server_flow_hold(con_handle, en);
ret = 0;
}
#endif
log_info("ble_trans_flow_enable:%d,%d\n", en, ret);
return ret;
}
//for test
static void timer_trans_flow_test(void)
{
static u8 sw = 0;
if (con_handle) {
sw = !sw;
ble_trans_flow_enable(sw);
}
}
static const char ble_ext_name[] = "(BLE)";
int tuya_app_send_user_data(u8 *data, u16 len)
{
int ret = 0;
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x03)
att_set_ccc_config(ATT_CHARACTERISTIC_2b10_01_VALUE_HANDLE + 1, ATT_OP_NOTIFY);
ret = app_send_user_data(ATT_CHARACTERISTIC_2b10_01_VALUE_HANDLE, data, len, ATT_OP_NOTIFY);
#endif
#if (TUYA_BLE_PROTOCOL_VERSION_HIGN == 0x04)
att_set_ccc_config(ATT_CHARACTERISTIC_00000002_0000_1001_8001_00805F9B07D0_01_VALUE_HANDLE + 1, ATT_OP_NOTIFY);
ret = app_send_user_data(ATT_CHARACTERISTIC_00000002_0000_1001_8001_00805F9B07D0_01_VALUE_HANDLE, data, len, ATT_OP_NOTIFY);
#endif
printf("tuya_send_user_data: %d, len = %d\n", ret, len);
put_buf(data, len);
return ret ;
}
void bt_ble_init(void)
{
le_controller_set_mac((void *)tuya_mac_addr);
log_info("***** ble_init******\n");
char *name_p;
#if DOUBLE_BT_SAME_NAME
u8 ext_name_len = 0;
#else
u8 ext_name_len = sizeof(ble_ext_name) - 1;
#endif
name_p = bt_get_local_name();
gap_device_name_len = strlen(name_p);
if (gap_device_name_len > BT_NAME_LEN_MAX - ext_name_len) {
gap_device_name_len = BT_NAME_LEN_MAX - ext_name_len;
}
memcpy(gap_device_name, name_p, gap_device_name_len);
#if DOUBLE_BT_SAME_NAME == 0
//增加后缀,区分名字
memcpy(&gap_device_name[gap_device_name_len], "(BLE)", ext_name_len);
gap_device_name_len += ext_name_len;
#endif
log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
#if ATT_DATA_RECIEVT_FLOW
log_info("att_server_flow_enable\n");
att_server_flow_enable(1);
/* sys_timer_add(0, timer_trans_flow_test, 3000); */
#endif
set_ble_work_state(BLE_ST_INIT_OK);
ble_module_enable(1);
extern void tuya_ble_app_init();
tuya_ble_app_init();
}
void bt_ble_exit(void)
{
log_info("***** ble_exit******\n");
}
void ble_app_disconnect(void)
{
ble_disconnect(NULL);
}
static const struct ble_server_operation_t mi_ble_operation = {
.adv_enable = set_adv_enable,
.disconnect = ble_disconnect,
.get_buffer_vaild = get_buffer_vaild_len,
.send_data = (void *)tuya_app_send_user_data_do,
.regist_wakeup_send = regiest_wakeup_send,
.regist_recieve_cbk = regiest_recieve_cbk,
.regist_state_cbk = regiest_state_cbk,
};
void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt)
{
*interface_pt = (void *)&mi_ble_operation;
}
void ble_server_send_test_key_num(u8 key_num)
{
;
}
#endif