952 lines
30 KiB
C
952 lines
30 KiB
C
/*********************************************************************************************
|
||
* Filename : le_server_module.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 "event/net_event.h"
|
||
#include "app_config.h"
|
||
|
||
#include "btstack/btstack_task.h"
|
||
#include "btstack/bluetooth.h"
|
||
#include "btcontroller_modules.h"
|
||
#include "bt_common.h"
|
||
#include "system/wait.h"
|
||
#include "third_party/common/ble_user.h"
|
||
#include "le_net_cfg.h"
|
||
#include "le_common.h"
|
||
|
||
#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_NET_CFG)
|
||
|
||
#define TEST_SEND_HANDLE_VAL ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE
|
||
|
||
#if 1
|
||
extern void printf_buf(u8 *buf, u32 len);
|
||
#define log_info printf
|
||
#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" */
|
||
|
||
//------
|
||
#define ATT_LOCAL_PAYLOAD_SIZE (128) //note: need >= 20
|
||
#define ATT_SEND_CBUF_SIZE (512) //note: need >= 20,缓存大小,可修改
|
||
#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_PAYLOAD_SIZE + ATT_SEND_CBUF_SIZE) //note:
|
||
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
|
||
//---------------
|
||
|
||
//---------------
|
||
#define ADV_INTERVAL_MIN (160)
|
||
|
||
static volatile hci_con_handle_t con_handle;
|
||
static void ble_module_enable(u8 en);
|
||
|
||
//连接参数设置
|
||
static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
|
||
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))
|
||
|
||
// 广播包内容
|
||
/* static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31 */
|
||
// scan_rsp 内容
|
||
/* static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31 */
|
||
|
||
#if (ATT_RAM_BUFSIZE < 64)
|
||
#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
|
||
#endif
|
||
|
||
#define adv_data &att_ram_buffer[0]
|
||
#define scan_rsp_data &att_ram_buffer[32]
|
||
|
||
static char gap_device_name[BT_NAME_LEN_MAX] = "wl80_ble_test";
|
||
static u8 complete = 0;
|
||
static u8 gap_device_name_len = 0;
|
||
static u8 ble_work_state = 0;
|
||
static u8 adv_ctrl_en;
|
||
static OS_MUTEX mutex;
|
||
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);
|
||
static int app_send_user_data_do(void *priv, u8 *data, u16 len);
|
||
static int app_send_user_data(u16 handle, const u8 *data, u16 len, u8 handle_type);
|
||
extern u8 is_in_config_network_state(void);
|
||
|
||
// Complete Local Name 默认的蓝牙名字
|
||
extern const char *bt_get_local_name();
|
||
|
||
//配网成回复命令
|
||
static const u8 rsp_cmd0[] = {
|
||
0x4A, 0x4C, 0x00, 0x0e, 0x10, 0x02,
|
||
'{', '"', 's', 't', 'a', 't', 'u', 's', '"', ':', '0', '}',
|
||
0x7C, 0xC3, 0xFF,
|
||
};
|
||
|
||
//正在配网回复命令
|
||
static const u8 rsp_cmd1[] = {
|
||
0x4A, 0x4C, 0x00, 0x0e, 0x10, 0x02,
|
||
'{', '"', 's', 't', 'a', 't', 'u', 's', '"', ':', '1', '}',
|
||
0x4F, 0xF2, 0xFF,
|
||
};
|
||
|
||
//配网失败回复命令
|
||
static const u8 rsp_cmd2[] = {
|
||
0x4A, 0x4C, 0x00, 0x0e, 0x10, 0x02,
|
||
'{', '"', 's', 't', 'a', 't', 'u', 's', '"', ':', '2', '}',
|
||
0x1A, 0xA1, 0xFF,
|
||
};
|
||
|
||
//未找到ssid回复命令
|
||
static const u8 rsp_cmd3[] = {
|
||
0x4A, 0x4C, 0x00, 0x0e, 0x10, 0x02,
|
||
'{', '"', 's', 't', 'a', 't', 'u', 's', '"', ':', '3', '}',
|
||
0x29, 0x90, 0xFF,
|
||
};
|
||
|
||
//密码错误回复命令
|
||
static const u8 rsp_cmd4[] = {
|
||
0x4A, 0x4C, 0x00, 0x0e, 0x10, 0x02,
|
||
'{', '"', 's', 't', 'a', 't', 'u', 's', '"', ':', '4', '}',
|
||
0xB0, 0x07, 0xFF,
|
||
};
|
||
|
||
//------------------------------------------------------
|
||
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_user_cmd_prepare(BLE_CMD_REQ_CONN_PARAM_UPDATE, 2, 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 const char *const phy_result[] = {
|
||
"None",
|
||
"1M",
|
||
"2M",
|
||
"Coded",
|
||
};
|
||
|
||
static void server_profile_start(u16 con_handle)
|
||
{
|
||
ble_user_cmd_prepare(BLE_CMD_ATT_SEND_INIT, 4, con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_PAYLOAD_SIZE);
|
||
set_ble_work_state(BLE_ST_CONNECT);
|
||
/* set_connection_data_phy(CONN_SET_CODED_PHY, CONN_SET_CODED_PHY); */
|
||
}
|
||
|
||
/*
|
||
* @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;
|
||
|
||
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);
|
||
break;
|
||
|
||
case 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_user_cmd_prepare(BLE_CMD_ATT_SEND_INIT, 4, con_handle, 0, 0, 0);
|
||
set_ble_work_state(BLE_ST_DISCONN);
|
||
#if !CONFIG_POWER_ON_ENABLE_BLE
|
||
if (is_in_config_network_state()) {
|
||
#else
|
||
{
|
||
#endif
|
||
os_mutex_pend(&mutex, 0);
|
||
bt_ble_adv_enable(1);
|
||
complete = 0;
|
||
os_mutex_post(&mutex);
|
||
}
|
||
connection_update_cnt = 0;
|
||
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_user_cmd_prepare(BLE_CMD_ATT_MTU_SIZE, 1, mtu);
|
||
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;
|
||
}
|
||
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_START(attRead): ATT Read */
|
||
|
||
// ATT Client Read Callback for Dynamic Data
|
||
// - if buffer == NULL, don't copy data, just return size of value
|
||
// - if buffer != NULL, copy data and return number bytes copied
|
||
// @param offset defines start of attribute value
|
||
static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
|
||
{
|
||
uint16_t att_value_len = 0;
|
||
uint16_t handle = att_handle;
|
||
|
||
log_info("read_callback, handle= 0x%04x,buffer= %08x\n", handle, (u32)buffer);
|
||
|
||
switch (handle) {
|
||
case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
|
||
att_value_len = gap_device_name_len;
|
||
|
||
if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
|
||
break;
|
||
}
|
||
|
||
if (buffer) {
|
||
memcpy(buffer, &gap_device_name[offset], buffer_size);
|
||
att_value_len = buffer_size;
|
||
log_info("\n------read gap_name: %s \n", gap_device_name);
|
||
}
|
||
break;
|
||
|
||
case ATT_CHARACTERISTIC_ae82_01_CLIENT_CONFIGURATION_HANDLE:
|
||
if (buffer) {
|
||
buffer[0] = att_get_ccc_config(handle);
|
||
buffer[1] = 0;
|
||
}
|
||
att_value_len = 2;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
log_info("att_value_len= %d\n", att_value_len);
|
||
return att_value_len;
|
||
}
|
||
|
||
static u16 user_buf_offset = 0, user_data_size = 0;
|
||
static u8 user_buf[128];
|
||
extern int get_page_turning_profile(char *username, char *password);
|
||
extern int get_payment_bind_msg(char *uuid, char *clientid, char *bind_token);
|
||
|
||
static int check_profile(void)
|
||
{
|
||
char username[64] = {0}, clientid[64] = {0}, bind_token[64] = {0};
|
||
if (get_page_turning_profile(username, NULL)) {
|
||
return false;
|
||
}
|
||
if (get_payment_bind_msg(NULL, clientid, bind_token)) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static void check_net_info_if_recv_complete(void)
|
||
{
|
||
if (user_buf[user_buf_offset - 1] == 0xFF && user_buf_offset == user_data_size + 7) {
|
||
user_buf[sizeof(user_buf) - 1] = 0;
|
||
extern int bt_net_config_set_ssid_pwd(const char *data);
|
||
extern u16 CRC16(const void *ptr, u32 len);
|
||
u16 crc16 = user_buf[user_buf_offset - 2] + (user_buf[user_buf_offset - 3] << 8);
|
||
put_buf(&user_buf[2], user_data_size + 2);
|
||
if (crc16 == CRC16(&user_buf[2], user_data_size + 2)) {
|
||
//去掉2byte crc 1byte 结束符
|
||
user_buf[user_buf_offset - 3] = 0;
|
||
if (0 == bt_net_config_set_ssid_pwd((const char *)&user_buf[6])) {
|
||
app_send_user_data(ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE, rsp_cmd1, sizeof(rsp_cmd1), ATT_OP_AUTO_READ_CCC);
|
||
complete = 1;
|
||
user_buf_offset = 0;
|
||
user_data_size = 0;
|
||
memset(user_buf, 0, sizeof(user_buf));
|
||
}
|
||
} else {
|
||
app_send_user_data(ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE, rsp_cmd2, sizeof(rsp_cmd2), ATT_OP_AUTO_READ_CCC);
|
||
user_buf_offset = 0;
|
||
user_data_size = 0;
|
||
memset(user_buf, 0, sizeof(user_buf));
|
||
}
|
||
}
|
||
}
|
||
|
||
static int payment_msg_send(void *priv)
|
||
{
|
||
char username[64] = {0}, clientid[64] = {0}, bind_token[64] = {0};
|
||
u16 len;
|
||
u8 msg_cmd[128] = {0};
|
||
char tmp_buf[256] = {0};
|
||
|
||
get_page_turning_profile(username, NULL);
|
||
get_payment_bind_msg(NULL, clientid, bind_token);
|
||
|
||
sprintf(tmp_buf, "{\"clientid\":\"%s\",\"username\":\"%s\",\"bind_token\":\"%s\"}", clientid, username, bind_token);
|
||
len = strlen(tmp_buf) + 2;
|
||
strcpy((char *)msg_cmd, "JL");
|
||
msg_cmd[2] = (u8)len >> 8;
|
||
msg_cmd[3] = (u8)len;
|
||
msg_cmd[4] = 0x10;
|
||
msg_cmd[5] = 0x04;
|
||
strcpy((char *)&msg_cmd[6], tmp_buf);
|
||
extern u16 CRC16(const void *ptr, u32 len);
|
||
u16 crc16 = CRC16(&msg_cmd[2], len + 2);
|
||
msg_cmd[len + 4] = crc16 >> 8;
|
||
msg_cmd[len + 5] = crc16;
|
||
msg_cmd[6 + len] = 0xff;
|
||
put_buf(msg_cmd, len + 7);
|
||
app_send_user_data(ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE, msg_cmd, len + 7, ATT_OP_AUTO_READ_CCC);
|
||
sys_timeout_add(0, (void (*)(void *))ble_module_enable, 100);
|
||
return 0;
|
||
}
|
||
|
||
/* 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;
|
||
u16 handle = att_handle;
|
||
log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
|
||
|
||
switch (handle) {
|
||
|
||
case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
|
||
break;
|
||
|
||
case ATT_CHARACTERISTIC_ae82_01_CLIENT_CONFIGURATION_HANDLE:
|
||
set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
|
||
check_connetion_updata_deal();
|
||
log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
|
||
att_set_ccc_config(handle, buffer[0]);
|
||
user_buf_offset = 0;
|
||
user_data_size = 0;
|
||
memset(user_buf, 0, sizeof(user_buf));
|
||
complete = 0;
|
||
break;
|
||
|
||
case ATT_CHARACTERISTIC_ae81_01_VALUE_HANDLE:
|
||
printf("\n-ae81_rx(%d):", buffer_size);
|
||
printf_buf(buffer, buffer_size);
|
||
|
||
if (!user_buf_offset) {
|
||
if (buffer[0] == 'J' && buffer[1] == 'L' && buffer[4] == 0x10 && buffer[5] == 0x01) {
|
||
user_data_size = (buffer[2] << 8) + buffer[3];
|
||
user_buf_offset += buffer_size;
|
||
if (buffer_size < sizeof(user_buf) && user_data_size < 32 + 64 + 24) {
|
||
memcpy(user_buf, buffer, buffer_size);
|
||
check_net_info_if_recv_complete();
|
||
break;
|
||
}
|
||
}
|
||
//////////
|
||
#if (defined PAYMENT_AUDIO_SDK_ENABLE)
|
||
if (buffer[0] == 'J' && buffer[1] == 'L' && buffer[4] == 0x10 && buffer[5] == 0x03) {
|
||
user_data_size = (buffer[2] << 8) + buffer[3];
|
||
if (user_data_size == 4) {
|
||
wait_completion(check_profile, payment_msg_send, NULL, NULL);
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
///////////
|
||
} else {
|
||
if (user_buf_offset + buffer_size < sizeof(user_buf)) {
|
||
memcpy(user_buf + user_buf_offset, buffer, buffer_size);
|
||
user_buf_offset += buffer_size;
|
||
if (user_buf_offset < user_data_size + 7) {
|
||
break;
|
||
}
|
||
check_net_info_if_recv_complete();
|
||
break;
|
||
}
|
||
}
|
||
|
||
puts("error : bt net config fail !!!\n");
|
||
|
||
user_buf_offset = 0;
|
||
user_data_size = 0;
|
||
memset(user_buf, 0, sizeof(user_buf));
|
||
app_send_user_data(ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE, rsp_cmd2, sizeof(rsp_cmd2), ATT_OP_AUTO_READ_CCC);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int app_send_user_data(u16 handle, const u8 *data, u16 len, u8 handle_type)
|
||
{
|
||
u32 ret = APP_BLE_NO_ERROR;
|
||
|
||
if (!con_handle) {
|
||
return APP_BLE_OPERATION_ERROR;
|
||
}
|
||
|
||
os_mutex_pend(&mutex, 0);
|
||
|
||
if (!att_get_ccc_config(handle + 1)) {
|
||
log_info("fail,no write ccc!!!,%04x\n", handle + 1);
|
||
os_mutex_post(&mutex);
|
||
return APP_BLE_NO_WRITE_CCC;
|
||
}
|
||
|
||
ret = ble_user_cmd_prepare(BLE_CMD_ATT_SEND_DATA, 4, handle, data, len, handle_type);
|
||
if (ret == BLE_BUFFER_FULL) {
|
||
ret = APP_BLE_BUFF_FULL;
|
||
}
|
||
|
||
os_mutex_post(&mutex);
|
||
|
||
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;
|
||
|
||
/* offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x18, 1); */
|
||
/* offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x1A, 1); */
|
||
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_COMPLETE_16BIT_SERVICE_UUIDS, 0xAF00, 2);
|
||
|
||
if (offset > ADV_RSP_PACKET_MAX) {
|
||
puts("***adv_data overflow!!!!!!\n");
|
||
return -1;
|
||
}
|
||
log_info("adv_data(%d):", offset);
|
||
log_info_hexdump(buf, offset);
|
||
ble_user_cmd_prepare(BLE_CMD_ADV_DATA, 2, 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;
|
||
}
|
||
offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
|
||
|
||
if (offset > ADV_RSP_PACKET_MAX) {
|
||
puts("***rsp_data overflow!!!!!!\n");
|
||
return -1;
|
||
}
|
||
|
||
log_info("rsp_data(%d):", offset);
|
||
log_info_hexdump(buf, offset);
|
||
ble_user_cmd_prepare(BLE_CMD_RSP_DATA, 2, 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_user_cmd_prepare(BLE_CMD_ADV_PARAM, 3, 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
|
||
}
|
||
|
||
extern void reset_PK_cb_register(void (*reset_pk)(u32 *));
|
||
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);
|
||
}
|
||
}
|
||
|
||
extern void le_device_db_init(void);
|
||
void ble_profile_init(void)
|
||
{
|
||
printf("ble profile init\n");
|
||
le_device_db_init();
|
||
|
||
#if PASSKEY_ENTER_ENABLE
|
||
ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION, 7, TCFG_BLE_SECURITY_EN);
|
||
#else
|
||
ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION, 7, TCFG_BLE_SECURITY_EN);
|
||
#endif
|
||
|
||
/* setup ATT server */
|
||
att_server_init(profile_data, att_read_callback, 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);
|
||
}
|
||
|
||
static int set_adv_enable(void *priv, u32 en)
|
||
{
|
||
ble_state_e next_state, cur_state;
|
||
|
||
if (!adv_ctrl_en && 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 (en) {
|
||
advertisements_setup_init();
|
||
}
|
||
ble_user_cmd_prepare(BLE_CMD_ADV_ENABLE, 1, 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(">>>ble send disconnect\n");
|
||
set_ble_work_state(BLE_ST_SEND_DISCONN);
|
||
ble_user_cmd_prepare(BLE_CMD_DISCONNECT, 1, con_handle);
|
||
} else {
|
||
log_info(">>>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_user_cmd_prepare(BLE_CMD_ATT_VAILD_LEN, 1, &vaild_len);
|
||
return vaild_len;
|
||
}
|
||
|
||
static int 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
|
||
return app_send_user_data(ATT_CHARACTERISTIC_ae82_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;
|
||
}
|
||
|
||
void bt_ble_adv_enable(u8 enable)
|
||
{
|
||
set_adv_enable(0, enable);
|
||
}
|
||
|
||
static void ble_module_enable(u8 en)
|
||
{
|
||
os_mutex_pend(&mutex, 0);
|
||
log_info("mode_en:%d\n", en);
|
||
if (en) {
|
||
extern u8 get_ble_gatt_role(void);
|
||
if (1 == get_ble_gatt_role()) {
|
||
ble_stack_gatt_role(0);
|
||
// register for HCI events
|
||
hci_event_callback_set(&cbk_packet_handler);
|
||
le_l2cap_register_packet_handler(&cbk_packet_handler);
|
||
}
|
||
complete = 0;
|
||
adv_ctrl_en = 1;
|
||
bt_ble_adv_enable(1);
|
||
} else {
|
||
if (con_handle) {
|
||
if (complete) {
|
||
os_mutex_post(&mutex);
|
||
return;
|
||
}
|
||
adv_ctrl_en = 0;
|
||
ble_disconnect(NULL);
|
||
} else {
|
||
bt_ble_adv_enable(0);
|
||
adv_ctrl_en = 0;
|
||
}
|
||
complete = 0;
|
||
}
|
||
os_mutex_post(&mutex);
|
||
}
|
||
|
||
static const char ble_ext_name[] = "(BLE)";
|
||
|
||
void bt_ble_init(void)
|
||
{
|
||
log_info("***** ble_init******\n");
|
||
const char *name_p = bt_get_local_name();
|
||
u8 ext_name_len = sizeof(ble_ext_name) - 1;
|
||
|
||
if (!os_mutex_valid(&mutex)) {
|
||
os_mutex_create(&mutex);
|
||
}
|
||
|
||
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);
|
||
memcpy(&gap_device_name[gap_device_name_len], "(BLE)", ext_name_len);
|
||
gap_device_name_len += ext_name_len;
|
||
|
||
log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
|
||
|
||
set_ble_work_state(BLE_ST_INIT_OK);
|
||
ble_module_enable(1);
|
||
}
|
||
|
||
static void stack_exit(void)
|
||
{
|
||
ble_module_enable(0);
|
||
/* set_ble_work_state(BLE_ST_SEND_STACK_EXIT); */
|
||
/* ble_user_cmd_prepare(BLE_CMD_STACK_EXIT, 1, 0); */
|
||
/* set_ble_work_state(BLE_ST_STACK_EXIT_COMPLETE); */
|
||
}
|
||
|
||
void bt_ble_exit(void)
|
||
{
|
||
log_info("***** ble_exit******\n");
|
||
|
||
stack_exit();
|
||
}
|
||
|
||
void ble_app_disconnect(void)
|
||
{
|
||
ble_disconnect(NULL);
|
||
}
|
||
|
||
void ble_cfg_net_result_notify(int event)
|
||
{
|
||
if (!complete) {
|
||
return;
|
||
}
|
||
|
||
if (event == NET_CONNECT_TIMEOUT_NOT_FOUND_SSID) {
|
||
app_send_user_data(ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE, rsp_cmd3, sizeof(rsp_cmd3), ATT_OP_AUTO_READ_CCC);
|
||
} else if (event == NET_CONNECT_ASSOCIAT_FAIL) {
|
||
app_send_user_data(ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE, rsp_cmd4, sizeof(rsp_cmd4), ATT_OP_AUTO_READ_CCC);
|
||
} else if (event == NET_EVENT_CONNECTED) {
|
||
app_send_user_data(ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE, rsp_cmd0, sizeof(rsp_cmd0), ATT_OP_AUTO_READ_CCC);
|
||
complete = 0;
|
||
#if !defined PAYMENT_AUDIO_SDK_ENABLE && !CONFIG_POWER_ON_ENABLE_BLE
|
||
sys_timeout_add(0, (void (*)(void *))ble_module_enable, 100);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
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 *)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;
|
||
}
|
||
|
||
#endif
|