亲爱的Dialog_Support,
我正在使用BLE外设作为我的项目的参考代码。BLE外围设备代码作为广告设备工作,但我想将其配置为扫描设备(中央)。现在我已经在现有的例子中做了以下更改。
1.在user_config.h
静态构造gapm_configuration user_gapm_conf = {
///设备角色:中心、外围设备、观察者或广播者
.role = GAP_CENTRAL_MST,
Struct scan_configuration {
///操作代码。
uint8_t代码;
///设备自己的BD地址源
uint8_t addr_src;
///扫描间隔
uint16_t间隔;
///扫描窗口大小
uint16_t窗口;
///扫描模式
uint8_t模式;
///扫描过滤策略
uint8_t filt_policy;
///扫描副本过滤策略
uint8_t filter_duplic;
};
user_scan_conf ={
///操作代码。
.code = GAPM_SCAN_PASSIVE,
///设备自己的BD地址源
.addr_src = GAPM_PUBLIC_ADDR,
///扫描间隔
.interval = 10,
///扫描窗口大小
.window = 5,
///扫描模式
.mode = GAP_GEN_DISCOVERY,
///扫描过滤策略
.filt_policy = SCAN_ALLOW_ADV_ALL,
///扫描副本过滤策略
.filter_duplic = SCAN_FILT_DUPLIC_EN
};
2.在user_callback_config.h
静态const结构app_callbacks user_app_callbacks = {
.app_on_connection = user_app_connection,
.app_on_disconnect = user_app_disconnect,
.app_on_update_params_rejected = NULL,
.app_on_update_params_complete = NULL,
.app_on_set_dev_config_complete = default_app_on_set_dev_config_complete
.app_on_adv_nonconn_complete = NULL,
.app_on_adv_undirect_complete = user_app_adv_undirect_complete,
.app_on_adv_direct_complete = NULL,
.app_on_db_init_complete = default_app_on_db_init_complete
.app_on_scanning_completed = user_on_scanning_completed,
.app_on_adv_report_ind = user_on_adv_report_ind,
#如果(BLE_APP_SEC)
.app_on_pairing_request = NULL,
.app_on_tk_exch_nomitm = NULL,
.app_on_irk_exch = NULL,
.app_on_csrk_exch = NULL,
.app_on_ltk_exch = NULL,
. app_on_pairing_succeeded = NULL,
.app_on_encrypt_ind = NULL,
.app_on_mitm_passcode_req = NULL,
.app_on_encrypt_req_ind = NULL,
.app_on_security_req_ind = NULL,
#endif // (BLE_APP_SEC)
};
3.我已经在user_peripheral.c文件中添加了这些函数
Void user_on_scanning_completed (uint8_t status)
{
if(status == gap_err_cancelled)
{
app_easy_gap_start_connection_to ();
connection_timer = app_easy_timer(USER_CON_TIMEOUT, user_gapm_cancel);
}
其他的
{
user_scan_start ();
}
返回;
}
user_scan_start(void)
{
struct gapm_start_scan_cmd* cmd = KE_MSG_ALLOC(gapm_start_scan_cmd,
TASK_GAPM TASK_APP,
gapm_start_scan_cmd);
cmd - > op。代码= user_scan_conf.code;
cmd - > op。Addr_src = user_scan_conf.addr_src;
Cmd ->interval = user_scan_conf.interval;
Cmd ->window = user_scan_conf.window;
Cmd ->模式= user_scan_conf.mode;
Cmd ->filt_policy = user_scan_conf.filt_policy;
Cmd ->filter_duplic = user_scan_conf.filter_duplic;
//发送信息
ke_msg_send (cmd);
//我们现在是可连接的
ke_state_set (TASK_APP APP_CONNECTABLE);
}
我已经在尊敬的文件中尝试了上述更改,但当我运行程序时,它会进入nmi_handler.c。
我有什么遗漏的吗?还是我做错了配置?请指导我正确的步骤配置BLE外围设备为中心。
先谢谢你。
与问候,
前腿帕特尔
你好,Ruchi Patel,
当设备准备好启动(配置好、设置好并准备好启动)时,广告或扫描命令将从.default_operation_adv中取出,因此在该钩子中,您应该放置您希望设备在准备好启动时执行的任何操作。所以我假设如果你在钩子中放置user_start_scan()函数而不是user_app_adv_start(),你的设备将开始扫描过程。
由于MT_dialog
谢谢你的建议。
我已经尝试了上面的解决方案,但我仍然得到同样的问题。当我运行程序时,它进入nmi_handler.h。我在user_config.h, user_callback_config.h和user_peripheral.c文件中所做的上述配置是否正确?您能否提供一个详细的解决方案或演示中心功能的示例代码。
与问候,
前腿帕特尔
你好,Ruchi Patel,
检查调试器user_scan_start()函数是否被触发,也检查完成回调,如果它被触发,你得到的错误代码是什么,如果它是一个GAP_ERROR_TIMEOUT,你得到它后大约8秒的活动,这意味着你正在扫描,NMI被触发,当你到达扫描过程的完成回调。关于你粘贴的文件和代码,我看不出有什么问题,你得到的NMI意味着代码在指令中停留了很长一段时间(这可能是主循环中的WFI(),如果你有睡眠禁用,没有BLE活动超过2.6秒,这是看门狗可以测量的最大时间)。就一个例子而言,我想你已经熟悉了主机端的DSPS代码。
由于MT_dialog
你好MT_Dialog,
谢谢你的回复。现在我能够连接ble_app_peripheral与我的中央设备。下一个任务是从中央设备向ble_app_peripheral发送命令来切换LED。我可以使用自定义配置文件特征发送命令到ble_app_peripheral从中央设备,因为我们正在从BLE扫描仪应用程序?
与问候,
前腿帕特尔
你好,Ruchi Patel,
从中心与自定义配置文件交互,需要在中心端实现,因为当设备连接时,中心应该启动发现过程,以便发现可用的服务和特征。在中央发现外围端的特征之后,它就可以开始写入和读取数据,因为中央需要知道外围端应该读取或写入的句柄。简而言之,只要特征是可写的,你就可以向自定义特征写入数据,但你必须实现中心端的发现过程,然后你才能写入数据。DSPS主机端实现了DSPS配置文件的发现过程,您可以将其作为参考。
由于MT_dialog
谢谢你的快速回复。
我需要实现自定义服务和特征的发现过程。我没有发现关于发现程序的明确步骤。我也通过了DSPS的例子,但由于其复杂性,我不能正确地理解它。
1.你能详细列出发现程序的步骤吗?
2.在DSPS中,哪些文件发现相关的信息被提及?
3.哪些功能对发现自定义服务和特征有用?
与问候,
前腿帕特尔
你好,Ruchi Patel,
1.我不能在这个论坛上提到发现过程的每一个细节,你应该检查BLE规范,以便获得发现过程的广泛知识,我可以提到关于这个过程的几个关键步骤,并在DSPS源代码中给你一些代码片段,以便遵循。RW-BLE-GATT-IS.pdf也是一份非常有用的文档,该文档包含了为了完成发现过程而应该向堆栈发出或从堆栈发出的所有命令/响应。
由于MT_dialog
你好Dialog_Support,
感谢您提供的客户端配置步骤。我遵循你的步骤,但我得到错误。
1. \src\custom_profile\user_custs_config.c(47):错误:#29:期望表达式
struct attm_desc_128 custs1_att_db[CUST1_IDX_NB] = {};
struct cust_prf_func_callback cust_prf_funcs[] =
{
#如果(BLE_CUSTOM1_SERVER)
{TASK_CUSTS1,
custs1_att_db,
CUST1_IDX_NB,
#如果(BLE_APP_PRESENT)
app_custs1_create_db app_custs1_enable,
其他#
空,空,
# endif
custs1_init,零
},
# endif
#如果(BLE_CUSTOM2_SERVER)
{TASK_CUSTS2,
空,
0,
#如果(BLE_APP_PRESENT)
app_custs2_create_db app_custs2_enable,
其他#
空,空,
# endif
custs2_init,零
},
# endif
{task_none, null, 0, null, null, null, null}, //不移动。永远是最后一个
};
上面的函数我已经在user_custs_config.c中声明
和user_custs1_def.h中的as
extern struct attm_desc_128 custs1_att_db[CUST1_IDX_NB];
2.我应该写什么而不是#if (BLE_SPS_CLIENT)
与问候,
前腿帕特尔
你好,Ruchi Patel,
1.显然,为了包含自定义配置文件,您已经在DSPS主机中放置了custs1.h include,并且还没有将任何内容声明为数据库,请检查例如ble_app_peripheral示例,并检查该数组中有什么。
2.我不明白第二个问题,这只是一个定义,以包括SPS客户端功能。
由于MT_dialog
非常感谢您的步骤。这对我们帮助很大。经过长时间的学习,我逐渐发现了服务的特点。现在我的下一个任务是客户端和服务器之间的数据传输。你能告诉我哪个自定义函数启动数据传输程序吗?
谢谢和问候,
前腿帕特尔
你好,Ruchi Patel,
您的意思是,您想要执行从中心到外围的特性的写入操作?您可以使用DSPS示例实现的prf_gatt_write()命令,当然,该函数会向堆栈发送一个特定的消息,即GATTC_WRITE_CMD,您将能够在支持网站上的rw - bly - gatt - is .pdf中找到关于此的额外信息。
由于MT_dialog
嗨MT_Dialog,
是的,我想写数据从中央到外围设备的特征。
正如您建议使用“prf_gatt_write()”命令,我在DSPS示例中检查了它。据我所知,有一个名为“sps_client_data_tx_req_handler”的特定处理程序,它使用“prf_gatt_write()”命令处理传输请求。因此,在理想情况下,只要Central提出写入(data tx)请求,就应该调用该处理程序。但是,我不明白如何调用tx_req_handler。我究竟如何调用一个内置函数或编写我自己的函数,这将调用“sps_client_data_tx_req_handler”?
谢谢和问候,
前腿帕特尔
你好,Ruchi Patel,
您所看到的处理程序是DSPS参考应用程序的实现,如果您希望通过发送消息并通过消息处理事件而不是调用直接函数调用来触发写入事件,则可以实现类似DSPS项目的东西。当DSPS希望发送数据时,它实现一个名为SPS_CLIENT_DATA_TX_REQ的消息并将其发送到堆栈,然后堆栈一旦处理完消息就会触发相应的处理程序,SPS_CLIENT_DATA_TX_REQ消息通过user_send_ble_data()函数发送,由该消息触发的处理程序在sps_client_connected数组中的sps_client_task.c文件中声明,您可以将其作为参考。
由于MT_dialog
.
嗨MT_dialog,
最初,我还考虑使用“user_send_ble_data()”函数通过BLE发送数据。这个函数需要data和data_length作为参数。然后它将数据发送到一个预定的特征。但在我的例子中,我不希望总是将数据发送到固定的特征。
例如:
假设我有一个名为“Cust_Service_1”的自定义服务。在该服务中,我有一些自定义特征,如“led_1_亮度”,“led_2_亮度”等,其中写入无响应属性附加到他们。
现在,我想将0x57发送给“LED_1_Brightness”特性。
所以我想到的是一个简单的函数,它接受以下参数:
Uint8_t data[1] = {0x57};
Uint8_t length = 1;
取消my_function_to_send_data (Service_NameCust_Service_1,Charecteristic_NameLED_1_Brightness,Data_Value*数据,Data_Length长度);
由于"user_send_ble_data()"函数只接受数据,和数据长度;我如何确保我的数据被发送到我想要的正确特征?我是否应该像上面的例子那样为服务名称和特征名称附加附加参数?或者是否有其他方法可以先在外部某个变量中设置服务和特征名称,然后调用“user_send_ble_data()”函数,以便将数据发送到所需的特征?请帮帮我。
谢谢和问候,
前腿帕特尔
你好,Ruchi Patel,
如上所述,user_send_ble_data()是DSPS使用的函数,而不是将数据发送到服务上可用的任何特征的通用函数。实际发送数据的处理程序是sps_client_data_tx_req_handler(),实际发送数据的函数是prf_gatt_write()。由于这是实际发送另一侧数据的函数,因此这也是决定数据将被发送的特征句柄的函数。因此,通过使用相应的句柄参数调用prf_gatt_write()将更新适当的特征值。在dsp的情况下,sps_client_data_tx_req_handler中始终使用的特征句柄是spsc_env->sps.chars[SPSC_SRV_RX_DATA_CHAR].val_hdl。
由于MT_dialog
嗨MT_dialog,
正如你在之前的评论中正确提到的,sps_client_data_tx_req_handler ()是实际发送数据的函数。我想要一个简单的应用程序,用户按下一个按钮,它就会触发一个中断例程。在中断例程中,我想调用sps_client_data_tx_req_handler ()函数发送一些数据。该函数需要配置如下参数:
静态int sps_client_data_tx_req_handler(ke_msg_id_t const msgstr,
Struct sps_client_data_tx_req
Ke_task_id_t const dest_id,
Ke_task_id_t)
然而,我不知道每个参数传递什么,以便将我的数据发送到特定的特征。你能给我更多的见解吗?
谢谢和问候,
前腿帕特尔
你好,Ruchi Patel,
你可以在sps_client_data_tx_req结构体中添加一个额外的成员,并从该成员中传递你想要的特征,所以当你分配一个sps_client_data_tx_req消息时,你也应该在请求中传递你想要执行写的特征,例如,结构体目前有三个成员(conhdl, length和data),当消息在发送之前已分配时填充。所以添加一个额外的成员来保存你想要写的特征。当调用sps_client_data_tx_req_handler()而不是prf_gatt_write()中的固定值时,您可以传递在sps_client_data_tx_req结构中添加的额外成员的值。
由于MT_dialog
嗨MT_Dialog,
谢谢你的帮助。我成功地将数据写入了特定的特征。我使用了一种与你建议的略有不同的方法,但既然它能起作用,我不介意。以下是我的程序所做的总结:
因此,我目前可以从1个BLE客户端发送数据到1个BLE外围设备。注意,它们在整个会话中始终保持连接。
现在,我的项目只剩下最后一步了。有1个客户端(我正在使用),有4个外围设备。我有4个不同的用户输入按钮,根据按下的按钮,我想从我的BLE客户端发送数据到特定的BLE外围设备。这里是我现在想要实现的示例流:
注意,我不需要同时连接,我只需要连接到一个特定的设备,发送数据,然后断开连接。
我需要紧急执行。所以我希望能有一个具体详细的解决方案。请帮. . ! !
提前谢谢你,
前腿帕特尔
你好,Ruchi Patel,
你的用例非常具体,我无法预见或记录这个论坛上的每个具体细节,请检查我下面的建议。
为了通过中心连接到外设,外设需要进行广告(广告是为了让外设接收连接请求而需要的,而不仅仅是为了让中心扫描设备),所以您是假设您的外设将在那里发出连接请求而不需要扫描过程,还是您也将进行扫描?我猜想您将为您的设备使用公共地址,因为规范中定义的静态地址应该在每次重启外设时改变,并且随机可解析需要与每个单独的设备绑定。所以假设你正在使用公共地址,这些地址是你的中心已知的,据我所知,有两个选择:
1)假设设备已经就绪,并且没有来自中央的扫描过程,只要按下按钮,您就可以通过app_easy_gap_start_connection_to_set()和app_easy_gap_start_connection_to()发出连接,以启动连接过程,但再次,您必须确保设备正在发布广告,如果没有,则连接过程没有超时,如果没有人响应,则必须通过应用程序使该过程超时。所以只要设备连接起来,发现过程就会开始,设备就会在连接时做任何事情。一旦交换数据,您就可以调用app_easy_gap_disconnect()来断开外围设备与中心设备的连接,当断开连接发生时禁用并清理概要文件结构(取决于您如何实现自定义概要文件)。断开连接请求可以通过外围设备发出,也可以通过中心设备发出。
2)关于第二个选项,你可以按下按钮,并在一个全局变量中存储你想要连接到的对应的bd地址,所以当扫描过程在指示回调上返回特定的地址时,你可以发出连接请求。除此之外,其余的一切都保持不变。
由于MT_dialog
嗨MT_dialog,
我的最终目标是设计一个可编程BLE遥控器用于控制多个调光灯。因此,遥控器最初保持外围模式,并与android应用程序连接。然后,应用程序会告诉哪个按钮应该实现哪个功能。BLE远程仍然只保持在外围模式。但是只要用户按下按钮,比如button-1,它就会做以下事情:
我仍然没有弄清楚如何在运行时进行角色切换。所以目前我的可编程BLE遥控器一直处于中央模式。
为了在我的BLE遥控器的按钮上操作调光器,我写了以下代码:
bool gboolD1Connect = false;
空白user_button_pressed(空白)
{
gboolD1Connect = true;
/ / user_on_adv_report_ind (param - >报告。adv_addr_type: 0 x01);
if (dimmer1_connected == true) //只有在整个连接过程完成后才会为真
{
uint8_t my_data [1];
My_data [0] = 0x14;//亮度值
uint16_t my_length;
My_length = 1;
//该函数将数据从switch发送到dimmer
prf_gatt_write(con_info, val_hdl, (uint8_t *)my_data, sizeof(uint8_t) * my_length, GATTC_WRITE);
}
}
//这是内置函数,我修改了它,使它只在gboolD1Connect为true时连接到dimmer-1
struct gapm_adv_report_ind const * param
{
如果(gboolD1Connect)
{
如果(! memcmp (param - >报告。数据[3],USER_ADVERTISE_DATA, USER_ADVERTISE_DATA_LEN))
{
arch_printf(“连接%02x %02x %02x %02x %02x %02x”,
param - > report.adv_addr.addr [5],
param - > report.adv_addr.addr [4],
param - > report.adv_addr.addr [3],
param - > report.adv_addr.addr [2],
param - > report.adv_addr.addr [1],
param - > report.adv_addr.addr [0]);
app_easy_gap_start_connection_to_set (param - >报告。Adv_addr_type, (uint8_t *)¶m->report.adv_addr。addr, MS_TO_DOUBLESLOTS (12.5));
user_gapm_cancel ();
}
}
}
上面的实现可以工作,但是它有一个问题。当我第一次按遥控器上的按钮时,它就会凝固gboolD1Connect为true,然后退出函数,因为dimmer1_connected还不是真的。之后,在后台,当user_on_adv_report_ind ()运行时,它将连接到调光器-1。一旦连接完成,所有的服务、特征和描述符都将被发现。最后,在描述符发现完成之后,我又在要创建的内置函数中插入了一行Dimmer1_connected = true.整个过程需要2-3秒。3秒后,当我再次按下按钮时,它将最终进入Dimmer1_connected == true节并发送亮度值。如你所见,我得按两次按钮(第一个用于连接,第二个用于发送数据)能够发送数据。发生此问题是因为每当我给出连接到调光器设备的命令(通过使gboolD1Connect要真,还是要靠用app_easy_gap_start_connection_to_set ()函数),我必须退出中断例程,并允许主程序运行,以便实际连接可以发生。但是既然我已经退出了我的中断例程,我将如何重新进入它并在外围设备连接后发送数据?
所以我有两个问题需要帮助:
提前感谢你的帮助,
前腿帕特尔
嗨,前腿,
我建议您看一看CodeLess示例应用程序(https://support.dialog-semiconductor.com/connectivity/reference-design/smartbond-codeless-serial-link).
这个应用程序演示了中央和外围设备的各个方面,以及如何在角色之间切换。
/ MHv
嗨MHv,
你提出的建议真的很好,我很高兴能推进它的实施。但是看了文档,我明白实现它需要两件主要的事情:
(1)带AT命令固件的DA1458x BLE模块
(2)第三方微控制器控制BLE模块
但在我的情况下,我只有一个芯片上的DA1458x BLE模块。我没有权限在同一芯片上添加另一个第三方控制器来控制BLE模块。
我希望我的DA1458x BLE模块有一个AT固件,然后在逻辑上调用AT命令本身的序列以独立的方式操作。
那么,是否有可能实现AT命令方法,而不需要任何外部控制机制,如终端,android应用程序或第三方控制器?
谢谢,
前腿帕特尔
嗨,前腿,
实现应该只是用于指导如何完成不同的事情。通过运行代码并使用调试器逐步执行各种命令,您将能够了解看似复杂的任务是如何实现的。这里有一些例子:
CodeLess实现使用AT命令来触发不同的操作,但是应该可以编写自己的逻辑来驱动相同的功能(您可能只需要从CodeLess复制适用的代码片段到您的项目中)
/ MHv
我不能发现特征,但我可以发现服务,我的项目基于ble_app_peripheral
你能告诉我如何发现特征吗?
非常感谢!
嗨chenpenglai,
这个论坛帖子已经很旧了,所以我建议你创建一个新的。如果您不知道创建一个新的论坛线程应该遵循的程序,请告诉我,我会为您提供所需的所有步骤。所以,请创建一个新的论坛帖子和复制粘贴你的问题。
关于你的问题,你使用的是哪个版本的SDK ?你对SDK的ble_app_peripheral示例做了任何修改吗?
谢谢,PM_Dialog