KT24-1110_65E-HA-651B/apps/soundbox/smartbox/tuya/tuya_demo.c
2024-11-10 18:44:17 +08:00

1146 lines
34 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*********************************************************************************************
* 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