-
Notifications
You must be signed in to change notification settings - Fork 7.4k
/
BLE_EddystoneURL_Beacon.ino
192 lines (158 loc) · 4.54 KB
/
BLE_EddystoneURL_Beacon.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
EddystoneURL beacon by BeeGee
EddystoneURL frame specification https://github.com/google/eddystone/blob/master/eddystone-url/README.md
*/
/*
Create a BLE server that will send periodic Eddystone URL frames.
The design of creating the BLE server is:
1. Create a BLE Server
2. Create advertising data
3. Start advertising.
4. wait
5. Stop advertising.
6. deep sleep
*/
#include "sys/time.h"
#include <Arduino.h>
#include "BLEDevice.h"
#include "BLEUtils.h"
#include "BLEBeacon.h"
#include "BLEAdvertising.h"
#include "BLEEddystoneURL.h"
#include "esp_sleep.h"
#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up
RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory
RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
BLEAdvertising *pAdvertising;
struct timeval now;
#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
static const char *eddystone_url_prefix_subs[] = {
"http://www.",
"https://www.",
"http://",
"https://",
"urn:uuid:",
NULL
};
static const char *eddystone_url_suffix_subs[] = {
".com/",
".org/",
".edu/",
".net/",
".info/",
".biz/",
".gov/",
".com",
".org",
".edu",
".net",
".info",
".biz",
".gov",
NULL
};
static int string_begin_with(const char *str, const char *prefix)
{
int prefix_len = strlen(prefix);
if (strncmp(prefix, str, prefix_len) == 0)
{
return prefix_len;
}
return 0;
}
void setBeacon()
{
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
const char url[] = "https://d.giesecke.tk";
int scheme_len, ext_len = 1, i, idx, url_idx;
char *ret_data;
int url_len = strlen(url);
ret_data = (char *)calloc(1, url_len + 13);
ret_data[0] = 2; // Len
ret_data[1] = 0x01; // Type Flags
ret_data[2] = 0x06; // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
ret_data[3] = 3; // Len
ret_data[4] = 0x03; // Type 16-Bit UUID
ret_data[5] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB
ret_data[6] = 0xFE; // Eddystone UUID 1 MSB
ret_data[7] = 19; // Length of Beacon Data
ret_data[8] = 0x16; // Type Service Data
ret_data[9] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB
ret_data[10] = 0xFE; // Eddystone UUID 1 MSB
ret_data[11] = 0x10; // Eddystone Frame Type
ret_data[12] = 0xF4; // Beacons TX power at 0m
i = 0, idx = 13, url_idx = 0;
//replace prefix
scheme_len = 0;
while (eddystone_url_prefix_subs[i] != NULL)
{
if ((scheme_len = string_begin_with(url, eddystone_url_prefix_subs[i])) > 0)
{
ret_data[idx] = i;
idx++;
url_idx += scheme_len;
break;
}
i++;
}
while (url_idx < url_len)
{
i = 0;
ret_data[idx] = url[url_idx];
ext_len = 1;
while (eddystone_url_suffix_subs[i] != NULL)
{
if ((ext_len = string_begin_with(&url[url_idx], eddystone_url_suffix_subs[i])) > 0)
{
ret_data[idx] = i;
break;
}
else
{
ext_len = 1; //inc 1
}
i++;
}
url_idx += ext_len;
idx++;
}
ret_data[7] = idx - 8;
Serial.printf("struct size %d url size %d reported len %d\n",
url_len + 13,
url_len, ret_data[7]);
Serial.printf("URL in data %s\n", &ret_data[13]);
std::string eddyStoneData(ret_data);
oAdvertisementData.addData(eddyStoneData);
oScanResponseData.setName("URLBeacon");
pAdvertising->setAdvertisementData(oAdvertisementData);
pAdvertising->setScanResponseData(oScanResponseData);
}
void setup()
{
Serial.begin(115200);
gettimeofday(&now, NULL);
Serial.printf("start ESP32 %d\n", bootcount++);
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", now.tv_sec, now.tv_sec - last);
last = now.tv_sec;
// Create the BLE Device
BLEDevice::init("URLBeacon");
BLEDevice::setPower(ESP_PWR_LVL_N12);
// Create the BLE Server
// BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage
pAdvertising = BLEDevice::getAdvertising();
setBeacon();
// Start advertising
pAdvertising->start();
Serial.println("Advertizing started...");
delay(10000);
pAdvertising->stop();
Serial.printf("enter deep sleep\n");
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
Serial.printf("in deep sleep\n");
}
void loop()
{
}