【BLE】CC2541之AT指令实时修改设备名称

devtools/2025/1/16 9:43:24/

本文最后修改时间:2020年02月07日 19:32

一、本节简介

本文以SimpleBLEPeripheral工程为例,介绍如何使用AT指令来修改设备名称,且不需要重启设备,断开连接时即可看到广播中修改后的设备名称。

二、实验平台

1)CC2541平台

①协议栈版本:BLE-CC254x-1.4.0

②编译软件:IAR 8.20.2

③硬件平台:香瓜CC2541开发板

④仿真器:香瓜CC Debugger下载器

2)手机平台

①手机型号:小米8

②安卓版本:安卓8

③安卓app:TruthBlue

三、版权声明

1)作者:甜甜的大香瓜

2)声明:喝水不忘挖井人,转载请注明出处。

3)纠错/业务合作:897503845@qq.com

4)香瓜BLE之CC2541群:127442605

5)本文出处:原创连载资料《简单粗暴学蓝牙4.0(CC2541篇)》

6)完整开源资料下载地址(电脑端打开):

opengua.taobao.com

7)香瓜CC2541开发板套件购买:

opengua.taobao.com

四、实验前提

1、在进行本文步骤前,请先阅读以下章节:

1)《简单粗暴学蓝牙4.0(CC2541篇)》的“第一章至第三章”章节

2)《简单粗暴学蓝牙4.0(CC2541篇)》的《CC2541之动态更新设备名》

3)《简单粗暴学蓝牙4.0(CC2541篇)》的《CC2541之SNV》

2、在进行本文步骤前,请先实现以下章节:

1)《简单粗暴学蓝牙4.0(CC2541篇)》的“第三章 软件的安装及使用”章节。

2)《简单粗暴学蓝牙4.0(CC2541篇)》的《CC2541之串口透传(20字节内任意长度)》

五、基础知识

暂无

六、硬件原理

暂无

七、实验步骤

1、添加SNV头文件(SimpleBLEPeripheral.c中)

#include “osal_snv.h”

2添加设备名称所用的宏定义(SimpleBLEPeripheral.c中)

//GUA

//SNV的设备名称使用

#define GUA_SNV_DEVICE_NAME_ID          0x80

#define GUA_SNV_DEVICE_NAME_READ        0x00

#define GUA_SNV_DEVICE_NAME_WRITE       0x01

//GUA

3添加SNV读写设备名称数据的函数

1定义SNV读写设备名称数据的函数(SimpleBLEPeripheral.c中)

//******************************************************************************

//name:         GUA_SNV_DeviceName

//introduce:    从 SNV 读取或写入设备名称

//parameter:    nGUA_WriteReadFlag:GUA_SNV_DEVICE_NAME_READ or GUA_SNV_DEVICE_NAME_WRITE

//              pGUA_DeviceName:设备名称结构体

//return:       none

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜 BLE 之 CC2541(127442605)

//shop:         opengua.taobao.com

//changetime:   2020.01.18

//******************************************************************************

static void GUA_SNV_DeviceName(uint8 nGUA_WriteReadFlag, ST_GUA_DEVICE_NAME *pGUA_DeviceName)

{

  uint8 nGUA_Ret;

  ST_GUA_DEVICE_NAME aGUA_Default_DeviceName = {7, “opengua”};

  //从SNV读设备名称

  if(nGUA_WriteReadFlag == GUA_SNV_DEVICE_NAME_READ)

  {

nGUA_Ret = osal_snv_read(GUA_SNV_DEVICE_NAME_ID, sizeof(stGUA_Device_Name), pGUA_DeviceName);

   

//如果第一次读取失败,则说明没有写过,是出厂的设备。因此在这里设置为出厂设备名称。

If(nGUA_Ret == NV_OPER_FAILED)

{

      //将出厂设备名称写入snv中

      osal_snv_write(GUA_SNV_DEVICE_NAME_ID, sizeof(stGUA_Device_Name), &aGUA_Default_DeviceName);

      //读出设备名称

      osal_snv_read(GUA_SNV_DEVICE_NAME_ID, sizeof(stGUA_Device_Name), pGUA_DeviceName);

}

  }

  //写新的设备名称到SNV

  else if(nGUA_WriteReadFlag == GUA_SNV_DEVICE_NAME_WRITE)

  {

//写进新的设备名称

osal_snv_write(GUA_SNV_DEVICE_NAME_ID, (pGUA_DeviceName->Len)+1, pGUA_DeviceName);

//读出新的设备名称

nGUA_Ret = osal_snv_read(GUA_SNV_DEVICE_NAME_ID, (pGUA_DeviceName->Len)+1, pGUA_DeviceName);

  }

}

每次上电时会调用此函数,将设备名称的结构体数据从SNV中读出。第一次出厂名称为“opengua”。

2声明SNV读写设备名称数据的函数(SimpleBLEPeripheral.c中)

//GUA

static void GUA_SNV_DeviceName(uint8 nGUA_WriteReadFlag, ST_GUA_DEVICE_NAME *pGUA_DeviceName);

//GUA

4、添加设备名称结构体SimpleBLEPeripheral.c中的最上方

//GUA

typedef struct{

  uint8 Len;

  uint8 Name[GAP_DEVICE_NAME_LEN];    

}ST_GUA_DEVICE_NAME;

ST_GUA_DEVICE_NAME stGUA_Device_Name;     

//GUA

之所以需要放在最上方,是因为声明函数中使用到此结构体,因此需要比声明函数位置更上方。

5、替换代码SimpleBLEPeripheral.c中的SimpleBLEPeripheral_Init

//GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );

替换成

//GUA

uint8 aGUA_ScanRspData_Temp[B_MAX_ADV_LEN] = {0}; 

uint8 nGUA_I = 0; 

   

//GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );

   

//从SNV中读出设备名称结构体

GUA_SNV_DeviceName(GUA_SNV_DEVICE_NAME_READ, &stGUA_Device_Name);

   

//保存名称数据字段

aGUA_ScanRspData_Temp[nGUA_I++] = 1 + stGUA_Device_Name.Len;        //名称字段的长度=1(数据类型长度)+数据长度

aGUA_ScanRspData_Temp[nGUA_I++] = GAP_ADTYPE_LOCAL_NAME_COMPLETE;   //名称字段的数据类型

osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], stGUA_Device_Name.Name, stGUA_Device_Name.Len);//复制名称数据

//保存原来历程中的后续数据字段

nGUA_I += stGUA_Device_Name.Len;

osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], (scanRspData+21), 9);

nGUA_I += 9;

   

//将扫描应答数据传给协议栈

GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, nGUA_I, aGUA_ScanRspData_Temp);   

//GUA

此处是在上电初始化时,将SNV的设备名称数据读出,并替换掉原来协议栈中的设备名称。但又保持原来扫描应答包的其他数据段。

6替换香瓜profile的回调函数(SimpleBLEPeripheral.c中)

//******************************************************************************

//name:         GUAProfileChangeCB

//introduce:    主机写入时的回调函数

//parameter:    paramID:特征值id

//return:       none

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜 BLE 之 CC2541(127442605)

//shop:         opengua.taobao.com

//changetime:   2020.01.19

//******************************************************************************

static void GUAProfileChangeCB( uint8 paramID )

{

  switch( paramID )

  {

case GUAPROFILE_CHAR1:

      {

        uint16 nGUA_NotifyHandle;

        uint8 aGUA_Buf[20] = {0};

        uint8 aGUA_AT[3] = “AT+”;  

        uint8 aGUA_AT_OK[5] = “AT+OK”;

        uint8 aGUA_ScanRspData_Temp[B_MAX_ADV_LEN] = {0}; 

        uint8 nGUA_I = 0;

       

        //获取句柄

        GAPRole_GetParameter(GAPROLE_CONNHANDLE, &nGUA_NotifyHandle);

       

        //获取主机发来的数据

        GUAProfile_GetParameter(GUAPROFILE_CHAR1, aGUA_Buf);

       

        //判断是否是AT指令,如果是AT指令,则是修改名称的指令,否则从串口透传出去

        if(osal_memcmp(aGUA_Buf, aGUA_AT, 3) == TRUE)

        {

          //保存名称数据长度和名称数据到SNV

          stGUA_Device_Name.Len = gnGUA_len -3;

          osal_memcpy(stGUA_Device_Name.Name, (aGUA_Buf+3), stGUA_Device_Name.Len);

          GUA_SNV_DeviceName(GUA_SNV_DEVICE_NAME_WRITE, &stGUA_Device_Name);       

          //保存名称数据字段到扫描应答包的缓冲区

          aGUA_ScanRspData_Temp[nGUA_I++] = 1 + stGUA_Device_Name.Len;        //名称字段的长度=1(数据类型长度)+数据长度

          aGUA_ScanRspData_Temp[nGUA_I++] = GAP_ADTYPE_LOCAL_NAME_COMPLETE;   //名称字段的数据类型

          osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], stGUA_Device_Name.Name, stGUA_Device_Name.Len);//复制名称数据

          

          //保存原来历程中的后续数据字段到扫描应答包的缓冲区

          nGUA_I += stGUA_Device_Name.Len;

          osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], (scanRspData+21), 9);

          nGUA_I += 9;

             

          //更新扫描应答包

          GAP_UpdateAdvertisingData(simpleBLEPeripheral_TaskID,

                                    FALSE,

                                    nGUA_I,

                                    aGUA_ScanRspData_Temp);                      

         

          //返回数据

          GUAprofile_Notify(GUAPROFILE_CHAR1, nGUA_NotifyHandle, aGUA_AT_OK, sizeof(aGUA_AT_OK));

        }

        else

        {

          //通过串口发送出去

          NPI_WriteTransport(aGUA_Buf, gnGUA_len);         

        }    

        break;

      }

     

default:break;

  }

}

如果是AT指令,则为修改名称,香瓜在此添加了实时修改名称的代码处理。如果不是AT指令,则为串口透传。

八、注意事项

1、手机可能缓存了之前固件的数据(在更新过固件之后,都需要清除手机端的缓存!!!),因此要清除缓存,清除缓存的方法如下:

方法一:关闭app、关闭蓝牙总开关、打开蓝牙总开关、打开app。

方法二:手机重启。

九、实验结果

   

上述三张图,分别为默认设备名称、修改名称指令、修改后的设备名称。

香瓜实现的是不需要重启即可实现的修改设备名称。

因此,实验成功。


http://www.ppmy.cn/devtools/150912.html

相关文章

【Apache Paimon】-- 源码解读之 PaimonSparkSessionExtensions

目录 1. spark.sql.extensions 简介 2. PaimonSparkSessionExtensions 详解 (1) 解析器扩展 (Parser Extensions) (2) 分析器扩展 (Analyzer Extensions) (3) 表值函数扩展 (Table Function Extensions) (4) 优化器扩展 (Optimizer Extensions) (5) 执行计划扩展 (Plann…

如何提高自动化测试覆盖率和效率

用ChatGPT做软件测试 在现代软件开发中,自动化测试已经成为保证软件质量的重要手段。然而,在实践中,自动化测试的覆盖率和效率常常受到限制,导致潜在缺陷未能及时发现或测试资源浪费。因此,提升自动化测试的覆盖率和效…

React:构建用户界面的JavaScript库

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

数据结构(Java版)第八期:LinkedList与链表(三)

专栏:数据结构(Java版) 个人主页:手握风云 目录 一、链表中的经典面试题 1.1. 链表分割 1.2. 链表的回文结构 1.3. 相交链表 1.4. 环形链表 一、链表中的经典面试题 1.1. 链表分割 题目中要求不能改变原来的数据顺序,也就是如上图所示。…

aarch64页表管理[1] 宏定义与头文件概览

文章目录 头文件与宏定义概览aarch64架构特定头文件通用头文件和页表无关的公共定义kernel config 头文件内容说明arch/arm64/include/asm/memory.hinclude/asm-generic/page.harch/arm64/include/asm/pgtable-types.harch/arm64/include/asm/pgtable.hpgtable-hwdef.hpage-def…

VSCode连接远程docker环境

容器内部署操作,进入容器 1、安装 ssh 服务 apt-get install openssh-server /etc/init.d/ssh start 设置 root 用户密码 passwd root 修改 ssh 配置文件 vim /etc/ssh/sshd_config 在末尾“插入模式”添加下面内容: RSAAuthentication yes Pu…

【C++】面试题整理(未完待续)

【C】面试题整理 文章目录 一、概述二、C基础2.1 - 指针在 32 位和 64 位系统中的长度2.2 - 数组和指针2.3 - 结构体对齐补齐2.4 - 头文件包含2.5 - 堆和栈的区别 三、智能指针3.1 - 智能指针是线程安全的吗?3.2 - 线程安全的几种方法 三、参考 一、概述 最近面试&…

STM32F1——CAN驱动代码

一、 CAN.H。 #ifndef __CAN_H #define __CAN_H #include "stm32f10x.h" #include "SysTick.h" //PA11--CANRX PA12--CANTX //CAN接收RX0中断使能 #define CAN_RX0_INT_ENABLE 0 //0,不使能;1,使能.u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 …