// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /**************************************************************************** * * This file is used to decode eddystone information. * ****************************************************************************/ #include #include #include #include #include "esp_err.h" #include "esp_gap_ble_api.h" #include "esp_eddystone_protocol.h" #include "esp_eddystone_api.h" /* Declare static functions */ static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res); static esp_err_t esp_eddystone_url_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res); static char* esp_eddystone_resolve_url_scheme(const uint8_t* url_start, const uint8_t* url_end); static esp_err_t esp_eddystone_tlm_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res); static esp_err_t esp_eddystone_get_inform(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res); /* Eddystone-URL scheme prefixes */ static const char* eddystone_url_prefix[4] = { "http://www.", "https://www.", "http://", "https://" }; /* Eddystone-URL HTTP URL encoding */ static const char* eddystone_url_encoding[14] = { ".com/", ".org/", ".edu/", ".net/", ".info/", ".biz/", ".gov/", ".com", ".org", ".edu", ".net", ".info", ".biz", ".gov" }; /* decode and store received UID */ static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res) { uint8_t pos = 0; if(len+4 != EDDYSTONE_UID_FRAME_LEN) { //ERROR:uid len wrong return -1; } res->inform.uid.ranging_data = buf[pos++]; for(int i=0; i<10; i++) { res->inform.uid.namespace_id[i] = buf[pos++]; } for(int i=0; i<6; i++) { res->inform.uid.instance_id[i] = buf[pos++]; } return 0; } /* resolve received URL to url_res pointer */ static char* esp_eddystone_resolve_url_scheme(const uint8_t *url_start, const uint8_t *url_end) { int pos = 0; static char url_buf[100] = {0}; const uint8_t *p = url_start; pos += sprintf(&url_buf[pos], "%s", eddystone_url_prefix[*p++]); for (; p <= url_end; p++) { if (esp_eddystone_is_char_invalid((*p))) { pos += sprintf(&url_buf[pos], "%s", eddystone_url_encoding[*p]); } else { pos += sprintf(&url_buf[pos], "%c", *p); } } return url_buf; } /* decode and store received URL, the pointer url_res points to the resolved url */ static esp_err_t esp_eddystone_url_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res) { char *url_res = NULL; uint8_t pos = 0; if(len-1 > EDDYSTONE_URL_MAX_LEN) { //ERROR:too long url return -1; } res->inform.url.tx_power = buf[pos++]; url_res = esp_eddystone_resolve_url_scheme(buf+pos, buf+len-1); memcpy(&res->inform.url.url, url_res, strlen(url_res)); return 0; } /* decode and store received TLM */ static esp_err_t esp_eddystone_tlm_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res) { uint8_t pos = 0; if(len+4 > EDDYSTONE_TLM_FRAME_LEN) { //ERROR:TLM too long return -1; } res->inform.tlm.version = buf[pos++]; res->inform.tlm.battery_voltage = big_endian_read_16(buf, pos); pos += 2; uint16_t temp = big_endian_read_16(buf, pos); int8_t temp_integral = (int8_t)((temp >> 8) & 0xff); float temp_decimal = (temp & 0xff) / 256.0; res->inform.tlm.temperature = temp_integral + temp_decimal; pos += 2; res->inform.tlm.adv_count = big_endian_read_32(buf, pos); pos += 4; res->inform.tlm.time = big_endian_read_32(buf, pos); return 0; } static esp_err_t esp_eddystone_get_inform(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res) { static esp_err_t ret=-1; switch(res->common.frame_type) { case EDDYSTONE_FRAME_TYPE_UID: { ret = esp_eddystone_uid_received(buf, len, res); break; } case EDDYSTONE_FRAME_TYPE_URL: { ret = esp_eddystone_url_received(buf, len, res); break; } case EDDYSTONE_FRAME_TYPE_TLM: { ret = esp_eddystone_tlm_received(buf, len, res); break; } default: break; } return ret; } esp_err_t esp_eddystone_decode(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res) { static uint8_t pos=0; while(res->common.srv_data_type != EDDYSTONE_SERVICE_UUID) { pos++; uint8_t ad_type = buf[pos++]; switch(ad_type) { case ESP_BLE_AD_TYPE_FLAG: { res->common.flags = buf[pos++]; break; } case ESP_BLE_AD_TYPE_16SRV_CMPL: { uint16_t uuid = little_endian_read_16(buf, pos); if(uuid != EDDYSTONE_SERVICE_UUID) { return -1; } res->common.srv_uuid = uuid; pos += 2; break; } case ESP_BLE_AD_TYPE_SERVICE_DATA: { uint16_t type = little_endian_read_16(buf, pos); pos += 2; uint8_t frame_type = buf[pos++]; if(type != EDDYSTONE_SERVICE_UUID || !(frame_type == EDDYSTONE_FRAME_TYPE_UID || frame_type == EDDYSTONE_FRAME_TYPE_URL || frame_type == EDDYSTONE_FRAME_TYPE_TLM)) { return -1; } res->common.srv_data_type = type; res->common.frame_type = frame_type; break; } default: break; } } return esp_eddystone_get_inform(buf+pos, len-pos, res); }