TI提供的蓝牙BLE协议中就支持空中升级的功能。空中升级这个功能对于产品来说可真是福音,不需要任何有线的连接可以升级产品中的程序。这个空中升级其实并不是BLE协议中的一部分,而是在蓝牙传输数据的基础上做了一些拓展而已。蓝牙空中升级的代码主要在Oad_target.c、Oad_target.h及oad.h这三个文件中。下面开始详细分析(不考虑加密相关部分代码)。 1、与升级文件首部信息相关的几个定义 (1)升级文件首部结构定义 typedef struct { uint16 crc1; uint16 ver; uint16 len; uint8 uid[4]; uint8 res[4]; } img_hdr_t; 其中crc1用来保存升级文件计算得到的CRC值;ver为升级文件的版本;len保存这升级文件的大小,以4字节为单位;uid[4]用来表明当前升级文件身份是ImageA还是ImageB;res[4]保留给后续功能用。 (2)固件版本的定义 #if !defined (OAD_IMAGE_VERSION) #define OAD_IMAGE_VERSION 0x0000 #endif 当没有在其他地方定义过OAD_IMAGE_VERSION时,固件的版本就由这里的定义过了算。 (3)ImageA文件的标识 #if !defined (OAD_IMAGE_A_USER_ID) #define OAD_IMAGE_A_USER_ID {'A', 'A', 'A', 'A'} #endif 当没有在其他文件定义过OAD_IMAGE_A_USER_ID时,就用这里的4个"A"来标识ImageA。 (4)ImageB文件的标识 #if !defined (OAD_IMAGE_B_USER_ID) #define OAD_IMAGE_B_USER_ID {'B', 'B', 'B', 'B'} #endif 当没有在其他文件定义过OAD_IMAGE_B_USER_ID时,就用这里的4个"B"来标识ImageB。 (5)升级文件首部填充 #pragma location="IMAGE_HEADER" const __code img_hdr_t _imgHdr = { 0xFFFF, OAD_IMG_VER( OAD_IMAGE_VERSION ), OAD_IMG_R_AREA * OAD_FLASH_PAGE_MULT, #if defined HAL_IMAGE_A OAD_IMAGE_A_USER_ID, #else OAD_IMAGE_B_USER_ID, #endif { 0xFF, 0xFF, 0xFF, 0xFF } }; 第一句的#pragma location="IMAGE_HEADER"将这个首部布局在在链接文件所指定的IAMGE_HEADER空间。 首部的crc1成员的值必须为0xFFFF,因为这个值是在BIM代码中计算的。 首部的ver成员的值根据是ImageA还是ImageB而有所不同,如下: #if defined (HAL_IMAGE_A) #define OAD_IMG_VER( ver ) ( (uint16)( (ver) << 0x01 ) ) #else #define OAD_IMG_VER( ver ) ( (uint16)( ( (ver) << 0x01 ) | 0x01 ) ) #endif 简单来说,凡是奇版本的升级文件都是ImageA生成的,凡而偶版本的升级文件都是ImageB生成的。ver的实际版本号只使用高15位,而最低的一位用来区分ImageA与ImageB. 首部的uid[4]的根据ImageA还是ImageB而不同,用4个"A"表示为ImageA,用4个"B"表示为ImageB。 首部的res[4]则全部0xFF填充。 2、空中升级服务的UUID 跟一般的UUID不同的16位不同,空中升级所使用的UUID为128位的。 #define TI_BASE_UUID_128( uuid ) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x40, 0x51, 0x04, LO_UINT16( uuid ), HI_UINT16( uuid ), 0x00, 0xF0 所以UUID的形式为:F000XXXX-0451-4000-B000-000000000000 (1)空中升级服务的UUID #define OAD_SERVICE_UUID 0xFFC0 static CONST uint8 oadServUUID[ATT_UUID_SIZE] = { TI_BASE_UUID_128( OAD_SERVICE_UUID ) }; 所以空中升级服务的UUID为:F000FFC0-0451-4000-B000-000000000000。 (2)升级文件特征的UUID 升级文件特性的UUID包括两部分,第一部分是升级文件身份UUID, 另一部分是升级文件数据块的UUID,如下: #define OAD_IMG_IDENTIFY_UUID 0xFFC1 #define OAD_IMG_BLOCK_UUID 0xFFC2 { TI_BASE_UUID_128( OAD_IMG_IDENTIFY_UUID ), TI_BASE_UUID_128( OAD_IMG_BLOCK_UUID ) } 所以空中升级文件身份的UUID为:F000FFC1-0451-4000-B000-000000000000和空中升级文件数据块UUID为::F000FFC2-0451-4000-B000-000000000000。 3、空中升级服务在GATT层上的属性配置 以数组的形式向GATT层注册空中的各种属性: static gattAttribute_t oadAttrTbl[] = {}; 这个数组共9个成员,主要包括:空中升级服务属性、空中升级身份属性及空中升级数据块属性。 (1)空中升级服务属性 static CONST gattAttrType_t oadService = { ATT_UUID_SIZE, oadServUUID }; { { ATT_BT_UUID_SIZE, primaryServiceUUID }, GATT_PERMIT_READ, 0, (uint8 *)&oadService }, (2)空中升级身份属性 (a)空中升级身份特征声明 static uint8 oadCharProps = GATT_PROP_WRITE_NO_RSP | GATT_PROP_WRITE | GATT_PROP_NOTIFY; { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &oadCharProps }, (b)空中升级身份特征值 static uint8 oadCharVals[OAD_CHAR_CNT]; { { ATT_UUID_SIZE, oadCharUUID[0] }, GATT_PERMIT_WRITE, 0, oadCharVals+0 }, (c)空中升级身份客户端特征配置 static gattCharCfg_t oadImgIdentifyConfig[GATT_MAX_NUM_CONN]; { { ATT_BT_UUID_SIZE, clientCharCfgUUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *)oadImgIdentifyConfig }, (d)空中升级身份特征描述 static CONST uint8 oadImgIdentifyDesc[] = "Img Identify"; { { ATT_BT_UUID_SIZE, charUserDescUUID }, GATT_PERMIT_READ, 0, (uint8 *)oadImgIdentifyDesc }, (3)空中升级数据块属性 (a)空中升级数据块特征声明 static uint8 oadCharProps = GATT_PROP_WRITE_NO_RSP | GATT_PROP_WRITE | GATT_PROP_NOTIFY; { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &oadCharProps }, (b)空中升级数据块特征值 static uint8 oadCharVals[OAD_CHAR_CNT]; { { ATT_UUID_SIZE, oadCharUUID[1] }, GATT_PERMIT_WRITE, 0, oadCharVals+1 }, (c)空中升级数据块客户端特征配置 static gattCharCfg_t oadImgBlockConfig[GATT_MAX_NUM_CONN]; { { ATT_BT_UUID_SIZE, clientCharCfgUUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *)oadImgBlockConfig }, (d)空中升级数据块描述 static CONST uint8 oadImgBlockDesc[] = "Img Block"; { { ATT_BT_UUID_SIZE, charUserDescUUID }, GATT_PERMIT_READ, 0, (uint8 *)oadImgBlockDesc } 4、关于升级文件数据块传输的几个变量 升级文件传输时,以一个块(16字节)为单位传输,可以通过获取升级文件的总数据块数及已传输的数据块数来得到升级文件的传输进程。 (1)升级文件的总数据块数 static uint16 oadBlkTot = 0xFFFF; (2)升级文件已传输的数据块数 static uint16 oadBlkNum = 0; 5、注册空中升级属性操作回调函数,有读、写、授权三个,这里只使用读写属性。 CONST gattServiceCBs_t oadCBs = { oadReadAttrCB, /* Read callback function pointer. */ oadWriteAttrCB, /* Write callback function pointer. */ NULL /* Authorization callback function pointer. */ };
OADTarget_AddService() 向蓝牙协议添加空中升级服务 1、初始化空中升级身份客户端特征配置和空中升级数据块客户端配置 GATTServApp_InitCharCfg( INVALID_CONNHANDLE, oadImgIdentifyConfig ); GATTServApp_InitCharCfg( INVALID_CONNHANDLE, oadImgBlockConfig ); 2、向LinkDB层注册连接状态改变回调函数 VOID linkDB_Register( oadHandleConnStatusCB ); 3、向GATT注册空中升级服务的属性列表和属性操作回调函数 return GATTServApp_RegisterService(oadAttrTbl, GATT_NUM_ATTRS(oadAttrTbl), &oadCBs); oadHandleConnStatusCB() 连接状态改变回调函数 参数: connHandle-连接的句柄 changeType-改变的状态 当连接断开时,则复位客户端特征配置。 if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && ( !linkDB_Up( connHandle ) ) ) ) { GATTServApp_InitCharCfg( connHandle, oadImgIdentifyConfig ); GATTServApp_InitCharCfg( connHandle, oadImgBlockConfig ); }
oadReadAttrCB() 空中升级读属性回调 空中升级服务的个属性中,读的属性,所以这个函数形同虚设。 *pLen = 0; status = ATT_ERR_INVALID_HANDLE; return status;
oadWriteAttrCB() 空中升级写属性回调 参数: connHandle-客户端连接句柄 *pAttr-要操作的属性 *pValue-要写入的属性的值 offset-偏移 写属性要分16位UUID和128位UUID而不同处理。16位的UUID主要是客户端特征配置,而128位的UUID主要是升级文件身份属性和升级文件数据块属性。 1、16位的UUID (1)获取16位的UUID uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); (2)如是客户端配置UUID,则嗲偶偶那个GATT函数处理这个写请求 if ( uuid == GATT_CLIENT_CHAR_CFG_UUID) { status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY ); }
|