Hi Dialog Team,
我跟着一个- b - 029文档,是成功的adding new characteristic(notify/read) to my service. However, when i am adding a new characteristic(write/read), i am unable to write in it. Everytime it is showing "Writing to characteristic failed" when i am writing anything.Is there any document like AN-B-029 which will provide the steps? I am stuck in this.
However, now I want to add new services to the existing sample128. And my new service should contain the two characteristics. How should i implement it?Please help.
With Best Regards,
Sam
Keywords:
设备:

Hello Sam,
个人资料将收到
gattc_write_cmd_ind.message. You need to attach handler function for this message in your profile, which you probably already have done? Could you share the handler function you have in yourprofilename_task.c.?嗨Vesan,
我正在尝试向现有示例128添加写入/读取特性。
/**
****************************************************************************************
*
* @file sample128_task.c.
*
*@brief Sample128 Task implementation.
*
*@brief 128 UUID service. sample code
*
*Copyright (C) 2013 Dialog Semiconductor GmbH and its Affiliates, unpublished work
*此计算机程序包括机密,专有信息,是商业秘密
*of Dialog Semiconductor GmbH and its Affiliates. All use, disclosure, and/or
*reproduction is prohibited unless authorized in writing. All Rights Reserved.
*
****************************************************************************************
*/
/*
*INCLUDE FILES
****************************************************************************************
*/
#include“rwble_config.h”
#if(ble_sample128)
#include“gap.h”
#include "gapc.h"
#include "gattc_task.h"
#include "atts_util.h"
#include“sample128.h”
#include "sample128_task.h"
#include“attm_cfg.h”
#include "attm_db.h"
#include "prf_utils.h"
/*
*FUNCTION DEFINITIONS
****************************************************************************************
*/
/**
****************************************************************************************
*@brief Handles reception of the @ref SAMPLE128_CREATE_DB_REQ message.
*@param[in] msgid Id of the message received (probably unused).
* @param [in] param指向消息的参数。
* @param [in]接收任务实例的dest_id ID(可能未使用)。
* @param [in]发送任务实例的src_id ID。
*@return If the message was consumed or not.
****************************************************************************************
*/
静态int sample128_create_db_req_handler(ke_msg_id_t const msgid,
struct sample128_create_db_req const * param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
//Database Creation Status
UINT8_T状态;
uint8_t nb_att_16;
uint8_t nb_att_128;
uint8_t nb_att_32;
UINT16_T ATT_DECL_SVC = ATT_DECL_PRIMARY_SERVICE;
uint16_t att_decl_char = ATT_DECL_CHARACTERISTIC;
uint16_t att_decl_cfg = ATT_DESC_CLIENT_CHAR_CFG;
uint16_t val_hdl;
uint16_t char_hdl;
//保存配置文件ID
sample128_env.con_info.prf_id = task_sample128;
/*---------------------------------------------------*
*Sample128 Service Creation
* -------------------------------------------- * /
//Add Service Into Database
nb_att_16 = 5;// 6 ... 4 UUID16属性声明类型
nb_att_32 = 0;// 0 UUID32属性声明类型
nb_att_128 = 3; // 2 UUID128 Attribute declaration types
status = attmdb_add_service( &(sample128_env.sample128_shdl),
TASK_SAMPLE128,
nb_att_16,
nb_att_32,
nb_att_128,
78.
);
if(status == att_err_no_error)
{
//添加主要服务属性//////////////////////////////////////////////////////////////////////////////////////////////////////////////// //
status = attmdb_add_attribute(sample128_env.sample128_shdl,//属性句柄
ATT_UUID_128_LEN,//数据大小= 16(ATT_UUID_128_LEN)
ATT_UUID_16_LEN,//声明类型ID的大小
(uint8_t*)&att_decl_svc, // 0x2800 for a primary service declaration
PERM(RD, ENABLE), // Permissions
&(sample128_env.sample128_shdl) // Attribute Handle
);
//添加主服务属性的值(自定义UUID)
status = attmdb_att_set_value(sample128_env.sample128_shdl,//属性句柄
ATT_UUID_128_LEN,//该值是服务的128位UUID
(uint8_t *)sample128_svc.uuid // uuid的服务
);
//独特性1:////// //////////////////////////////////////////////////////////////////////////////////////////////
// Add characteristic declaration attribute to database
status = attmdb_add_attribute( sample128_env.sample128_shdl,
ATT_UUID_128_LEN + 3,//数据大小= 19(ATT_UUID_128_LEN + 3)
ATT_UUID_16_LEN,//声明类型ID的大小
(UINT8_T *)&ATT_DECL_CHAR,// 0x2803用于特征声明
PERM(RD, ENABLE), // Permissions
&(char_hdl) // Handle to the characteristic declaration
);
//将特征值声明属性添加到数据库
status = attmdb_add_attribute( sample128_env.sample128_shdl,
sizeof(uint8_t), // Data size = 1 Byte
ATT_UUID_128_LEN,//自定义声明类型= 128位的大小
(uint8_t*)&sample128_1_val.uuid, // UUID of the characteristic value
perm(rd,启用)|PERM(WR, ENABLE),// Permissions
&(val_hdl)//句柄到值属性
);
// Store the value handle for characteristic 1
memcpy(sample128_1_char.attr_hdl,&val_hdl,sizeof(uint16_t));
// Set initial value of characteristic 1
status = attmdb_att_set_value(char_hdl,sizeof(sample128_1_char),(uint8_t *)和sample128_1_char);
//Characteristic 2: //////////////////////////////////////////////////////////////////////////////////
// Add characteristic declaration attribute to database
status = attmdb_add_attribute( sample128_env.sample128_shdl,
ATT_UUID_128_LEN + 3,//数据大小= 19(ATT_UUID_128_LEN + 3)
ATT_UUID_16_LEN,//Size of declaration type ID
(UINT8_T *)&ATT_DECL_CHAR,// 0x2803用于特征声明
PERM(RD, ENABLE),// Permissions
&(char_hdl) // Handle to the characteristic declaration
);
//将特征值声明属性添加到数据库
status = attmdb_add_attribute( sample128_env.sample128_shdl,
sizeof(uint8_t),// data size = 1字节
ATT_UUID_128_LEN,//自定义声明类型ID = 128bit的大小
(uint8_t*)&sample128_2_val.uuid, // UUID of the characteristic value
perm(rd,启用)|perm(ntf,启用),//权限
&(val_hdl)//句柄到值属性
);
// Store the value handle for characteristic 2
memcpy(sample128_2_char.attr_hdl,&val_hdl,sizeof(uint16_t));
// Set initial value of characteristic 2
status = attmdb_att_set_value(char_hdl, sizeof(sample128_2_char), (uint8_t *)&sample128_2_char);
//将客户端配置声明属性添加到数据库(促进通知)
status = attmdb_add_attribute( sample128_env.sample128_shdl,
sizeof(uint16_t),//数据大小2bytes(16bit)
ATT_UUID_16_LEN,//客户端配置类型ID的大小
(uint8_t*) &att_decl_cfg, // 0x2902 UUID of client configuration declaration type
perm(rd,启用)|perm(wr,启用),//权限
&(val_hdl)//句柄value属性
);
// Characterisitic 3 for write: ////////////////////////////////////////////////////////////////////////////////
// Add characteristic declaration attribute to database
status = attmdb_add_attribute( sample128_env.sample128_shdl,
ATT_UUID_128_LEN + 3,//数据大小= 19(ATT_UUID_128_LEN + 3)
ATT_UUID_16_LEN,//声明类型ID的大小
(UINT8_T *)&ATT_DECL_CHAR,// 0x2803用于特征声明
PERM(RD, ENABLE), // Permissions
&(char_hdl) // Handle to the characteristic declaration
);
//将特征值声明属性添加到数据库
status = attmdb_add_attribute( sample128_env.sample128_shdl,
sizeof(my_newer_t), // Data size = 1 Byte
ATT_UUID_128_LEN,//自定义声明类型= 128位的大小
(uint8_t*)&sample128_3_val.uuid, // UUID of the characteristic value
perm(rd,启用)|PERM(WR, ENABLE),// Permissions
&(val_hdl)//句柄到值属性
);
// Store the value handle for characteristic 3
memcpy(sample128_3_char.attr_hdl, &val_hdl, sizeof(uint16_t));
// Set initial value of characteristic 3
status = attmdb_att_set_value(char_hdl,sizeof(sample128_3_char),(uint8_t *)和sample128_3_char);
//////// //////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//禁用示例128服务
attmdb_svc_set_permission(sample128_env.sample128_shdl,perm(svc,disable));
//If we are here, database has been fulfilled with success, go to idle state
ke_state_set(task_sample128,sample128_idle);
}
//将CFM发送到应用程序
struct sample128_create_db_cfm * cfm = ke_msg_alloc(sample128_create_db_cfm,src_id,
TASK_SAMPLE128, sample128_create_db_cfm);
cfm->status = status;
KE_MSG_SEND(CFM);
return(ke_msg_consumed);
}
/**
****************************************************************************************
*@brief Enable the Sample128 role, used after connection.
* @param [in]收到的消息的msgid ID。
* @param [in] param指向消息的参数。
* @param [in]接收任务实例的dest_id ID
* @param [in]发送任务实例的src_id ID。
*@return If the message was consumed or not.
****************************************************************************************
*/
static int sample128_enable_req_handler(ke_msg_id_t const msgid,
struct sample128_enable_req const * param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint16_t temp = 1;
//保留消息来源,进一步响应它
sample128_env.con_info.appid = src_id;
// Store the connection handle for which this profile is enabled
sample128_env.con_info.conidx = gapc_get_conidx(param-> conhdl);
// Check if the provided connection exist
if (sample128_env.con_info.conidx == GAP_INVALID_CONIDX)
{
//连接不存在,请求禁止
prf_server_error_ind_send((prf_env_struct *)和sample128_env,prf_err_req_disally,
SAMPLE128_ERROR_IND, SAMPLE128_ENABLE_REQ);
}
别的
{
// Sample128 service permissions
attmdb_svc_set_permission(sample128_env.sample128_shdl, param->sec_lvl);
//将特征1设置为指定值
attmdb_att_set_value(sample128_env.sample128_shdl + sample128_1_idx_val,
sizeof(uint8_t),(uint8_t *)和param-> sample128_1_val);
//将特征2设置为指定值
attmdb_att_set_value(sample128_env.sample128_shdl + SAMPLE128_2_IDX_VAL,
sizeof(uint8_t), (uint8_t *)¶m->sample128_2_val);
// Set characteristic 3 to specified value
attmdb_att_set_value(sample128_env.sample128_shdl + sample128_3_idx_val,
sizeof(uint8_t), (uint8_t *)¶m->sample128_3_val);
sample128_env.feature = param->feature;
if (!sample128_env.feature)
{
temp = 0;
}
attmdb_att_set_value(sample128_env.sample128_shdl + sample128_2_idx_cfg,
sizeof(uint16_t),(uint8_t *)&temp);
//转到连接状态
ke_state_set(TASK_SAMPLE128, SAMPLE128_CONNECTED);
}
return(ke_msg_consumed);
}
/**
****************************************************************************************
* @brief更新特性值2.如果启用了属性,请向对等体发送通知。
* @param [in]收到的消息的msgid ID。
* @param [in] param指向消息的参数。
* @param [in]接收任务实例的dest_id ID
* @param [in]发送任务实例的src_id ID。
*@return If the message was consumed or not.
****************************************************************************************
*/
静态int sample128_upd_char2_req_handler(ke_msg_id_t const msgid,
struct sample128_upd_char2_req const * param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
UINT8_T status = prf_err_ok;
//检查提供的值
if(param-> conhdl == gapc_get_conhdl(sample128_env.con_info.conidx))
{
//更新数据库中的值
attmdb_att_set_value(sample128_env.sample128_shdl + SAMPLE128_2_IDX_VAL,
sizeof(uint8_t),(uint8_t *)和param-> val);
if((sample128_env.feature&prf_cli_start_ntf))
//通过gatt发送通知
prf_server_send_event((prf_env_struct *)和sample128_env,false,
sample128_env.sample128_shdl + SAMPLE128_2_IDX_VAL);
}
别的
{
status = prf_err_invalid_param;
}
if(状态!= prf_err_ok)
{
sample128_upd_char2_cfm_send(状态);
}
return(ke_msg_consumed);
}
/**
****************************************************************************************
*@brief Handles reception of the @ref GATT_WRITE_CMD_IND message.
*@param[in] msgid Id of the message received (probably unused).
* @param [in] param指向消息的参数。
* @param [in]接收任务实例的dest_id ID(可能未使用)。
* @param [in]发送任务实例的src_id ID。
*@return If the message was consumed or not.
****************************************************************************************
*/
static int gattc_write_cmd_ind_handler(ke_msg_id_t const msgid,
struct gattc_write_cmd_ind.const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint8_t char_code = SAMPLE128_ERR_CHAR;
uint8_t status = PRF_APP_ERROR;
if (KE_IDX_GET(src_id) == sample128_env.con_info.conidx)
{
if (param->handle == sample128_env.sample128_shdl + SAMPLE128_1_IDX_VAL)
{
char_code = SAMPLE128_1_CHAR;
}
if(param-> handle == sample128_env.sample128_shdl + sample128_2_idx_cfg)
{
char_code = sample128_2_cfg;
}
if (param->handle == sample128_env.sample128_shdl + SAMPLE128_3_IDX_VAL)
{
char_code = SAMPLE128_3_CHAR;
}
if (char_code == SAMPLE128_1_CHAR)
{
//Save value in DB
attmdb_att_set_value(param->handle, sizeof(uint8_t), (uint8_t *)¶m->value[0]);
如果(param->最后)
{
sample128_send_val(param-> value [0]);
}
status = prf_err_ok;
}
别的if (char_code == SAMPLE128_2_CFG)
{
//书面价值
uint16_t ntf_cfg;
//在检查前提取值
ntf_cfg = co_read16p(&param-> value [0]);
//仅更新配置如果停止或通知启用的值
if ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_NTF))
{
//Save value in DB
attmdb_att_set_value(param->句柄,sizeof(uint16_t),(uint8_t *)和param->值[0]);
// Conserve information in environment
if(ntf_cfg == prf_cli_start_ntf)
{
// Ntf cfg bit set to 1
sample128_env.feature |= PRF_CLI_START_NTF;
}
别的
{
// Ntf cfg bit set to 0
sample128_env.feature &= ~PRF_CLI_START_NTF;
}
status = prf_err_ok;
}
}
别的if (char_code == SAMPLE128_3_CHAR)
{
//Save value in DB
attmdb_att_set_value(param->handle, sizeof(uint8_t), (uint8_t *)¶m->value[0]);
如果(param->最后)
{
sample128_send_val(param-> value [0]);
}
status = prf_err_ok;
}
}
// Send Write Response
atts_write_rsp_send(sample128_env.con_info.conidx, param->handle, status);
return(ke_msg_consumed);
}
/**
****************************************************************************************
* @brief断开指示样本128。
* @param [in]收到的消息的msgid ID。
* @param [in] param指向消息的参数。
* @param [in]接收任务实例的dest_id ID
* @param [in]发送任务实例的src_id ID。
*@return If the message was consumed or not.
****************************************************************************************
*/
msgid静态int gap_disconnect_ind_handler(ke_msg_id_t const,
struct gapc_disconnect_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
//检查连接句柄
if (KE_IDX_GET(src_id) == sample128_env.con_info.conidx)
{
// In any case, inform APP about disconnection
sample128_disable();
}
return(ke_msg_consumed);
}
/*
*全局变量定义
****************************************************************************************
*/
/// Disabled State handler definition.
const struct ke_msg_handler sample128_disabled [] =
{
{sample128_create_db_req,(ke_msg_func_t)sample128_create_db_req_handler},
{sample128_create_db_req3,(ke_msg_func_t)sample128_create_db_req_handler},
};
/// Idle State handler definition.
const struct ke_msg_handler sample128_idle [] =
{
{sample128_enable_req,(ke_msg_func_t)sample128_enable_req_handler},
};
/// Connected State handler definition.
const struct ke_msg_handler sample128_connected [] =
{
{gattc_write_cmd_ind,(ke_msg_func_t)gattc_write_cmd_ind_handler},
{SAMPLE128_UPD_CHAR2_REQ, (ke_msg_func_t) sample128_upd_char2_req_handler},
{gattc_write_cmd_ind3,(ke_msg_func_t)gattc_write_cmd_ind_handler3},
};
///默认状态处理程序定义
const struct ke_msg_handler sample128_default_state[] =
{
{gapc_disconnect_ind,(ke_msg_func_t)gap_disconnnect_ind_handler},
};
/// Specifies the message handler structure for every input state.
const struct ke_state_handler sample128_state_handler[SAMPLE128_STATE_MAX] =
{
[SAMPLE128_DISABLED] = KE_STATE_HANDLER(sample128_disabled),
[sample128_idle] = ke_state_handler(sample128_idle),
[sample128_connected] = ke_state_handler(sample128_connected),
};
/// Specifies the message handlers that are common to all states.
const struct ke_state_handler sample128_default_handler = ke_state_handler(sample128_default_state);
///定义所有任务实例的状态的位置持有者。
ke_state_t sample128_state[SAMPLE128_IDX_MAX] __attribute__((section("retention_mem_area0"),zero_init));
#endif // ble_sample128.
Hi Sam123,
你不能拥有
{gattc_write_cmd_ind3,(ke_msg_func_t)gattc_write_cmd_ind_handler3}。您需要处理每个服务特征gattc_write_cmd_ind.。You can tell the difference between each characteristics by inspecting the handle value of the message parameter
帕纳在处理函数中。它具有以下结构/// Inform that a modification of database has been requested by peer device.
struct gattc_write_cmd_ind.
{
///处理必须写入的属性
UINT16_T手柄;
/// Data length to be written
uint16_t length;
///要写数据的偏移量
uint16_t offset;
///目标任务如果为true,则应发送返回写入响应命令。
BOOL反应;
///通知它是多个准备写请求的最后一个请求。
bool last;
///在属性数据库中写入的数据
UINT8_T值[__ array_empty];
};
In other words, inspect the value of the param->handle. Eg., you can create switch case comparison for the attribute (characteristic value):
交换机(param->句柄 - your_profile_env.start_handle){
案例char1:休息;
案件char2:休息;
}
对不起,这有点匆匆写。没有测试,但我希望你有一些照片
谢谢!
你好,
I can only add 8 characteristics in a service, when I added the 9th one, it is not running, anyone tried this?
Hi redbear,
It depends on the characteristic's you are adding to your service. The software supports until 32 attributes per service.
谢谢mt_dialog.
嗨mt_dialog,
nb_att_16 = 1+9+9; // 1svc,9char,9user_desc
nb_att_32 = 0;
nb_att_128 = 9; // val att
我大致了解,但28 <32。
Hi redbear,
What do you mean its not running, can you debug your application in order to see if it goes through the app_adv_start() function?
你可以9一个服务的特征。请耐心ase check your code its easy to make a mistake with copying and pasting.
谢谢mt_dialog.
嗨mt_dialog,
" its not running" means I can not see from lightblue.
first I write a macro switch to add two char, maybe copying and pasting error as you said,
但现在我添加了两个宏开关,只添加第8个,确定。只添加第9个,确定,这意味着代码是对的。
添加两个,我看不到闪烁。
用keil?
anyother way to debug?
我认为用户DESC字符串有点长,
我现在缩短了这是工作!
but what is the limit?
嗨Antony,
我没有得到它,你缩短了什么和工作?
谢谢mt_dialog.
嗨mt_dialog,
我更改了char_user_description长度,如下所示:
旧的:
static const uint8_t beacon_user_desc_1 [] =“beacon uuid”;
static const uint8_t beacon_user_desc_2[] = "Major identity ID";
static const uint8_t beacon_user_desc_3 [] =“次要身份ID”;
...直到beaccon_user_desc_9.
new one:
static const uint8_t beacon_user_desc_1 [] =“uuid”;
static const uint8_t beaccon_user_desc_2 [] =“major”;
static const uint8_t beacon_user_desc_3[] = "Minor";
......
它有效。
嗨Antony42,
You are changing the characteristics of the database or the advertising string ? The advertising string has a fixed maximum number of 29 bytes payload. That has nothing to do with the database.
谢谢mt_dialog.
嗨mt_dialog,
the characteristics of the database,
ATT_DESC_CHAR_USER_DESCRIPTION, I made the description string shorter, 9 characteristics in a service is ok.
你好,
我添加了塞尔维护和28个特征,工作正常,
但我添加了另外两个特征,我可以从浅蓝色看,但不能连接,
为什么一个最多的项目中的特点是多少?
嗨Antony,
除了在前一篇文章中提到的32个属性的限制,理论上,特征数量没有其他限制。唯一的限制是数据库的内存大小,由db_heap_size定义。
谢谢mt_dialog.
嗨mt_dialog,
我试过,仍然没有工作。
首先我增加了db_heap_sz的大小,甚至高达1024 * 2,但不起作用,然后我增加了三雪石三,没什么改变。
#define DB_HEAP_SZ (1024+256)
#define env_heap_sz 328.
#define MSG_HEAP_SZ 1312
#define NON_RET_HEAP_SZ 1024
undef其中一个,一切正常,添加这三个灯泡不起作用。
cfg_beacon_config_struct.
CFG_PRF_SPOTAR
CFG_PRF_ANTHONY
什么可能导致这个问题?
非常感谢,
安东尼。
嗨Antony42,
当你是#undef任何#defines你已经提到你的设备是广告的,你想要的所有30个特征?
谢谢mt_dialog.
嗨mt_dialog,
当我#def这三个时,我看不到浅蓝色,
其中一个人,工作正常。
顺便问一下,你使用Skype吗?(ID:ElectronicFan)
谢谢,
Anthony
嗨Antony42,
对话框本地团队的成员将尽快与您联系,以支持您。
谢谢mt_dialog.