123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- /**************************************************************************************************
-
- Phyplus Microelectronics Limited confidential and proprietary.
- All rights reserved.
- IMPORTANT: All rights of this software belong to Phyplus Microelectronics
- Limited ("Phyplus"). Your use of this Software is limited to those
- specific rights granted under the terms of the business contract, the
- confidential agreement, the non-disclosure agreement and any other forms
- of agreements as a customer or a partner of Phyplus. You may not use this
- Software unless you agree to abide by the terms of these agreements.
- You acknowledge that the Software may not be modified, copied,
- distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy
- (BLE) integrated circuit, either as a product or is integrated into your
- products. Other than for the aforementioned purposes, you may not use,
- reproduce, copy, prepare derivative works of, modify, distribute, perform,
- display or sell this Software and/or its documentation for any purposes.
- YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
- PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
- INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
- NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
- PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT,
- NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
- LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
- INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
- OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
- OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
- (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
-
- **************************************************************************************************/
- #include "bcomdef.h"
- #include "linkdb.h"
- #include "osal.h"
- #include "gatt.h"
- #include "gapgattserver.h"
- #include "gattservapp.h"
- #include "peripheral.h"
- #include "gapbondmgr.h"
- #include "gatt_profile_uuid.h"
- #include "ble_ancs.h"
- #include "ancs_attr.h"
- #include "log.h"
- static bool all_req_attrs_parsed(ancs_ctx_t * p_ancs)
- {
- if (p_ancs->parse_info.expected_number_of_attrs == 0)
- {
- return TRUE;
- }
- return FALSE;
- }
- static bool attr_is_requested(ancs_ctx_t * p_ancs, ancs_attr_evt_t* pattr)
- {
- if(p_ancs->parse_info.p_attr_list[pattr->attr_id].en == TRUE)
- {
- return TRUE;
- }
- return FALSE;
- }
- static ancs_parse_state_t command_id_parse(ancs_ctx_t* p_ancs, const uint8_t * p_data_src, uint32_t * index)
- {
- ancs_parse_state_t parse_state;
- p_ancs->parse_info.command_id = (ancs_cmd_id_val_t) p_data_src[(*index)++];
- p_ancs->attr_rsp_evt.msg = (void*)(&(p_ancs->attr_evt_msg));
- switch (p_ancs->parse_info.command_id)
- {
- case ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES:
- p_ancs->attr_rsp_evt.type = BLE_ANCS_EVT_NOTIF_ATTRIBUTE;
- p_ancs->parse_info.p_attr_list = p_ancs->notif_attr_list;
- p_ancs->parse_info.nb_of_attr = ANCS_NB_OF_NOTIF_ATTR;
- parse_state = NOTIF_UID;
- break;
- case ANCS_COMMAND_ID_GET_APP_ATTRIBUTES:
- p_ancs->attr_rsp_evt.type = BLE_ANCS_EVT_APP_ATTRIBUTE;
- p_ancs->parse_info.p_attr_list = p_ancs->app_attr_list;
- p_ancs->parse_info.nb_of_attr = ANCS_NB_OF_APP_ATTR;
- parse_state = APP_ID;
- break;
- default:
- //no valid command_id, abort the rest of the parsing procedure.
- LOG("Invalid Command ID");
- parse_state = DONE;
- break;
- }
- return parse_state;
- }
- static ancs_parse_state_t notif_uid_parse(ancs_ctx_t * p_ancs,
- const uint8_t * p_data_src,
- uint32_t * index)
- {
- p_ancs->attr_evt_msg.notif_uid = BUILD_UINT32(p_data_src[*index],p_data_src[*index+1],p_data_src[*index+2],p_data_src[*index+3]);
- *index += sizeof(uint32_t);
- return ATTR_ID;
- }
- static ancs_parse_state_t app_id_parse(ancs_ctx_t * p_ancs,
- const uint8_t * p_data_src,
- uint32_t * index)
- {
- p_ancs->attr_evt_msg.app_id[p_ancs->parse_info.current_app_id_index] = p_data_src[(*index)++];
- if(p_ancs->attr_evt_msg.app_id[p_ancs->parse_info.current_app_id_index] != '\0')
- {
- p_ancs->parse_info.current_app_id_index++;
- return APP_ID;
- }
- else
- {
- return ATTR_ID;
- }
- }
- static ancs_parse_state_t attr_id_parse(ancs_ctx_t * p_ancs,
- const uint8_t * p_data_src,
- uint32_t * index)
- {
- p_ancs->attr_evt_msg.attr_id = p_data_src[(*index)++];
- if (p_ancs->attr_evt_msg.attr_id >= p_ancs->parse_info.nb_of_attr)
- {
- LOG("Attribute ID Invalid.\r\n");
- return DONE;
- }
- p_ancs->attr_evt_msg.p_attr_data = p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].p_attr_data;
- if (all_req_attrs_parsed(p_ancs))
- {
- LOG("All requested attributes received. \r\n");
- return DONE;
- }
- else
- {
- if (attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
- {
- p_ancs->parse_info.expected_number_of_attrs--;
- }
- LOG("Attribute ID %i \r\n", p_ancs->attr_evt_msg.attr_id);
- return ATTR_LEN1;
- }
- }
- static ancs_parse_state_t attr_len1_parse(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
- {
- p_ancs->attr_evt_msg.attr_len = p_data_src[(*index)++];
- return ATTR_LEN2;
- }
- static ancs_parse_state_t attr_len2_parse(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
- {
- p_ancs->attr_evt_msg.attr_len |= (p_data_src[(*index)++] << 8);
- p_ancs->parse_info.current_attr_index = 0;
- if (p_ancs->attr_evt_msg.attr_len != 0)
- {
- //If the attribute has a length but there is no allocated space for this attribute
- if((p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len == 0) ||
- (p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].p_attr_data == NULL))
- {
- return ATTR_SKIP;
- }
- else
- {
- return ATTR_DATA;
- }
- }
- else
- {
- LOG("Attribute LEN %i \r\n", p_ancs->attr_evt_msg.attr_len);
- if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
- {
- p_ancs->callback(&p_ancs->attr_rsp_evt);
- }
- if(all_req_attrs_parsed(p_ancs))
- {
- return DONE;
- }
- else
- {
- return ATTR_ID;
- }
- }
- }
- static ancs_parse_state_t attr_data_parse(ancs_ctx_t * p_ancs,
- const uint8_t * p_data_src,
- uint32_t * index)
- {
- // We have not reached the end of the attribute, nor our max allocated internal size.
- // Proceed with copying data over to our buffer.
- if ( (p_ancs->parse_info.current_attr_index < p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len)
- && (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len))
- {
- //LOG("Byte copied to buffer: %c\r\n", p_data_src[(*index)]); // Un-comment this line to see every byte of an attribute as it is parsed. Commented out by default since it can overflow the uart buffer.
- p_ancs->attr_evt_msg.p_attr_data[p_ancs->parse_info.current_attr_index++] = p_data_src[(*index)++];
- }
- // We have reached the end of the attribute, or our max allocated internal size.
- // Stop copying data over to our buffer. NUL-terminate at the current index.
- if ( (p_ancs->parse_info.current_attr_index == p_ancs->attr_evt_msg.attr_len) ||
- (p_ancs->parse_info.current_attr_index == p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len - 1))
- {
- if (attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
- {
- p_ancs->attr_evt_msg.p_attr_data[p_ancs->parse_info.current_attr_index] = '\0';
- }
- // If our max buffer size is smaller than the remaining attribute data, we must
- // increase index to skip the data until the start of the next attribute.
- if (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len)
- {
- return ATTR_SKIP;
- }
- LOG("Attribute finished!\r\n");
- if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
- {
- p_ancs->callback(&p_ancs->attr_rsp_evt);
- }
- if(all_req_attrs_parsed(p_ancs))
- {
- return DONE;
- }
- else
- {
- return ATTR_ID;
- }
- }
- return ATTR_DATA;
- }
- static ancs_parse_state_t attr_skip(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
- {
- // We have not reached the end of the attribute, nor our max allocated internal size.
- // Proceed with copying data over to our buffer.
- if (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len)
- {
- p_ancs->parse_info.current_attr_index++;
- (*index)++;
- }
- // At the end of the attribute, determine if it should be passed to event handler and
- // continue parsing the next attribute ID if we are not done with all the attributes.
- if (p_ancs->parse_info.current_attr_index == p_ancs->attr_evt_msg.attr_len)
- {
- if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
- {
-
- p_ancs->callback(&p_ancs->attr_rsp_evt);
- }
- if(all_req_attrs_parsed(p_ancs))
- {
- return DONE;
- }
- else
- {
- return ATTR_ID;
- }
- }
- return ATTR_SKIP;
- }
- static void print_hex (const uint8 *data, uint16 len)
- {
- uint16 i;
- for (i = 0; i < len - 1; i++)
- {
- LOG("%x,",data[i]);
- LOG(" ");
- }
- LOG("%d\n",data[i]);
- }
- void ancs_parse_get_attrs_response(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint8_t hvx_data_len)
- {
- uint32_t index;
- LOG("ancs_parse_get_attrs_response:\n");
- print_hex(p_data_src, hvx_data_len);
- for (index = 0; index < hvx_data_len;)
- {
- switch (p_ancs->parse_info.parse_state)
- {
- case COMMAND_ID:
- p_ancs->parse_info.parse_state = command_id_parse(p_ancs, p_data_src, &index);
- break;
- case NOTIF_UID:
- p_ancs->parse_info.parse_state = notif_uid_parse(p_ancs, p_data_src, &index);
- break;
- case APP_ID:
- p_ancs->parse_info.parse_state = app_id_parse(p_ancs, p_data_src, &index);
- break;
- case ATTR_ID:
- p_ancs->parse_info.parse_state = attr_id_parse(p_ancs, p_data_src, &index);
- break;
- case ATTR_LEN1:
- p_ancs->parse_info.parse_state = attr_len1_parse(p_ancs, p_data_src, &index);
- break;
- case ATTR_LEN2:
- p_ancs->parse_info.parse_state = attr_len2_parse(p_ancs, p_data_src, &index);
- break;
- case ATTR_DATA:
- p_ancs->parse_info.parse_state = attr_data_parse(p_ancs, p_data_src, &index);
- break;
- case ATTR_SKIP:
- p_ancs->parse_info.parse_state = attr_skip(p_ancs, p_data_src, &index);
- break;
- case DONE:
- LOG("Parse state: Done %s\r\n", p_ancs->attr_evt_msg.p_attr_data);
- index = hvx_data_len;
- break;
- default:
- // Default case will never trigger intentionally. Go to the DONE state to minimize the consequences.
- p_ancs->parse_info.parse_state = DONE;
- break;
- }
- }
- }
- static bool app_attr_is_requested(ancs_ctx_t * p_ancs, uint32_t attr_id)
- {
- if(p_ancs->app_attr_list[attr_id].en == TRUE)
- {
- return TRUE;
- }
- return false;
- }
- static uint32_t app_attr_nb_to_get(ancs_ctx_t * p_ancs)
- {
- uint32_t attr_nb_to_get = 0;
- for(uint32_t i = 0; i < (sizeof(p_ancs->app_attr_list)/sizeof(ancs_attr_list_t)); i++)
- {
- if(app_attr_is_requested(p_ancs,i))
- {
- attr_nb_to_get++;
- }
- }
- return attr_nb_to_get;
- }
- static encode_app_attr_t app_attr_encode_cmd_id(ancs_ctx_t * p_ancs,
- uint32_t * index,
- uint8_t * tx_buf)
- {
- LOG("Encoding Command ID\r\n");
- // Encode Command ID.
- tx_buf[(*index)++] = ANCS_COMMAND_ID_GET_APP_ATTRIBUTES;
- return APP_ATTR_APP_ID;
- }
- static encode_app_attr_t app_attr_encode_app_id(ancs_ctx_t * p_ancs,
- uint32_t * p_index,
- uint16_t * p_offset,
- uint8_t * tx_buf,
- const uint8_t * p_app_id,
- const uint32_t app_id_len,
- uint32_t * p_app_id_bytes_encoded_count)
- {
- LOG("Encoding APP ID\r\n");
- //Encode App Identifier.
- if(*p_app_id_bytes_encoded_count == app_id_len)
- {
- tx_buf[(*p_index)++] = '\0';
- (*p_app_id_bytes_encoded_count)++;
- }
- LOG("%c\r\n", p_app_id[(*p_app_id_bytes_encoded_count)]);
- if(*p_app_id_bytes_encoded_count < app_id_len)
- {
- tx_buf[(*p_index)++] = p_app_id[(*p_app_id_bytes_encoded_count)++];
- }
- if(*p_app_id_bytes_encoded_count > app_id_len)
- {
- return APP_ATTR_ATTR_ID;
- }
- return APP_ATTR_APP_ID;
- }
- static encode_app_attr_t app_attr_encode_attr_id(ancs_ctx_t * p_ancs,
- uint32_t * p_index,
- uint16_t * p_offset,
- uint8_t * tx_buf,
- uint32_t * p_attr_count,
- uint32_t * attr_get_total_nb)
- {
- LOG("Encoding Attribute ID\r\n");
- //Encode Attribute ID.
- if (*p_attr_count < ANCS_NB_OF_APP_ATTR)
- {
- if (app_attr_is_requested(p_ancs, *p_attr_count))
- {
- tx_buf[(*p_index)] = *p_attr_count;
- (*p_index)++;
- LOG("offset %i\r\n", *p_offset);
- }
- (*p_attr_count)++;
- }
- if (*p_attr_count == ANCS_NB_OF_APP_ATTR)
- {
- return APP_ATTR_DONE;
- }
- return APP_ATTR_APP_ID;
- }
- bStatus_t app_attrs_get(ancs_ctx_t * p_ancs, const uint8_t * p_app_id, uint8_t app_id_len)
- {
- ancs_service_t* pservice = &(p_ancs->ancs_service);
- uint32_t index = 0;
- uint32_t attr_bytes_encoded_count = 0;
- uint16_t offset = 0;
- uint32_t app_id_bytes_encoded_count = 0;
- encode_app_attr_t state = APP_ATTR_COMMAND_ID;
- bStatus_t status;
- p_ancs->parse_info.parse_state = COMMAND_ID;
- uint32_t attr_get_total_nb = app_attr_nb_to_get(p_ancs);
- uint8_t* tx_buf = p_ancs->app_attr_tx_buf;
- if(app_id_len == 0)
- {
- return INVALIDPARAMETER;
- }
- if(p_app_id[app_id_len] != '\0') // App id to be requestes must be NULL terminated
- {
- return INVALIDPARAMETER;
- }
- osal_memset(tx_buf, 0, sizeof(ANCS_APP_ATTR_TX_SIZE));
- while(state != APP_ATTR_DONE)
- {
- switch(state)
- {
- case APP_ATTR_COMMAND_ID:
- state = app_attr_encode_cmd_id(p_ancs,
- &index,
- tx_buf);
- break;
- case APP_ATTR_APP_ID:
- state = app_attr_encode_app_id(p_ancs,
- &index,
- &offset,
- tx_buf,
- p_app_id,
- app_id_len,
- &app_id_bytes_encoded_count);
- break;
- case APP_ATTR_ATTR_ID:
- state = app_attr_encode_attr_id(p_ancs,
- &index,
- &offset,
- tx_buf,
- &attr_bytes_encoded_count,
- &attr_get_total_nb);
- break;
- case APP_ATTR_DONE:
- break;
- default:
- break;
- }
- }
-
- p_ancs->parse_info.expected_number_of_attrs = ANCS_NB_OF_APP_ATTR;
- if(index > 20){
- gattPrepareWriteReq_t lreq = {0,0};
-
- lreq.pValue = osal_mem_alloc(index);
- osal_memcpy(lreq.pValue, tx_buf, index);
- lreq.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
- lreq.len = index;
- status = GATT_WriteLongCharValue(pservice->conn_hdl, &lreq, p_ancs->app_task_ID);
- if (status != SUCCESS)
- {
- // If it fails free the message.
- LOG("CP WRITE ERROR:\t%d\n",status);
- osal_mem_free(lreq.pValue);
- }
- }
- else
- {
- attWriteReq_t req;
-
- osal_memcpy(req.value, tx_buf, index);
- req.sig = 0;
- req.cmd = 0;
- req.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
- req.len = index;
- status = GATT_WriteCharValue(pservice->conn_hdl, &req, p_ancs->app_task_ID);
- if (status != SUCCESS)
- {
- // If it fails free the message.
- LOG("CP WRITE ERROR:\t%d\n",status);
- }
- }
- return SUCCESS;
- }
- bStatus_t notif_attrs_get(ancs_ctx_t * p_ancs,const uint8_t * pNotificationUID)
- {
- ancs_service_t* pservice = &(p_ancs->ancs_service);
- ancs_attr_list_t* pattrlist = p_ancs->notif_attr_list;
- bStatus_t status;
- uint8_t* tx_buf = p_ancs->app_attr_tx_buf;
-
- uint8_t number_of_requested_attr = 0;
- p_ancs->parse_info.parse_state = COMMAND_ID;
- osal_memset(tx_buf, 0, sizeof(ANCS_APP_ATTR_TX_SIZE));
- uint32_t index = 0;
- //Encode Command ID.
- tx_buf[index++] = ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
- //Encode Notification UID.
- tx_buf[index++] = pNotificationUID[0];
- tx_buf[index++] = pNotificationUID[1];
- tx_buf[index++] = pNotificationUID[2];
- tx_buf[index++] = pNotificationUID[3];
- //Encode Attribute ID.
- for (uint32_t attr = 0; attr < ANCS_NB_OF_NOTIF_ATTR; attr++)
- {
- if (pattrlist[attr].en == TRUE)
- {
- tx_buf[index++] = attr;
- if ((attr == BLE_ANCS_NOTIF_ATTR_ID_TITLE) ||
- (attr == BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
- (attr == BLE_ANCS_NOTIF_ATTR_ID_MESSAGE))
- {
- //Encode Length field, only applicable for Title, Subtitle and Message
- tx_buf[index++] = (uint8_t)(pattrlist[attr].attr_len & 0xff);
- tx_buf[index++] = (uint8_t)((pattrlist[attr].attr_len >> 8)&0xff);
- }
- number_of_requested_attr++;
- }
- }
- LOG("notif_attrs_get:\n");
- print_hex(tx_buf, index);
- p_ancs->parse_info.expected_number_of_attrs = number_of_requested_attr;
- if(index > 20){
- gattPrepareWriteReq_t lreq = {0,0};
-
- lreq.pValue = osal_mem_alloc(index);
- osal_memcpy(lreq.pValue, tx_buf, index);
- lreq.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
- lreq.len = index;
- status = GATT_WriteLongCharValue(pservice->conn_hdl, &lreq, p_ancs->app_task_ID);
- if (status != SUCCESS)
- {
- // If it fails free the message.
- LOG("CP WRITE ERROR:\t%d\n",status);
- osal_mem_free(lreq.pValue);
- }
- }
- else
- {
- attWriteReq_t req;
-
- osal_memcpy(req.value, tx_buf, index);
- req.sig = 0;
- req.cmd = 0;
- req.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
- req.len = index;
-
- status = GATT_WriteCharValue(pservice->conn_hdl, &req, p_ancs->app_task_ID);
- if (status != SUCCESS)
- {
- // If it fails free the message.
- LOG("CP WRITE ERROR:\t%d\n",status);
- }
- }
- return SUCCESS;
- }
|