• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <string.h>
21 #include "securec.h"
22 #include "os/endian.h"
23 #include "host/ble_hs_adv.h"
24 #include "ble_hs_priv.h"
25 #include "host/ble_eddystone.h"
26 
27 #define BLE_EDDYSTONE_MAX_SVC_DATA_LEN  22
28 #define BLE_EDDYSTONE_SVC_DATA_BASE_SZ  3
29 
30 #define BLE_EDDYSTONE_SERVICE_UUID      0xfeaa
31 
32 #define BLE_EDDYSTONE_FRAME_TYPE_UID    0x00
33 #define BLE_EDDYSTONE_FRAME_TYPE_URL    0x10
34 
35 static ble_uuid16_t ble_eddystone_uuids16[BLE_EDDYSTONE_MAX_UUIDS16 + 1];
36 static uint8_t ble_eddystone_svc_data[BLE_EDDYSTONE_MAX_SVC_DATA_LEN];
37 
38 /**
39  * Writes an eddystone header to the global service data buffer.
40  *
41  * @param frame_type                The eddystone frame type; one of the
42  *                                      BLE_EDDYSTONE_FRAME_TYPE_[...] values.
43  *
44  * @return                          A pointer to where the service data payload
45  *                                      should be written.
46  */
ble_eddystone_set_svc_data_base(uint8_t frame_type)47 static void *ble_eddystone_set_svc_data_base(uint8_t frame_type)
48 {
49     put_le16(ble_eddystone_svc_data, BLE_EDDYSTONE_SERVICE_UUID);
50     ble_eddystone_svc_data[2] = frame_type; // 2:array element
51     return ble_eddystone_svc_data + BLE_EDDYSTONE_SVC_DATA_BASE_SZ;
52 }
53 
54 /**
55  * Populates the supplied advertisement fields struct to represent an eddystone
56  * advertisement.  Prior to calling this function, you must write the service
57  * data header and payload using the ble_eddystone_set_svc_data_base()
58  * function.
59  *
60  * @param adv_fields            The base advertisement fields to transform into
61  *                                  an eddystone beacon.  All configured fields
62  *                                  are preserved; you probably want to clear
63  *                                  this struct before calling this function.
64  * @param svc_data_len          The amount of data written to the global
65  *                                  service data buffer.
66  *
67  * @return                      0 on success; BLE_HS_E... on failure.
68  */
ble_eddystone_set_adv_data_gen(struct ble_hs_adv_fields * adv_fields,uint8_t svc_data_len)69 static int ble_eddystone_set_adv_data_gen(struct ble_hs_adv_fields *adv_fields, uint8_t svc_data_len)
70 {
71     int rc;
72 
73     if (adv_fields->num_uuids16 > BLE_EDDYSTONE_MAX_UUIDS16) {
74         return BLE_HS_EINVAL;
75     }
76 
77     if (svc_data_len > BLE_EDDYSTONE_MAX_SVC_DATA_LEN) {
78         return BLE_HS_EINVAL;
79     }
80 
81     if (adv_fields->num_uuids16 > 0 && !adv_fields->uuids16_is_complete) {
82         return BLE_HS_EINVAL;
83     }
84 
85     if (adv_fields->svc_data_uuid16_len != 0) {
86         return BLE_HS_EINVAL;
87     }
88 
89     ble_eddystone_uuids16[0] = (ble_uuid16_t) BLE_UUID16_INIT(BLE_EDDYSTONE_SERVICE_UUID);
90     memcpy_s(ble_eddystone_uuids16 + 1, sizeof(ble_eddystone_uuids16 + 1),
91         adv_fields->uuids16, adv_fields->num_uuids16 * sizeof(ble_uuid16_t));
92     adv_fields->uuids16 = ble_eddystone_uuids16;
93     adv_fields->num_uuids16++;
94     adv_fields->uuids16_is_complete = 1;
95     adv_fields->svc_data_uuid16 = ble_eddystone_svc_data;
96     adv_fields->svc_data_uuid16_len = svc_data_len +
97                                       BLE_EDDYSTONE_SVC_DATA_BASE_SZ;
98     rc = ble_gap_adv_set_fields(adv_fields);
99     if (rc != 0) {
100         return rc;
101     }
102 
103     return 0;
104 }
105 
ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields * adv_fields,void * uid,int8_t measured_power)106 int ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields,
107                                    void *uid, int8_t measured_power)
108 {
109     uint8_t *svc_data;
110     int rc;
111     /* Eddystone UUID and frame type (0). */
112     svc_data = ble_eddystone_set_svc_data_base(BLE_EDDYSTONE_FRAME_TYPE_UID);
113 
114     /* Measured Power ranging data (Calibrated tx power at 0 meters). */
115     if (measured_power < -100 || measured_power > 20) { // -100:Analyzing conditions, 20:Analyzing conditions
116         return BLE_HS_EINVAL;
117     }
118 
119     svc_data[0] = measured_power;
120     /* UID. */
121     memcpy_s(svc_data + 1, sizeof(svc_data + 1), uid, 16); // 16:size
122     /* Reserved. */
123     svc_data[17] = 0x00; // 17:array element
124     svc_data[18] = 0x00; // 18:array element
125     rc = ble_eddystone_set_adv_data_gen(adv_fields, 19); // 19:svc_data_len
126     if (rc != 0) {
127         return rc;
128     }
129 
130     return 0;
131 }
132 
ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields * adv_fields,uint8_t url_scheme,char * url_body,uint8_t url_body_len,uint8_t url_suffix,int8_t measured_power)133 int ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields,
134                                    uint8_t url_scheme, char *url_body,
135                                    uint8_t url_body_len, uint8_t url_suffix,
136                                    int8_t measured_power)
137 {
138     uint8_t *svc_data;
139     int url_len;
140     int rc;
141     url_len = url_body_len;
142 
143     if (url_suffix != BLE_EDDYSTONE_URL_SUFFIX_NONE) {
144         url_len++;
145     }
146 
147     if (url_len > BLE_EDDYSTONE_URL_MAX_LEN) {
148         return BLE_HS_EINVAL;
149     }
150 
151     svc_data = ble_eddystone_set_svc_data_base(BLE_EDDYSTONE_FRAME_TYPE_URL);
152 
153     /* Measured Power ranging data (Calibrated tx power at 0 meters). */
154     if (measured_power < -100 || measured_power > 20) { // -100:Analyzing conditions, 20:Analyzing conditions
155         return BLE_HS_EINVAL;
156     }
157 
158     svc_data[0] = measured_power;
159     svc_data[1] = url_scheme;
160     memcpy_s(svc_data + 2, sizeof(svc_data + 2), url_body, url_body_len); // 2:byte alignment
161 
162     if (url_suffix != BLE_EDDYSTONE_URL_SUFFIX_NONE) {
163         svc_data[2 + url_body_len] = url_suffix; // 2:byte alignment
164     }
165 
166     rc = ble_eddystone_set_adv_data_gen(adv_fields, url_len + 2); // 2:byte alignment
167     if (rc != 0) {
168         return rc;
169     }
170 
171     return 0;
172 }