esp_eddystone_api.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. /****************************************************************************
  14. *
  15. * This file is used to decode eddystone information.
  16. *
  17. ****************************************************************************/
  18. #include <stdio.h>
  19. #include <stdint.h>
  20. #include <string.h>
  21. #include <stdbool.h>
  22. #include "esp_err.h"
  23. #include "esp_gap_ble_api.h"
  24. #include "esp_eddystone_protocol.h"
  25. #include "esp_eddystone_api.h"
  26. /* Declare static functions */
  27. static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res);
  28. static esp_err_t esp_eddystone_url_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res);
  29. static char* esp_eddystone_resolve_url_scheme(const uint8_t* url_start, const uint8_t* url_end);
  30. static esp_err_t esp_eddystone_tlm_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res);
  31. static esp_err_t esp_eddystone_get_inform(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res);
  32. /* Eddystone-URL scheme prefixes */
  33. static const char* eddystone_url_prefix[4] = {
  34. "http://www.",
  35. "https://www.",
  36. "http://",
  37. "https://"
  38. };
  39. /* Eddystone-URL HTTP URL encoding */
  40. static const char* eddystone_url_encoding[14] = {
  41. ".com/",
  42. ".org/",
  43. ".edu/",
  44. ".net/",
  45. ".info/",
  46. ".biz/",
  47. ".gov/",
  48. ".com",
  49. ".org",
  50. ".edu",
  51. ".net",
  52. ".info",
  53. ".biz",
  54. ".gov"
  55. };
  56. /* decode and store received UID */
  57. static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res)
  58. {
  59. uint8_t pos = 0;
  60. if(len+4 != EDDYSTONE_UID_FRAME_LEN) {
  61. //ERROR:uid len wrong
  62. return -1;
  63. }
  64. res->inform.uid.ranging_data = buf[pos++];
  65. for(int i=0; i<10; i++) {
  66. res->inform.uid.namespace_id[i] = buf[pos++];
  67. }
  68. for(int i=0; i<6; i++) {
  69. res->inform.uid.instance_id[i] = buf[pos++];
  70. }
  71. return 0;
  72. }
  73. /* resolve received URL to url_res pointer */
  74. static char* esp_eddystone_resolve_url_scheme(const uint8_t *url_start, const uint8_t *url_end)
  75. {
  76. int pos = 0;
  77. static char url_buf[100] = {0};
  78. const uint8_t *p = url_start;
  79. pos += sprintf(&url_buf[pos], "%s", eddystone_url_prefix[*p++]);
  80. for (; p <= url_end; p++) {
  81. if (esp_eddystone_is_char_invalid((*p))) {
  82. pos += sprintf(&url_buf[pos], "%s", eddystone_url_encoding[*p]);
  83. } else {
  84. pos += sprintf(&url_buf[pos], "%c", *p);
  85. }
  86. }
  87. return url_buf;
  88. }
  89. /* decode and store received URL, the pointer url_res points to the resolved url */
  90. static esp_err_t esp_eddystone_url_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res)
  91. {
  92. char *url_res = NULL;
  93. uint8_t pos = 0;
  94. if(len-1 > EDDYSTONE_URL_MAX_LEN) {
  95. //ERROR:too long url
  96. return -1;
  97. }
  98. res->inform.url.tx_power = buf[pos++];
  99. url_res = esp_eddystone_resolve_url_scheme(buf+pos, buf+len-1);
  100. memcpy(&res->inform.url.url, url_res, strlen(url_res));
  101. return 0;
  102. }
  103. /* decode and store received TLM */
  104. static esp_err_t esp_eddystone_tlm_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res)
  105. {
  106. uint8_t pos = 0;
  107. if(len+4 > EDDYSTONE_TLM_FRAME_LEN) {
  108. //ERROR:TLM too long
  109. return -1;
  110. }
  111. res->inform.tlm.version = buf[pos++];
  112. res->inform.tlm.battery_voltage = big_endian_read_16(buf, pos);
  113. pos += 2;
  114. uint16_t temp = big_endian_read_16(buf, pos);
  115. int8_t temp_integral = (int8_t)((temp >> 8) & 0xff);
  116. float temp_decimal = (temp & 0xff) / 256.0;
  117. res->inform.tlm.temperature = temp_integral + temp_decimal;
  118. pos += 2;
  119. res->inform.tlm.adv_count = big_endian_read_32(buf, pos);
  120. pos += 4;
  121. res->inform.tlm.time = big_endian_read_32(buf, pos);
  122. return 0;
  123. }
  124. static esp_err_t esp_eddystone_get_inform(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res)
  125. {
  126. static esp_err_t ret=-1;
  127. switch(res->common.frame_type)
  128. {
  129. case EDDYSTONE_FRAME_TYPE_UID: {
  130. ret = esp_eddystone_uid_received(buf, len, res);
  131. break;
  132. }
  133. case EDDYSTONE_FRAME_TYPE_URL: {
  134. ret = esp_eddystone_url_received(buf, len, res);
  135. break;
  136. }
  137. case EDDYSTONE_FRAME_TYPE_TLM: {
  138. ret = esp_eddystone_tlm_received(buf, len, res);
  139. break;
  140. }
  141. default:
  142. break;
  143. }
  144. return ret;
  145. }
  146. esp_err_t esp_eddystone_decode(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res)
  147. {
  148. static uint8_t pos=0;
  149. while(res->common.srv_data_type != EDDYSTONE_SERVICE_UUID)
  150. {
  151. pos++;
  152. uint8_t ad_type = buf[pos++];
  153. switch(ad_type)
  154. {
  155. case ESP_BLE_AD_TYPE_FLAG: {
  156. res->common.flags = buf[pos++];
  157. break;
  158. }
  159. case ESP_BLE_AD_TYPE_16SRV_CMPL: {
  160. uint16_t uuid = little_endian_read_16(buf, pos);
  161. if(uuid != EDDYSTONE_SERVICE_UUID) {
  162. return -1;
  163. }
  164. res->common.srv_uuid = uuid;
  165. pos += 2;
  166. break;
  167. }
  168. case ESP_BLE_AD_TYPE_SERVICE_DATA: {
  169. uint16_t type = little_endian_read_16(buf, pos);
  170. pos += 2;
  171. uint8_t frame_type = buf[pos++];
  172. if(type != EDDYSTONE_SERVICE_UUID || !(frame_type == EDDYSTONE_FRAME_TYPE_UID || frame_type == EDDYSTONE_FRAME_TYPE_URL ||
  173. frame_type == EDDYSTONE_FRAME_TYPE_TLM)) {
  174. return -1;
  175. }
  176. res->common.srv_data_type = type;
  177. res->common.frame_type = frame_type;
  178. break;
  179. }
  180. default:
  181. break;
  182. }
  183. }
  184. return esp_eddystone_get_inform(buf+pos, len-pos, res);
  185. }