SYD8801从机和TIcc2540主机进行通讯(通过修改主机端代码实现)
SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。具体可咨询:http://www.syd-tek.com/
SYD8801从机和TIcc2540主机进行通讯
关于TI主机的代码基本解析请看:http://blog.****.net/chengdong1314/article/details/73701973
注意:
TI的主机发现特性的handle是通过ATT的Read By Type Request命令的,这时候type(请求的类型)发的却是具体的特性的UUID(比如写特性uuid:0x0002)。这个和手机请求特性handle的方式不一样,手机虽然也是通过ATT的Read By Type Request命令,但是其发送的确实特性的类型UUID:0x2803,而不是具体的特性!所以要让TI的主机和SYD8801能够正常通讯,其中的一条思路就是改变TI主机发现特性的方式,修改办法如下:
从上篇博客可知ti主机获取特性和服务的方式是在simpleBLECentralStartDiscovery函数中发送GATT_DiscPrimaryServiceByUUID命令获取到服务,然后协议栈将调用simpleBLEGATTDiscoveryEvent函数来获取特性等,这里主要是在simpleBLEGATTDiscoveryEvent函数中修改:
1.Read By Type Request命令中发送的参数是特性的类型UUID:0x2803,修改前代码如下左图,修改后的代码如下右图:
2.原来的方式只能够获取到一个特性的handle,而新的方式却是能够获取到所有特性的handle,所以这里要在获取到特性后修改保存handle的方法,修改前代码如下左图,修改后的代码如下右图:
修改前的simpleBLEGATTDiscoveryEvent函数如下:
static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
attReadByTypeReq_t req;
BLE_DEV *p = simpleBLECentralGetDev(pMsg->connHandle);
if ( p->simpleBLEDiscState == BLE_DISC_STATE_SVC )
{
// Service found, store handles
if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0 )
{
p->simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
p->simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
}
// If procedure complete
if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete ) ||
( pMsg->method == ATT_ERROR_RSP ) )
{
if ( p->simpleBLESvcStartHdl != 0 )
{
// Discover characteristic
p->simpleBLEDiscState = BLE_DISC_STATE_CHAR1;
req.startHandle = p->simpleBLESvcStartHdl;
req.endHandle = p->simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID( p->simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
}
else if ( p->simpleBLEDiscState == BLE_DISC_STATE_CHAR1 )
{
NPI_PrintValue("1 pMsg->method", pMsg->method, 10);
NPI_PrintValue("1 numPairs", pMsg->msg.readByTypeRsp.numPairs, 10);
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
p->simpleBLECharHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "CHAR 1 Found", HAL_LCD_LINE_3 );
p->simpleBLEProcedureInProgress = TRUE;
}
else // pMsg->msg.readByTypeRsp.numPairs is 0.
{
p->simpleBLEDiscState = BLE_DISC_STATE_CHAR6;
req.startHandle = p->simpleBLESvcStartHdl;
req.endHandle = p->simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);
GATT_ReadUsingCharUUID( p->simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
else if (p->simpleBLEDiscState == BLE_DISC_STATE_CHAR6)
{ // Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
p->simpleBLECharHdl[5] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "CHAR 6 Found", HAL_LCD_LINE_4 );
p->simpleBLEProcedureInProgress = FALSE;
}
p->simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
}
修改后的simpleBLEGATTDiscoveryEvent函数如下:
static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
attReadByTypeReq_t req;
BLE_DEV *p = simpleBLECentralGetDev(pMsg->connHandle);
if ( p->simpleBLEDiscState == BLE_DISC_STATE_SVC )
{
// Service found, store handles
if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0 )
{
p->simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
p->simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
}
NPI_PrintValue("0 pMsg->method", pMsg->method, 10);
// If procedure complete
if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete ) ||
( pMsg->method == ATT_ERROR_RSP ) )
{
NPI_PrintValue("0 status", pMsg->hdr.status, 10);
if ( p->simpleBLESvcStartHdl != 0 )
{
// Discover characteristic
p->simpleBLEDiscState = BLE_DISC_STATE_CHAR1;
req.startHandle = p->simpleBLESvcStartHdl;
req.endHandle = p->simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(0x2803);
req.type.uuid[1] = HI_UINT16(0x2803);
GATT_ReadUsingCharUUID( p->simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
}
else if ( p->simpleBLEDiscState == BLE_DISC_STATE_CHAR1 )
{
NPI_PrintValue("1 pMsg->method", pMsg->method, 10);
NPI_PrintValue("1 numPairs", pMsg->msg.readByTypeRsp.numPairs, 10);
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
p->simpleBLECharHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[3],
pMsg->msg.readByTypeRsp.dataList[4] );
p->simpleBLECharHdl[1] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[3+pMsg->msg.readByTypeRsp.len],
pMsg->msg.readByTypeRsp.dataList[4+pMsg->msg.readByTypeRsp.len] );
LCD_WRITE_STRING( "CHAR Found", HAL_LCD_LINE_3 );
p->simpleBLEProcedureInProgress = TRUE;
p->simpleBLEDiscState = BLE_DISC_STATE_IDLE;
p->simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
}
把修改后的TI主机的代码烧录到cc2540中,并且在SYD8801上烧录开发板的程序,即可做测试,测试步骤对于SYD8801十分简单,直接把程序下载到开发板运行即可,对于TICC2540测试步骤如下;
1.按下五向键的上键(UP),这时候TICC2540开始扫描设备,这里会列出设备列表,如果发现了SYD8801,那么SYD8801的地址(0XFF1122334455)会显示到OLED上
2.当搜索到SYD8801的地址后按下五向键的中间键开始连接搜索到的地址列表中的每一项!连接完成后会自动的去发现服务获取特性的handle
3.当正确获取到特性的handle后按下开发板上的S1键这是TICC2540将向SYD8801发送数据,这时候在SYD8801的OLED上将看到CC2540发送过来的数据,最后截图如下:
最后上传以上内容的设计到的代码:
TICC2540主机端的程序:http://download.****.net/detail/chengdong1314/9882423
syd8801从机端的程序:http://download.****.net/detail/chengdong1314/9882392
要增加notify功能,在主机上要两个步骤:
1.在发现完服务之后主机发送使能notify的命令给从机,这里通过按下五向键的左键实现,其源代码如下:
if ( keys & HAL_KEY_LEFT )
{
BLE_DEV *p = simpleBLECentralGetDev(0);
attWriteReq_t req;
uint8 value[20];
uint8 status;
value[0]=1;
value[1]=0;
req.handle = p->simpleBLECharHdl[1]+1;
req.len = 2;
//req.value[0] = value;//p->simpleBLECharVal;
osal_memcpy(req.value, value, 2);
req.sig = 0;
req.cmd = 0;
//NPI_PrintValue("DoWrite :", p->simpleBLECharVal, 10);
status = GATT_WriteCharValue( p->simpleBLEConnHandle, &req, simpleBLETaskId ); // 发送数据
NPI_PrintString(" [KEY LEFT pressed!]\r\n");
}
其实就是往0x0003的CCCD(0x2902)特性写入0x01,0x00,这样就使能了notify,这里我们是在已经知道读特性(p->simpleBLECharHdl[1])的下一个特性就是CCCD特性,所以我这里直接往这个特性写,并不会去判断这个特性!
2.当使能了notily之后下一步操作就是监听notify等待协议栈回调notify事件,我们只需要在协议栈回调notify事件的时候显示出发送过来的内容即可,协议栈回调notify事件在simpleBLECentralProcessGATTMsg函数的else if ( ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) )分支进行处理,这里我们处理的源代码如下:
else if ( ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) ) //通知
{
if( pMsg->msg.handleValueNoti.handle == p->simpleBLECharHdl[1]) //CHAR6的通知 串口打印
{
//1, 收到的数据通过显示屏显示出来
// 这里要提醒一下,从机中只有char6 才具有notify 功能, 因此, 从机发送上来的数据就是char6的, 最大19个子节
// 另外,如果这个主机连接了几个从机, 那么也都是通过这里进来数据, 那么如何区分是什么从机发送过来的呢
// 这个时候,我们自然是想到这个函数的形参 gattMsgEvent_t *pMsg
// 通过查找 发现 gattMsgEvent_t -> connHandle 就是连接handle, 每个从机的连接handle是唯一的, 我们可以用这个来区分是何从机
// 为了简单,我们假设从机发送过来的数据是字符串,这样我们直接显示就行, 无需做更多处理
char str[32] = {0};
char str2[32] = {0};
// 根据 connHandle 查找对应的设备
BLE_DEV *p = simpleBLECentralGetDev(pMsg->connHandle);
osal_memcpy(str, pMsg->msg.handleValueNoti.value, pMsg->msg.handleValueNoti.len );
//1, 显示在oled显示屏上
sprintf(str2, "[%d]:%s", p->simpleBLEDevIdx, str);
HalLcdWriteString(str2, HAL_LCD_LINE_8 );
//2, 这里是收到的数据通过串口透传出去
// NPI_WriteTransport(pMsg->msg.handleValueNoti.value, pMsg->msg.handleValueNoti.len );
//3, 这里是收到从机数据时闪灯
HalLedBlink (HAL_LED_3, 1, 50, 100);//这个的意思是, 100ms内,以50%的占空比闪烁1次, 实际就是点亮50ms
}
}
这里的操作就是判断是否是读特性的notify,如果是就打印SYD8801发送过来的内容即可!这里在OLED的最后一行打印!
这里测试结果如下图:
这里上传本节使用到的源代码,注意:带有notify功能的源代码不管是salve还是master都是不一样的,请用如下代码进行测试:
TICC2540 master端源代码:http://download.****.net/detail/chengdong1314/9883303
SYD8801 salve源代码:http://download.****.net/detail/chengdong1314/9883300