@@ -3,30 +3,11 @@
*
* @file user_peripheral.c
*
* @brief Peripheral project source code.
* @brief 外设项目源代码文件, 主要实现BLE外设功能、时钟管理、EPD屏幕显示及OTP数据读取等功能
*
* Copyright (C) 2015-2023 Renesas Electronics Corporation and/or its affiliates.
* All rights reserved. Confidential Information.
*
* This software ("Software") is supplied by Renesas Electronics Corporation and/or its
* affiliates ("Renesas"). Renesas grants you a personal, non-exclusive, non-transferable,
* revocable, non-sub-licensable right and license to use the Software, solely if used in
* or together with Renesas products. You may make copies of this Software, provided this
* copyright notice and disclaimer ("Notice") is included in all such copies. Renesas
* reserves the right to change or discontinue the Software at any time without notice.
*
* THE SOFTWARE IS PROVIDED "AS IS". RENESAS DISCLAIMS ALL WARRANTIES OF ANY KIND,
* WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. TO THE
* MAXIMUM EXTENT PERMITTED UNDER LAW, IN NO EVENT SHALL RENESAS BE LIABLE FOR ANY DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE, EVEN IF RENESAS HAS BEEN ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGES. USE OF THIS SOFTWARE MAY BE SUBJECT TO TERMS AND CONDITIONS CONTAINED IN
* AN ADDITIONAL AGREEMENT BETWEEN YOU AND RENESAS. IN CASE OF CONFLICT BETWEEN THE TERMS
* OF THIS NOTICE AND ANY SUCH ADDITIONAL LICENSE AGREEMENT, THE TERMS OF THE AGREEMENT
* SHALL TAKE PRECEDENCE. BY CONTINUING TO USE THIS SOFTWARE, YOU AGREE TO THE TERMS OF
* THIS NOTICE.IF YOU DO NOT AGREE TO THESE TERMS, YOU ARE NOT PERMITTED TO USE THIS
* SOFTWARE.
*
****************************************************************************************
*/
@@ -39,90 +20,86 @@
*/
/*
* INCLUDE FILES
* 包含头文件
****************************************************************************************
*/
# include "rwip_config.h" // SW configuration
# include "gattc_task.h"
# include "gap.h"
# include "app_easy_timer.h"
# include "user_peripheral.h"
# include "user_custs1_impl.h"
# include "user_custs1_def.h"
# include "co_bt.h"
# include "hw_otpc.h"
# include "rwip_config.h" // 软件配置
# include "gattc_task.h" // GATT客户端任务相关定义
# include "gap.h" // GAP层相关定义
# include "app_easy_timer.h" // 应用层定时器功能
# include "user_peripheral.h" // 本文件接口声明
# include "user_custs1_impl.h" // 自定义服务1实现
# include "user_custs1_def.h" // 自定义服务1定义
# include "co_bt.h" // 蓝牙协议协议相关定义
# include "hw_otpc.h" // OTP控制器硬件接口
# include "epd.h"
# include "epd.h" // EPD电子纸屏幕驱动
/*
* TYPE DEFINITIONS
* 类型定义
****************************************************************************************
*/
/*
* GLOBAL VARIABLE DEFINITIONS
* 全局变量定义
****************************************************************************************
*/
int app_connection_idx __SECTION_ZERO ( " retention_mem_area0 " ) ;
timer_hnd app_clock_timer_used __SECTION_ZERO ( " retention_mem_area0 " ) ; //@RETENTION MEMORY
timer_hnd app_param_update_request_timer_used __SECTION_ZERO ( " retention_mem_area0 " ) ;
int app_connection_idx __SECTION_ZERO ( " retention_mem_area0 " ) ; // 连接索引,使用 retention 内存区域保存
timer_hnd app_clock_timer_used __SECTION_ZERO ( " retention_mem_area0 " ) ; // 时钟定时器句柄, retention内存保存
timer_hnd app_param_update_request_timer_used __SECTION_ZERO ( " retention_mem_area0 " ) ; // 参数更新请求定时器句柄, retention内存保存
static int adv_state ;
static int otp_btaddr [ 2 ] ;
static int otp_boot ;
static char adv_name [ 20 ] ;
char * bt_id = adv_name + 12 ;
int clock_interval ;
int clock_fixup_value ;
int clock_fixup_count ;
static int adv_state ; // 广播状态: 0-未广播, 1-正在广播
static int otp_btaddr [ 2 ] ; // 从OTP读取的蓝牙地址
static int otp_boot ; // 从OTP读取的启动相关数据
static char adv_name [ 20 ] ; // 广播名称缓冲区
char * bt_id = adv_name + 12 ; // 蓝牙ID在广播名称中的起始位置
int clock_interval ; // 时钟更新间隔(秒)
int clock_fixup_value ; // 时钟修正值
int clock_fixup_count ; // 时钟修正计数器
// EPD版本信息( volatile确保不被优化, 用于版本检测)
const volatile u32 epd_version [ 3 ] = { 0xF9A51379 , ~ 0xF9A51379 , EPD_VERSION } ;
extern int year , month ; // 当前时间变量
/*
* FUNCTION DEFINITIONS
* 函数定义
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Add an AD structure in the Advertising or Scan Response Data of the
* GAPM_START_ADVERTISE_CMD parameter struct.
* @param[in] cmd GAPM_START_ADVERTISE_CMD parameter struct
* @param[in] ad_struct_data AD structure buffer
* @param[in] ad_struct_ len AD structure length
* @param[in] adv_connectable Connectable advertising event or not. It controls whether
* the advertising data use the full 31 bytes length or only
* 28 bytes (Document CCSv6 - Part 1.3 Flags).
* @brief 在GAPM_START_ADVERTISE_CMD参数结构的广播或扫描响应数据中添加AD结构
* @param[in] cmd GAPM_START_ADVERTISE_CMD参数结构
* @param[in] ad_struct_data AD结构数据缓冲区
* @param[in] ad_struct_len AD结构长度
* @param[in] adv_connectab le 是否为可连接广播事件, 控制广播数据最大长度( 可连接时28字节, 否则31字节)
****************************************************************************************
*/
static void app_add_ad_struct ( struct gapm_start_advertise_cmd * cmd , void * ad_struct_data , uint8_t ad_struct_len , uint8_t adv_connectable )
{
// 根据是否可连接确定广播数据最大长度
uint8_t adv_data_max_size = ( adv_connectable ) ? ( ADV_DATA_LEN - 3 ) : ( ADV_DATA_LEN ) ;
// 优先添加到广播数据
if ( ( adv_data_max_size - cmd - > info . host . adv_data_len ) > = ad_struct_len )
{
// Append manufacturer data to advertising data
memcpy ( & cmd - > info . host . adv_data [ cmd - > info . host . adv_data_len ] , ad_struct_data , ad_struct_len ) ;
// Update Advertising Data Length
cmd - > info . host . adv_data_len + = ad_struct_len ;
}
// 广播数据空间不足时添加到扫描响应数据
else if ( ( SCAN_RSP_DATA_LEN - cmd - > info . host . scan_rsp_data_len ) > = ad_struct_len )
{
// Append manufacturer data to scan response data
memcpy ( & cmd - > info . host . scan_rsp_data [ cmd - > info . host . scan_rsp_data_len ] , ad_struct_data , ad_struct_len ) ;
// Update Scan Response Data Length
cmd - > info . host . scan_rsp_data_len + = ad_struct_len ;
}
// 空间不足时触发断言警告
else
{
// Manufacturer Specific Data do not fit in either Advertising Data or Scan Response Data
ASSERT_WARNING ( 0 ) ;
}
}
@@ -130,27 +107,36 @@ static void app_add_ad_struct(struct gapm_start_advertise_cmd *cmd, void *ad_str
/**
****************************************************************************************
* @brief Parameter update request timer callback function.
* @brief 参数更新请求定时器回调函数
* 当定时器超时,发起连接参数更新请求
****************************************************************************************
*/
static void param_update_request_timer_cb ( )
{
app_easy_gap_param_update_start ( app_connection_idx ) ;
app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER ;
app_easy_gap_param_update_start ( app_connection_idx ) ; // 发起参数更新
app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER ; // 重置定时器句柄
}
/**
****************************************************************************************
* @brief 读取OTP( 一次性可编程) 存储器中的值
* 主要读取蓝牙地址和启动信息,并生成广播名称
****************************************************************************************
*/
static void read_otp_value ( void )
{
hw_otpc_init ( ) ;
hw_otpc_manual_read_on ( false ) ;
hw_otpc_init ( ) ; // 初始化OTP控制器
hw_otpc_manual_read_on ( false ) ; // 关闭手动读取模式
otp_boot = * ( u32 * ) ( 0x07f8fe00 ) ;
otp_btaddr [ 0 ] = * ( u32 * ) ( 0x07f8ffa8 ) ;
otp_btaddr [ 1 ] = * ( u32 * ) ( 0x07f8ffac ) ;
// 从OTP特定地址读取数据
otp_boot = * ( u32 * ) ( 0x07f8fe00 ) ; // 读取启动相关数据
otp_btaddr [ 0 ] = * ( u32 * ) ( 0x07f8ffa8 ) ; // 读取蓝牙地址低32位
otp_btaddr [ 1 ] = * ( u32 * ) ( 0x07f8ffac ) ; // 读取蓝牙地址高32位
hw_otpc_disable ( ) ;
hw_otpc_disable ( ) ; // 禁用OTP控制器
// 处理蓝牙地址,生成设备唯一标识
u32 ba0 = otp_btaddr [ 0 ] ;
u32 ba1 = otp_btaddr [ 1 ] ;
@@ -158,190 +144,279 @@ static void read_otp_value(void)
ba0 & = 0x00ffffff ;
ba0 ^ = ba1 ;
// 生成广播名称( 格式: DLG-CLOCK-XXYYZZ, XXYYZZ为蓝牙地址后三段)
u8 * ba = ( u8 * ) & ba0 ;
sprintf ( adv_name + 2 , " DLG-CLOCK-%02x%02x%02x " , ba [ 2 ] , ba [ 1 ] , ba [ 0 ] ) ;
int name_len = strlen ( adv_name + 2 ) ;
// 如果设备名称未设置,则使用生成的名称
if ( device_info . dev_name . length = = 0 ) {
device_info . dev_name . length = name_len ;
memcpy ( device_info . dev_name . name , adv_name + 2 , name_len ) ;
}
// 构造AD结构: 第一个字节为长度, 第二个字节为AD类型( 完整名称)
adv_name [ 0 ] = name_len + 1 ;
adv_name [ 1 ] = GAP_AD_TYPE_COMPLETE_NAME ;
}
// 外部声明的区域表基地址(用于内存相关操作)
extern int Region $ $ Table $ $ Base ;
/**
****************************************************************************************
* @brief 应用初始化函数
* 初始化OTP数据、定时器、屏幕、蓝牙等模块
****************************************************************************************
*/
void user_app_init ( void )
{
read_otp_value ( ) ;
read_otp_value ( ) ; // 读取OTP数据, 初始化广播名称
printk ( " \n \n user_app_init! %s %08x \n " , __TIME__ , epd_version [ 2 ] ) ;
app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER ;
app_clock_timer_used = EASY_TIMER_INVALID_TIMER ;
app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER ; // 初始化参数更新定时器
app_clock_timer_used = EASY_TIMER_INVALID_TIMER ; // 初始化时钟定时器
clock_interval = 60 ; // 60s
clock_fixup_value = 0 ;
clock_fixup_count = 0 ;
clock_interval = 60 ; // 时钟更新间隔设置为 60秒
clock_fixup_value = 0 ; // 初始化时钟修正值
clock_fixup_count = 0 ; // 初始化时钟修正计数器
adv_state = 0 ;
fspi_config ( 0x00030605 ) ;
adv_state = 0 ; // 初始化为未广播状态
fspi_config ( 0x00030605 ) ; // 配置FSPI接口
selflash ( otp_boot ) ;
selflash ( otp_boot ) ; // 根据OTP启动数据执行自闪存操作
epd_hw_init ( 0x23200700 , 0x05210006 , detect_w , detect_h , detect_mode | ROTATE_3 ) ; // 2.13黑白屏, 6个测试点
if ( epd_detect ( ) = = 0 ) {
epd_hw_init ( 0x23111000 , 0x07210120 , detect_w , detect_h , detect_mode | ROTATE_3 ) ; // 2.13黑白屏, 5个测试点
// 初始化EPD屏幕( 2.13黑白屏, 6个测试点)
epd_hw_init ( 0x23200700 , 0x05210006 , detect_w , detect_h , detect_mode | ROTATE_3 ) ;
if ( epd_detect ( ) = = 0 ) { // 如果检测不到屏幕,尝试另一种配置( 5个测试点)
epd_hw_init ( 0x23111000 , 0x07210120 , detect_w , detect_h , detect_mode | ROTATE_3 ) ;
epd_detect ( ) ;
}
app_c onnection_idx = - 1 ;
default_app_on_init ( ) ;
app_connection_idx = - 1 ; // 初始化连接索引为无效值
default_ app_on_init ( ) ; // 执行默认应用初始化
}
// 时钟快慢修正
// minutes : 自上次对时后,经过的分钟数
// diff_sec: 自上次对时后,误差的秒 数
// 误差为正数,说明时钟快了。将定时器加上一个修正值,让它慢一点。
// 误差为负数,说明时钟慢了。将定时器减去一个修正值,让它快一点。
/**
****************************************************************************************
* @brief 时钟快慢修正函 数
* @param[in] diff_sec 自上次对时后的误差秒数(正数表示快了,负数表示慢了)
* @param[in] minutes 自上次对时后经过的分钟数
* @note 计算并累积时钟修正值,用于调整定时器间隔,补偿时钟误差
****************************************************************************************
*/
void clock_fixup_set ( int diff_sec , int minutes )
{
// 计算新的修正值( 基于4096精度的分数计算)
int new_fixup_value = diff_sec * 100 * 4096 / minutes ;
clock_fixup_value + = new_fixup_value ;
clock_fixup_value + = new_fixup_value ; // 累积修正值
}
/**
****************************************************************************************
* @brief 应用时钟修正值
* @return 本次需要调整的毫秒数
* @note 从累积的修正计数器中提取整数部分作为本次调整值,保留余数
****************************************************************************************
*/
static int clock_fixup ( void )
{
int value ;
clock_fixup_count + = clock_fixup_value ;
clock_fixup_count + = clock_fixup_value ; // 累积修正计数
value = clock_fixup_count > > 12 ;
clock_fixup_count & = 0xfff ;
value = clock_fixup_count > > 12 ; // 右移12位( 除以4096) 得到整数部分
clock_fixup_count & = 0xfff ; // 保留低12位作为余数
return value ;
return value ; // 返回本次调整的毫秒数
}
extern int adcval ; // ADC电压值变量
/**
****************************************************************************************
* @brief 应用时钟定时器回调函数
* 定时更新时钟、推送时钟数据、处理屏幕显示,并根据需要重启广播
****************************************************************************************
*/
static void app_clock_timer_cb ( void )
{
int adj = clock_fixup ( ) ;
int adj = clock_fixup ( ) ; // 获取时钟修正值
// 重启定时器, 应用修正后的间隔( 单位: 10ms, 故乘以100)
app_clock_timer_used = app_easy_timer ( clock_interval * 100 + adj , app_clock_timer_cb ) ;
// 确定屏幕更新标志(根据时钟状态)
int flags = UPDATE_FLY ; // 默认快速更新
// 更新时钟并打印
int stat = clock_update ( clock_interval ) ;
clock_print ( ) ;
// 如果已连接,则推送时钟数据
if ( app_connection_idx ! = - 1 ) {
clock_push ( ) ;
}
//未进行初始化,则始终展示二维码
if ( year = = 2025 & & month < = 5 ) {
// 在2024年2月执行特定操作( 占位符)
QR_draw ( ) ;
user_app_adv_start ( ) ; //持续开启广播
return ;
}
int flags = UPDATE_FLY ;
if ( stat > = 3 ) {
flags = DRAW_BT | UPDATE_FULL ;
} else if ( stat > = 2 ) {
flags = DRAW_BT | UPDATE_FAST ;
}
// 如果是快速更新, 更新ADC数据,若电量不足则不继续执行任务
if ( flags = = 4 ) {
adc1_update ( ) ;
if ( adcval < 1360 ) {
LB_draw ( ) ;
return ;
}
}
if ( stat > = 3 ) {
flags = DRAW_BT | UPDATE_FULL ; // 需要蓝牙图标+全量更新
} else if ( stat > = 2 ) {
flags = DRAW_BT | UPDATE_FAST ; // 需要蓝牙图标+快速更新
}
// 如果需要显示蓝牙图标,启动广播
if ( flags & DRAW_BT ) {
user_app_adv_start ( ) ;
}
// 根据状态或标志更新屏幕显示
if ( stat > 0 | | flags & DRAW_BT ) {
clock_draw ( flags ) ;
}
}
/**
****************************************************************************************
* @brief 重启应用时钟定时器
****************************************************************************************
*/
void app_clock_timer_restart ( void )
{
app_easy_timer_cancel ( app_clock_timer_used ) ;
app_easy_timer_cancel ( app_clock_timer_used ) ; // 取消当前定时器
// 以默认间隔重启定时器
app_clock_timer_used = app_easy_timer ( clock_interval * 100 , app_clock_timer_cb ) ;
}
/**
****************************************************************************************
* @brief 数据库初始化完成回调函数
* 当GATT数据库初始化完成后调用, 初始化ADC、显示时钟并启动广播
****************************************************************************************
*/
void user_app_on_db_init_complete ( void )
{
printk ( " \n user_app_on_db_init_complete! \n " ) ;
// 更新ADC值并打印电压
int adcval = adc1_update ( ) ;
printk ( " Voltage: %d \n " , adcval ) ;
// 打印并推送时钟数据
clock_print ( ) ;
clock_push ( ) ;
// 绘制时钟(带蓝牙图标+全量更新)并启动广播
clock_draw ( DRAW_BT | UPDATE_FULL ) ;
user_app_adv_start ( ) ;
// 启动时钟定时器
app_clock_timer_used = app_easy_timer ( clock_interval * 100 , app_clock_timer_cb ) ;
}
/**
****************************************************************************************
* @brief 启动应用广播
* 构造广播数据( 包含设备名称和EPD版本) , 并启动带超时的无向广播
****************************************************************************************
*/
void user_app_adv_start ( void )
{
u8 vbuf [ 4 ] ;
u8 vbuf [ 4 ] ; // 版本信息AD结构缓冲区
// 如果已在广播状态,直接返回
if ( adv_state )
return ;
adv_state = 1 ;
adv_state = 1 ; // 标记为正在广播
struct gapm_start_advertise_cmd * cmd = app_easy_gap_undirected_advertise_get_active ( ) ;
// 获取广播命令结构
struct gapm_start_advertise_cmd * cmd = app_easy_gap_undirected_advertise_get_active ( ) ;
// 添加设备名称AD结构
app_add_ad_struct ( cmd , adv_name , adv_name [ 0 ] + 1 , 1 ) ;
// 构造版本信息AD结构( 长度+类型+版本号低两位)
vbuf [ 0 ] = 0x03 ;
vbuf [ 1 ] = GAP_AD_TYPE_MANU_SPECIFIC_DATA ;
vbuf [ 2 ] = EPD_VERSION & 0xff ;
vbuf [ 3 ] = ( EPD_VERSION > > 8 ) & 0xff ;
app_add_ad_struct ( cmd , vbuf , vbuf [ 0 ] + 1 , 1 ) ;
//default_advertise_operation();
//app_easy_gap_undirected_advertise_start();
// 启动带超时的无向广播
app_easy_gap_undirected_advertise_with_timeout_start ( user_default_hnd_conf . advertise_period , NULL ) ;
printk ( " \n user_app_adv_start! %s \n " , adv_name + 2 ) ;
}
/**
****************************************************************************************
* @brief 连接事件回调函数
* 当收到连接请求时调用,更新连接索引,检查连接参数并在需要时请求参数更新
* @param[in] connection_idx 连接索引
* @param[in] param 连接请求参数
****************************************************************************************
*/
void user_app_connection ( uint8_t connection_idx , struct gapc_connection_req_ind const * param )
{
printk ( " user_app_connection: %d \n " , connection_idx ) ;
// 检查连接是否有效
if ( app_env [ connection_idx ] . conidx ! = GAP_INVALID_CONIDX )
{
app_connection_idx = connection_idx ;
app_connection_idx = connection_idx ; // 更新连接索引
// 打印连接参数
printk ( " interval: %d \n " , param - > con_interval ) ;
printk ( " latency : %d \n " , param - > con_latency ) ;
printk ( " sup_to : %d \n " , param - > sup_to ) ;
// Check if the parameters of the established connection are the preferred ones.
// If not then schedule a connection parameter update request.
// 检查连接参数是否符合预期,不符合则调度参数更新请求
if ( ( param - > con_interval < user_connection_param_conf . intv_min ) | |
( param - > con_interval > user_connection_param_conf . intv_max ) | |
( param - > con_latency ! = user_connection_param_conf . latency ) | |
( param - > sup_to ! = user_connection_param_conf . time_out ) )
{
// Connection params are not these that we expect
app_param_update_request_timer_used = app_easy_timer ( APP_PARAM_UPDATE_REQUEST_TO , param_update_request_timer_cb ) ;
}
// 推送时钟数据到客户端
clock_push ( ) ;
} else {
adv_state = 0 ;
adv_state = 0 ; // 连接无效时,标记为未广播
}
// 执行默认连接处理
default_app_on_connection ( connection_idx , param ) ;
}
/**
****************************************************************************************
* @brief 无向广播完成回调函数
* 当广播超时或异常结束时调用,更新广播状态并刷新屏幕
* @param[in] status 广播结束状态码
****************************************************************************************
*/
void user_app_adv_undirect_complete ( uint8_t status )
{
printk ( " user_app_adv_undirect_complete: %02x \n " , status ) ;
// 状态非0表示异常结束, 更新广播状态并刷新屏幕
if ( status ! = 0 ) {
adv_state = 0 ;
clock_draw ( UPDATE_FLY ) ;
@@ -349,22 +424,29 @@ void user_app_adv_undirect_complete(uint8_t status)
}
/**
****************************************************************************************
* @brief 断开连接回调函数
* 当连接断开时调用,清理定时器,更新连接状态,并根据断开原因决定是否重启广播
* @param[in] param 断开连接参数(包含断开原因)
****************************************************************************************
*/
void user_app_disconnect ( struct gapc_disconnect_ind const * param )
{
printk ( " user_app_disconnect! reason=%02x \n " , param - > reason ) ;
// Cancel the parameter update request timer
// 取消参数更新请求定时器
if ( app_param_update_request_timer_used ! = EASY_TIMER_INVALID_TIMER )
{
app_easy_timer_cancel ( app_param_update_request_timer_used ) ;
app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER ;
}
app_connection_idx = - 1 ;
adv_state = 0 ;
app_connection_idx = - 1 ; // 重置连接索引为无效值
adv_state = 0 ; // 标记为未广播
// 非远程用户主动断开时,重启广播;否则仅刷新屏幕
if ( param - > reason ! = CO_ERROR_REMOTE_USER_TERM_CON ) {
// 非主动断开连接时, 重新广播.
user_app_adv_start ( ) ;
} else {
clock_draw ( UPDATE_FLY ) ;
@@ -373,6 +455,16 @@ void user_app_disconnect(struct gapc_disconnect_ind const *param)
}
/**
****************************************************************************************
* @brief 未处理消息的捕获处理函数
* 处理各类未被默认处理的消息, 包括特征值读写、参数更新、MTU变更等事件
* @param[in] msgid 消息ID
* @param[in] param 消息参数
* @param[in] dest_id 目标任务ID
* @param[in] src_id 源任务ID
****************************************************************************************
*/
void user_catch_rest_hndl ( ke_msg_id_t const msgid ,
void const * param ,
ke_task_id_t const dest_id ,
@@ -380,12 +472,12 @@ void user_catch_rest_hndl(ke_msg_id_t const msgid,
{
switch ( msgid )
{
// 特征值写入通知(值已写入数据库)
case CUSTS1_VAL_WRITE_IND :
{
/* 写特征值通知. 值已经写入Database中了. */
//printk("CUSTS1_VAL_WRITE_IND!\n");
struct custs1_val_write_ind const * msg_param = ( struct custs1_val_write_ind const * ) ( param ) ;
// 根据句柄分发到对应的处理函数
switch ( msg_param - > handle )
{
case SVC1_IDX_CONTROL_POINT_VAL :
@@ -401,22 +493,22 @@ void user_catch_rest_hndl(ke_msg_id_t const msgid,
}
} break ;
// Notification确认( 请求已发出)
case CUSTS1_VAL_NTF_CFM :
{
/* Notification确认. 请求已经发出. */
} break ;
// Indication确认( 请求已发出)
case CUSTS1_VAL_IND_CFM :
{
/* Indication确认. 请求已经发出. */
} break ;
// 读ATT_INFO请求( 需要返回数据)
case CUSTS1_ATT_INFO_REQ :
{
/* 读ATT_INFO请求. 需要返回数据. */
//printk("CUSTS1_ATT_INFO_REQ!\n");
struct custs1_att_info_req const * msg_param = ( struct custs1_att_info_req const * ) param ;
// 根据属性索引分发处理
switch ( msg_param - > att_idx )
{
case SVC1_IDX_LONG_VALUE_VAL :
@@ -429,16 +521,17 @@ void user_catch_rest_hndl(ke_msg_id_t const msgid,
}
} break ;
// 连接参数更新通知
case GAPC_PARAM_UPDATED_IND :
{
// Cast the "param" pointer to the appropriate message structure
struct gapc_param_updated_ind const * msg_param = ( struct gapc_param_updated_ind const * ) ( param ) ;
printk ( " GAPC_PARAM_UPDATED_IND! \n " ) ;
// 打印更新后的参数
printk ( " interval: %d \n " , msg_param - > con_interval ) ;
printk ( " latency : %d \n " , msg_param - > con_latency ) ;
printk ( " sup_to : %d \n " , msg_param - > sup_to ) ;
// Check if updated Conn Params filled to preferred ones
// 检查更新后的参数是否符合预期
if ( ( msg_param - > con_interval > = user_connection_param_conf . intv_min ) & &
( msg_param - > con_interval < = user_connection_param_conf . intv_max ) & &
( msg_param - > con_latency = = user_connection_param_conf . latency ) & &
@@ -448,51 +541,48 @@ void user_catch_rest_hndl(ke_msg_id_t const msgid,
}
} break ;
// 特征值读取请求
case CUSTS1_VALUE_REQ_IND :
{
/* 读特征值. 什么时候会有这个事件? */
printk ( " CUSTS1_VALUE_REQ_IND! \n " ) ;
struct custs1_value_req_ind const * msg_param = ( struct custs1_value_req_ind const * ) param ;
// 处理未定义的读取请求,返回错误
switch ( msg_param - > att_idx )
{
default :
{
// Send Error message
struct custs1_value_req_rsp * rsp = KE_MSG_ALLOC ( CUSTS1_VALUE_REQ_RSP ,
src_id ,
dest_id ,
custs1_value_req_rsp ) ;
// Provide the connection index.
rsp - > conidx = app_env [ msg_param - > conidx ] . conidx ;
// Provide the attribute index.
rsp - > att_idx = msg_param - > att_idx ;
// Force current length to zero.
rsp - > length = 0 ;
// Set Error status
rsp - > status = ATT_ERR_APP_ERROR ;
// Send message
KE_MSG_SEND ( rsp ) ;
} break ;
}
} break ;
// GATT事件请求指示( 确认未处理的指示以避免超时)
case GATTC_EVENT_REQ_IND :
{
// Confirm unhandled indication to avoid GATT timeout
struct gattc_event_ind const * ind = ( struct gattc_event_ind const * ) param ;
struct gattc_event_cfm * cfm = KE_MSG_ALLOC ( GATTC_EVENT_CFM , src_id , dest_id , gattc_event_cfm ) ;
cfm - > handle = ind - > handle ;
KE_MSG_SEND ( cfm ) ;
} break ;
// MTU( 最大传输单元) 变更指示
case GATTC_MTU_CHANGED_IND :
{
struct gattc_mtu_changed_ind * ind = ( struct gattc_mtu_changed_ind * ) param ;
printk ( " GATTC_MTU_CHANGED_IND: %d \n " , ind - > mtu ) ;
} break ;
// 未处理的消息
default :
{
printk ( " Unhandled msgid=%08x \n " , msgid ) ;
@@ -500,4 +590,4 @@ void user_catch_rest_hndl(ke_msg_id_t const msgid,
}
}
/// @} APP
/// @} APP