/** ****************************************************************************** * @file hgics_blenc.c * @author HUGE-IC Application Team * @version V1.0.0 * @date 2022-05-18 * @brief hgic BLE network configure lib ****************************************************************************** * @attention * *

© COPYRIGHT 2022 HUGE-IC

* ****************************************************************************** */ #ifndef __RTOS__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #else #include #include #endif #include "hgic.h" #define ATT_MTU (512) #define BT_L2CAP_HDR_SIZE (4) #define HCI_CONN_HANDLE (1) #define HCI_ACL_HDR_SIZE (4) #define HCI_ACL_DATA_PACKET (2) #define HGICS_GATT_CHARAC_Broadcast (0x01) #define HGICS_GATT_CHARAC_Read (0x02) #define HGICS_GATT_CHARAC_Write_Without_Response (0x04) #define HGICS_GATT_CHARAC_Write (0x08) #define HGICS_GATT_CHARAC_Notify (0x10) #define HGICS_GATT_CHARAC_Indicate (0x20) #define HGICS_GATT_CHARAC_Authenticated_Signed_Writes (0x40) #define HGICS_GATT_CHARAC_Extended_Properties (0x80) #define BLENC_STR_CUTDOWN_BUFFER_LEN (1024) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) int hgic_gatt_notify(uint16_t att_hdl, char *data, int len); typedef int (*hgic_gatt_valhdl)(int hdl, int offset, char *data, int len); struct hgic_gatt_hdr { uint16_t att_hdl; union { uint8_t att_type_128[16]; uint16_t att_type; }; uint16_t priv_type; }; struct hgic_gatt_primary_service { struct hgic_gatt_hdr hdr; union { uint8_t att_type_128[16]; uint16_t att_type; }; }; struct hgic_gatt_characteristic { struct hgic_gatt_hdr hdr; uint8_t properties; uint16_t value_hdl; union { uint8_t value_type_128[16]; uint16_t value_type; }; }; struct hgic_gatt_characteristic_value { struct hgic_gatt_hdr hdr; hgic_gatt_valhdl read_cb; hgic_gatt_valhdl write_cb; }; #define HGICS_GATT_PRIMARY_SVR(hdl, type) struct hgic_gatt_primary_service att##hdl = {\ .hdr = { \ .att_hdl = (hdl), \ .att_type = 0x2800,\ .priv_type = 1,\ }, \ .att_type = (type),\ } #define HGICS_GATT_PRIMARY_SVR_128(hdl, type_128) struct hgic_gatt_primary_service att##hdl = {\ .hdr = { \ .att_hdl = (hdl), \ .att_type = 0x2800,\ .priv_type = 11,\ }, \ .att_type_128 = type_128,\ } #define HGICS_GATT_CHARACTER(hdl, flag, v_hdl, v_type) struct hgic_gatt_characteristic att##hdl = {\ .hdr = { \ .att_hdl = (hdl), \ .att_type = 0x2803,\ .priv_type = 2,\ }, \ .properties = (flag),\ .value_hdl = (v_hdl),\ .value_type = (v_type),\ } #define HGICS_GATT_CHARACTER_128(hdl, flag, v_hdl, v_type_128) struct hgic_gatt_characteristic att##hdl = {\ .hdr = { \ .att_hdl = hdl, \ .att_type = 0x2803,\ .priv_type = 21,\ }, \ .properties = flag,\ .value_hdl = v_hdl,\ .value_type_128 = v_type_128,\ } #define HGICS_GATT_CHARACTER_VALUE(hdl, type, read, write) struct hgic_gatt_characteristic_value att##hdl = {\ .hdr = { \ .att_hdl = (hdl), \ .att_type = (type),\ .priv_type = 4,\ }, \ .read_cb = (read),\ .write_cb = (write),\ } #define HGICS_GATT_CHARACTER_VALUE_128(hdl, type_128, read, write) struct hgic_gatt_characteristic_value att##hdl = {\ .hdr = { \ .att_hdl = hdl, \ .att_type_128 = type_128,\ .priv_type = 41,\ }, \ .read_cb = read,\ .write_cb = write,\ } #define HGICS_GATT_CHARACTER_CCCD(hdl, read, write) struct hgic_gatt_characteristic_value att##hdl = {\ .hdr = { \ .att_hdl = (hdl), \ .att_type = (0x2902),\ .priv_type = 4,\ }, \ .read_cb = (read),\ .write_cb = (write),\ } /* static inline void put_unaligned_le16(unsigned short val, unsigned char *p) { *p++ = val; *p++ = val >> 8; } static inline unsigned short get_unaligned_le16(const unsigned char *p) { return p[0] | p[1] << 8; } */ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// int ble_connected = 0; int att_mtu = 23; int mtu_exchanged = 0; int ble_ll_length = 27; ////////////////////////////////////////////////////////////////////////////// /* Define GATT Service --- Demo Service */ ////////////////////////////////////////////////////////////////////////////// extern int demo_app_recv_attdata(int hdl, int offset, char *data, int len); extern int demo_app_read_attdata(int hdl, int offset, char *data, int len); /* 通用UUID的定义,参考文档《BLE_Assigned_Numbers.pdf》, section 3: 16-bit UUIDs*/ /* Primary Service 1 */ HGICS_GATT_PRIMARY_SVR(1, 0x1800); HGICS_GATT_CHARACTER(2, HGICS_GATT_CHARAC_Read, 3, 0x2a00); HGICS_GATT_CHARACTER_VALUE(3, 0x2a00, demo_app_read_attdata, NULL); HGICS_GATT_CHARACTER(4, HGICS_GATT_CHARAC_Read, 5, 0x2a01); HGICS_GATT_CHARACTER_VALUE(5, 0x2a01, demo_app_read_attdata, NULL); /* Primary Service 2 */ #if 0 //demo1, UUID 128 #define server_uuid {0x00,0x00,0x18,0x2c,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0x80,0x5f,0x9b,0x34,0xfb} #define data_uuid {0x00,0x00,0x2A,0x7A,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0x80,0x5f,0x9b,0x34,0xfb} #define notity_uuid {0x00,0x00,0x2A,0x80,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0x80,0x5f,0x9b,0x34,0xfb} HGICS_GATT_PRIMARY_SVR_128(6, server_uuid); HGICS_GATT_CHARACTER_128(7, HGICS_GATT_CHARAC_Write_Without_Response, 8, data_uuid); HGICS_GATT_CHARACTER_VALUE_128(8, data_uuid, demo_app_read_attdata, demo_app_recv_attdata); HGICS_GATT_CHARACTER_128(9, HGICS_GATT_CHARAC_Notify, 10, notity_uuid); HGICS_GATT_CHARACTER_VALUE_128(10, notity_uuid, NULL, NULL); HGICS_GATT_CHARACTER_CCCD(11, NULL, NULL); #endif #if 0 //demo2, UUID 128 #define server_uuid {0x06,0x05,0x04,0x03,0x02,0x01,0x03,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0x00,0x36} #define data_uuid {0x06,0x05,0x04,0x03,0x02,0x01,0x03,0x00,0x02,0x00,0x01,0x00,0x02,0x00,0x00,0x36} #define notity_uuid {0x06,0x05,0x04,0x03,0x02,0x01,0x03,0x00,0x02,0x00,0x01,0x00,0x03,0x00,0x00,0x36} HGICS_GATT_PRIMARY_SVR_128(6, server_uuid); HGICS_GATT_CHARACTER_128(7, HGICS_GATT_CHARAC_Write_Without_Response, 8, data_uuid); HGICS_GATT_CHARACTER_VALUE_128(8, data_uuid, demo_app_read_attdata, demo_app_recv_attdata); HGICS_GATT_CHARACTER_128(9, HGICS_GATT_CHARAC_Notify, 10, notity_uuid); HGICS_GATT_CHARACTER_VALUE_128(10, notity_uuid, NULL, NULL); HGICS_GATT_CHARACTER_CCCD(11, NULL, NULL); #endif #if 0 //demo 3: UUID 128 HGICS_GATT_PRIMARY_SVR(6, 0x1912); HGICS_GATT_CHARACTER(7, HGICS_GATT_CHARAC_Read|HGICS_GATT_CHARAC_Write, 8, 0x2b13); HGICS_GATT_CHARACTER_VALUE(8, 0x2b13, demo_app_read_attdata, demo_app_recv_attdata); #define UUID1 {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11} HGICS_GATT_CHARACTER_128(7, HGICS_GATT_CHARAC_Write_Without_Response, 8, UUID1); HGICS_GATT_CHARACTER_VALUE_128(8, UUID1, demo_app_read_attdata, demo_app_recv_attdata); #endif #if 1 //default demo: UUID 16 HGICS_GATT_PRIMARY_SVR(6, 0x1912); HGICS_GATT_CHARACTER(7, HGICS_GATT_CHARAC_Read|HGICS_GATT_CHARAC_Write, 8, 0x2b13); HGICS_GATT_CHARACTER_VALUE(8, 0x2b13, demo_app_read_attdata, demo_app_recv_attdata); HGICS_GATT_CHARACTER(9, HGICS_GATT_CHARAC_Notify, 10, 0x2b10); HGICS_GATT_CHARACTER_VALUE(10, 0x2b10, NULL, NULL); HGICS_GATT_CHARACTER_CCCD(11, NULL, NULL); #endif static struct hgic_gatt_hdr *att_table[] = { (struct hgic_gatt_hdr *)&att1, (struct hgic_gatt_hdr *)&att2, (struct hgic_gatt_hdr *)&att3, (struct hgic_gatt_hdr *)&att4, (struct hgic_gatt_hdr *)&att5, (struct hgic_gatt_hdr *)&att6, (struct hgic_gatt_hdr *)&att7, (struct hgic_gatt_hdr *)&att8, (struct hgic_gatt_hdr *)&att9, (struct hgic_gatt_hdr *)&att10, (struct hgic_gatt_hdr *)&att11 }; static char test_read_data[ATT_MTU]={0}; int demo_app_read_attdata(int hdl, int offset, char *data, int len) { //setup test data. if(test_read_data[0] == 0){ int i = 0; for(i=0; i 0){ memcpy(data, test_read_data+offset, ret); } printf("hdl 8 read, offset=%d, len=%d\r\n", offset, ret); break; default: sprintf(data, "hdl %d NULL Value", hdl); ret = strlen(data); break; } return ret; } int demo_app_recv_attdata(int hdl, int offset, char *data, int len) { #if 1 //sample code char *ssid, *psk, *keymgmt; uint8_t cmd[64]; //char out[128]; extern char *HGIC; printf("hdl %d recv data, len = %d, offset=%d\r\n", hdl, len, offset); if (hdl == 8 && data[0] == ':') { ssid = data + 1; psk = strchr(ssid, ','); if(psk == NULL) return -1; *psk++ = 0; keymgmt = strchr(psk, ','); if(keymgmt == NULL) return -1; *keymgmt++ = 0; printf("SET ssid:%s\r\n", ssid); hgics_wpacli_set_ssid("hg0", ssid); printf("SET passwd:%s\r\n", psk); hgics_wpacli_set_psk("hg0", psk); printf("SET keymgmt:%s\r\n", keymgmt[0] == '1' ? "WPA-PSK" : "NONE"); hgics_wpacli_set_keymgmt("hg0", keymgmt[0] ? "WPA-PSK" : "NONE"); hgic_blenc_release(); hgic_iwpriv_blenc_start("hg0", 0, 38); hgics_wpacli_disable_network( "hg0"); hgics_wpacli_enable_network("hg0"); } #endif } void hgic_gatt_notify_test() { static int __loop__ = 0; static int __value__ = 0; int notify_hdl = 10; char notify_data[ATT_MTU]; __loop__++; if(ble_connected && __loop__ > 50){ __loop__ = 0; memset(notify_data, 'A'+__value__, att_mtu-3); __value__ = (__value__ >= 26 ? 0 : __value__+1); hgic_gatt_notify(notify_hdl, notify_data, att_mtu-3); } } ///////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// int hgic_gatt_send_frag(char *att_data, int len, int tot_len, int first) { int off = 0; int bc = 0; int pb = first ? 0 : 1; int ret = -ENOMEM; char *data = malloc(ble_ll_length+HCI_ACL_HDR_SIZE+4); if(data == NULL){ printf("malloc fail, ble_ll_length=%d\r\n", ble_ll_length); return -1; } // 0 - Connection handle put_unaligned_le16(HCI_CONN_HANDLE|(pb<<12)|(bc<<14), data+off); off += 2; // 2 - ACL length put_unaligned_le16(len + 4u, data+off); off += 2; if(first){ // 4 - L2CAP packet length: tot_len put_unaligned_le16(tot_len, data+off); off += 2; // 6 - L2CAP CID put_unaligned_le16(0x04, data+off); off += 2; } memcpy(data+off, att_data, len); off += len; ret = hgic_iwpriv_blenc_send_hcidata("hg0", HCI_ACL_DATA_PACKET, data, off); //printf(" -->send ble frag, len=%d\r\n", len); free(data); return ret >= 0 ? len : 0; } int hgic_gatt_send_data(char *att_data, int tot_len) { int flen; int off = 0; //hgic_dump_hex("\r\nSEND:\r\n", att_data, tot_len, 1); while(off < tot_len){ flen = ((off==0)?(ble_ll_length-4):ble_ll_length); flen = (tot_len-off)>flen?flen:(tot_len-off); flen = hgic_gatt_send_frag(att_data+off, flen, tot_len, (off==0)); if(flen <= 0) break; off += flen; } return off; } // att_hdl: the CHARACTER_VALUE's handle that has Notify properties. int hgic_gatt_notify(uint16_t att_hdl, char *data, int len) { int ret = -ENOMEM; char buff[ATT_MTU]; if(len > att_mtu - 3){ printf("BLE: data len exceed MTU size! MTU is %d\r\n", att_mtu); return -E2BIG; } buff[0] = 0x1B; put_unaligned_le16(att_hdl, buff + 1); memcpy(buff + 3, data, len); printf("att hdl %d notify data, len:%d.\r\n", att_hdl, len); return hgic_gatt_send_data(buff, 3 + len); } void hgic_gatt_send_ATT_ERROR(uint8_t opcode, uint16_t atthandle, uint8_t err_code) { uint8_t buff[5]; buff[0] = 0x01; buff[1] = opcode; put_unaligned_le16(atthandle, buff + 2); buff[4] = err_code; hgic_gatt_send_data( buff, 5); } void hgic_gatt_send_PREPARE_WRITE_RESP(uint8_t *req, uint16_t len) { req[0] = 0x17; hgic_gatt_send_data(req, len); } void hgic_gatt_EXCUTE_WRITE(uint8_t req) { uint8_t opcode = 0x19; hgic_gatt_send_data(&opcode, 1); } void hgic_gatt_send_EXCHANGE_MTU(uint8_t opcode) { uint8_t buff[5]; buff[0] = opcode; put_unaligned_le16(ATT_MTU, buff + 1); hgic_gatt_send_data(buff, 3); } void hgic_gatt_EXCHANGE_MTU(uint32_t mtu, uint8_t req) { if(mtu < 23) mtu = 23; att_mtu = MIN(mtu, ATT_MTU); mtu_exchanged = 1; printf("new ATT MTU %d\r\n", att_mtu); if(req){ hgic_gatt_send_EXCHANGE_MTU(0x03); } } void hgic_gatt_READ_REQ(uint16_t att_hdl, uint32_t offset, uint8_t opcode) { int i = 0; int len = -1; char resp[ATT_MTU]; struct hgic_gatt_characteristic_value *v; resp[0] = opcode + 1; for (i = 0; i < ARRAY_SIZE(att_table); i++) { if (att_table[i]->att_hdl == att_hdl && (att_table[i]->priv_type == 4 || att_table[i]->priv_type == 41)) { v = (struct hgic_gatt_characteristic_value *)att_table[i]; if (v->read_cb) { len = v->read_cb(att_table[i]->att_hdl, offset, resp + 1, att_mtu-1); } break; } } if (len >= 0) { hgic_gatt_send_data(resp, 1 + len); } else { printf("==>ATT_NOT_FOUND: att_hdl=%d\r\n", att_hdl); hgic_gatt_send_ATT_ERROR(opcode, att_hdl, 0x0a); } } void hgic_gatt_WRITE(uint16_t att_hdl, uint32_t offset, char *att_value, int value_len, uint8_t resp) { int i = 0; struct hgic_gatt_characteristic_value *v; for (i = 0; i < ARRAY_SIZE(att_table); i++) { if (att_table[i]->att_hdl == att_hdl && (att_table[i]->priv_type == 4 || att_table[i]->priv_type == 41)) { v = (struct hgic_gatt_characteristic_value *)att_table[i]; if (v->write_cb) { v->write_cb(att_table[i]->att_hdl, offset, att_value, value_len); } if (resp) { hgic_gatt_send_data(&resp, 1); } return; } } printf("==>ATT_NOT_FOUND: att_hdl=%d, resp=0x%x\r\n", att_hdl, resp & 0xff); hgic_gatt_send_ATT_ERROR(resp, att_hdl, 0x0a); } void hgic_gatt_FIND_INFORMATION_REQ(uint16_t start_hdl, uint16_t end_hdl) { int i = 0; int off = 2; char buff[ATT_MTU]; int item_len = 0; int parse_end = 0; buff[0] = 0x05; buff[1] = 0x1; for (i = 0; buff[1] && i < ARRAY_SIZE(att_table) && !parse_end; i++) { if (att_table[i]->att_hdl >= start_hdl && att_table[i]->att_hdl <= end_hdl) { if (item_len == 0) { item_len = (att_table[i]->priv_type == 21 || att_table[i]->priv_type == 41) ? 18 : 4; } else if (item_len != ((att_table[i]->priv_type == 21 || att_table[i]->priv_type == 41) ? 18 : 4)) { parse_end = 1; break; } if (att_table[i]->priv_type == 21 || att_table[i]->priv_type == 41) { //uuid 128 put_unaligned_le16(att_table[i]->att_hdl, buff + off); off += 2; memcpy(buff + off, att_table[i]->att_type_128, 16); off += 16; }else{ // uuid 16 put_unaligned_le16(att_table[i]->att_hdl, buff + off); off += 2; put_unaligned_le16(att_table[i]->att_type, buff + off); off += 2; } if (off > (att_mtu - item_len)) { parse_end = 1; break; } } } if (off > 2) { buff[1] = (item_len == 4 ? 0x1 : 02); //foramt hgic_gatt_send_data(buff, off); } else { printf("==>ATT_NOT_FOUND: start_hdl=%d, end_hdl=%d\r\n", start_hdl, end_hdl); hgic_gatt_send_ATT_ERROR(0x04, start_hdl, 0x0a); } } void hgic_gatt_READ_BY_TYPE_REQ(uint16_t start_hdl, uint16_t end_hdl, uint16_t att_type) { int item_len = 0; int i = 0; int off = 2; char buff[ATT_MTU]; int parse_end = 0; struct hgic_gatt_characteristic *c; buff[0] = 0x09; for (i = 0; i < ARRAY_SIZE(att_table) && !parse_end; i++) { if (att_table[i]->att_hdl >= start_hdl && att_table[i]->att_hdl <= end_hdl && att_table[i]->att_type == att_type) { switch (att_type) { case 0x2803: /*read Characteristic*/ c = (struct hgic_gatt_characteristic *)att_table[i]; if (item_len == 0) { item_len = (c->hdr.priv_type == 21 || c->hdr.priv_type == 41) ? 21 : 7; } else if (item_len != ((c->hdr.priv_type == 21 || c->hdr.priv_type == 41) ? 21 : 7)) { parse_end = 1; break; } if (c->hdr.priv_type == 21 || c->hdr.priv_type == 41) { //uuid 128 put_unaligned_le16(c->hdr.att_hdl, buff + off); off += 2; buff[off] = c->properties; off += 1; put_unaligned_le16(c->value_hdl, buff + off); off += 2; memcpy(buff + off, c->value_type_128, 16); off += 16; }else{ // uuid 16 put_unaligned_le16(c->hdr.att_hdl, buff + off); off += 2; buff[off] = c->properties; off += 1; put_unaligned_le16(c->value_hdl, buff + off); off += 2; put_unaligned_le16(c->value_type, buff + off); off += 2; } if (off > (att_mtu - item_len)) { parse_end = 1; break; } break; }; } } if (off > 2) { buff[1] = item_len; hgic_gatt_send_data(buff, off); } else { printf("==>ATT_NOT_FOUND: start_hdl=%d, end_hdl=%d, att_type=0x%x\r\n", start_hdl, end_hdl, att_type); hgic_gatt_send_ATT_ERROR(0x08, start_hdl, 0x0a); } } void hgic_gatt_READ_BY_GROUP_TYPE_REQ(uint16_t start_hdl, uint16_t end_hdl, uint16_t group_type) { int item_len = 0; int off = 2; int i = 0; char buff[ATT_MTU]; int start_idx = -1; int end_indx = -1; int parse_end = 0; struct hgic_gatt_primary_service *p; buff[0] = 0x11; buff[1] = 0; for (i = 0; i < ARRAY_SIZE(att_table) && !parse_end; i++) { if (att_table[i]->att_hdl >= start_hdl && att_table[i]->att_hdl <= end_hdl) { switch (group_type) { case 0x2800: /*read Primary Service*/ if (att_table[i]->att_type == 0x2800) { //find a primary service if (end_indx > 0) { //last group end p = (struct hgic_gatt_primary_service *)att_table[start_idx]; put_unaligned_le16(att_table[end_indx]->att_hdl, buff + off); off += 2; if (p->hdr.priv_type == 11) { // uuid 128 memcpy(buff+off, p->att_type_128, 16); off += 16; } else { // uuid 16 put_unaligned_le16(p->att_type, buff + off); off += 2; } } if (item_len == 0) { item_len = (att_table[i]->priv_type == 11 ? 20 : 6); } else if (item_len != (att_table[i]->priv_type == 11 ? 20 : 6)) { parse_end = 1; start_idx = -1; break; } if (off > (att_mtu - item_len)) { parse_end = 1; start_idx = -1; break; } start_idx = i; //new group start put_unaligned_le16(att_table[start_idx]->att_hdl, buff + off); off += 2; } if (start_idx >= 0) end_indx = i; break; } } } if (off > 2) { buff[1] = item_len; if (start_idx >= 0) { p = (struct hgic_gatt_primary_service *)att_table[start_idx]; put_unaligned_le16(att_table[end_indx]->att_hdl, buff + off); off += 2; if (p->hdr.priv_type == 11) { // uuid 128 memcpy(buff+off, p->att_type_128, 16); off += 16; } else { // uuid 16 put_unaligned_le16(p->att_type, buff + off); off += 2; } } hgic_gatt_send_data(buff, off); } else { printf("==>ATT_NOT_FOUND: start_hdl=%d, end_hdl=%d, att_type=0x%x\r\n", start_hdl, end_hdl, group_type); hgic_gatt_send_ATT_ERROR(0x10, start_hdl, 0x0a); } } static void hgic_recv_ble_gatt_data(char *data, int len) { unsigned char opcode = data[0]; printf("recv att data, opcode=0x%x\r\n", opcode); switch (opcode) { case 0x02: //EXCHANGE_MTU_REQ hgic_gatt_EXCHANGE_MTU(get_unaligned_le16(data + 1), 1); break; case 0x03: //EXCHANGE_MTU_RESP hgic_gatt_EXCHANGE_MTU(get_unaligned_le16(data + 1), 0); break; case 0x04: //FIND_INFORMATION_REQ hgic_gatt_FIND_INFORMATION_REQ(get_unaligned_le16(data + 1), get_unaligned_le16(data + 3)); break; case 0x06: //FIND_BY_TYPE_VALUE_REQ printf("==>FIND_BY_TYPE_VALUE_REQ: not support\r\n"); hgic_gatt_send_ATT_ERROR(opcode, get_unaligned_le16(data + 1), 0x06); break; case 0x08: //READ_BY_TYPE_REQ hgic_gatt_READ_BY_TYPE_REQ(get_unaligned_le16(data + 1), get_unaligned_le16(data + 3), get_unaligned_le16(data + 5)); break; case 0x0A: //READ_REQ hgic_gatt_READ_REQ(get_unaligned_le16(data + 1), 0, 0x0A); break; case 0x0C: //READ_BLOB_REQ hgic_gatt_READ_REQ(get_unaligned_le16(data + 1), get_unaligned_le16(data + 3), 0x0C); break; case 0x0e: //READ_MULTIPLE_REQ printf("==>READ_MULTIPLE_REQ: not support\r\n"); hgic_gatt_send_ATT_ERROR(opcode, get_unaligned_le16(data + 1), 0x06); break; case 0x10: // READ_BY_GROUP_TYPE_REQ hgic_gatt_READ_BY_GROUP_TYPE_REQ(get_unaligned_le16(data + 1), get_unaligned_le16(data + 3), get_unaligned_le16(data + 5)); break; case 0x12: //WRITE_REQ hgic_gatt_WRITE(get_unaligned_le16(data + 1), 0, data + 3, len - 3, 0x13); break; case 0x16: //PREPARE_WRITE_REQ hgic_gatt_WRITE(get_unaligned_le16(data + 1), get_unaligned_le16(data + 3), data + 5, len - 5, 0); hgic_gatt_send_PREPARE_WRITE_RESP(data, len); break; case 0x18: //EXECUTE_WRITE_REQ hgic_gatt_EXCUTE_WRITE(data[1]); break; case 0x52: //WRITE_CMD hgic_gatt_WRITE(get_unaligned_le16(data + 1), 0, data + 3, len - 3, 0); break; case 0xD2: //SIGNED_WRITE_CMD printf("==>SIGNED_WRITE_CMD: not support\r\n"); hgic_gatt_send_ATT_ERROR(opcode, get_unaligned_le16(data + 1), 0x06); break; default: printf("==>unknow opcode: %x: not support\r\n", opcode); hgic_gatt_send_ATT_ERROR(opcode, get_unaligned_le16(data + 1), 0x06); break; } if(mtu_exchanged == 0){ hgic_gatt_send_EXCHANGE_MTU(0x02); } } static void hgic_recv_l2cap_data(char type, char *data, int len) { static char frag_buff[ATT_MTU]; static int frag_len = 0; static int tot_len = 0; int hdr_len; int hdr_cid; if (tot_len == 0) { hdr_len = get_unaligned_le16(data); hdr_cid = get_unaligned_le16(data + 2); if (hdr_cid != 0x4) { printf("%s,%d:Not ATT DATA\n",__FUNCTION__,__LINE__); frag_len = tot_len = 0; return; // Is not ATT data. } data += BT_L2CAP_HDR_SIZE; len -= BT_L2CAP_HDR_SIZE; tot_len = hdr_len; frag_len = 0; } if (frag_len + len > ATT_MTU) { printf("ATT_MTU is not enough. L2CAP_PKTSIZE_MAX=%d, frag_len=%d, len=%d\r\n", ATT_MTU, frag_len, len); frag_len = tot_len = 0; return; } memcpy(frag_buff + frag_len, data, len); frag_len += len; if (frag_len >= tot_len) { hgic_dump_hex("\r\nRECV:\r\n", frag_buff, frag_len, 1); hgic_recv_ble_gatt_data(frag_buff, frag_len); frag_len = tot_len = 0; } } static void hgic_recv_ble_event(char *data, int len) { switch (data[2]) { case 0x1: att_mtu = 23; mtu_exchanged = 0; ble_connected = 1; ble_ll_length = 27; printf("BLE Connected\r\n"); //hgic_gatt_notify_test(); break; case 0x07: ble_ll_length = get_unaligned_le16(data+3); printf("BLE Exchange LL_LENGTH: tx=%d, rx=%d\r\n", get_unaligned_le16(data+3), get_unaligned_le16(data+5)); break; } } static void hgic_recv_bt_event(char *data, int len) { switch (data[0]) { case 0x05: att_mtu = 23; mtu_exchanged = 0; ble_connected = 0; ble_ll_length = 27; printf("Disconnect\r\n"); break; case 0x3e: hgic_recv_ble_event(data, len); break; default: printf("%s,%d:Recv unknow evt:0x%x\n",__FUNCTION__,__LINE__,data[0]); break; } } void hgic_proc_bt_data(char *data, int len) { extern struct hgic_fw_info hgic_fwinfo; struct hgic_ctrl_hdr *hdr = (struct hgic_ctrl_hdr *)data; data += sizeof(struct hgic_ctrl_hdr); len -= sizeof(struct hgic_ctrl_hdr); switch (hdr->hci.type) { case 0x02: // ACL data if (hgic_fwinfo.version > 0x02040000) { data += sizeof(struct bt_rx_info); len -= sizeof(struct bt_rx_info); } data += HCI_ACL_HDR_SIZE; len -= HCI_ACL_HDR_SIZE; //hgic_dump_hex("BT ACL DATA:\r\n", data, len, 1); //hgic_dump_hex("ORI DATA:\r\n", hdr, len + sizeof(struct hgic_ctrl_hdr), 1); hgic_recv_l2cap_data(hdr->hci.type, data, len); break; case 0x04: // Event hgic_recv_bt_event(data, len); break; } }