-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBLE_binary_encoding.ino
More file actions
293 lines (250 loc) · 11.2 KB
/
BLE_binary_encoding.ino
File metadata and controls
293 lines (250 loc) · 11.2 KB
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// BLE_binary_encoding.ino
// Arduino script for Data Controllers to communicate with the ADPC IoT app
// Include necessary libraries for BLE functionality and JSON handling
#include <BLEDevice.h> // Main BLE library for ESP32
#include <BLEUtils.h> // Utility library for BLE
#include <BLEServer.h> // Library to use ESP32 as a BLE server
#include <ArduinoJson.h> // Library for JSON serialization and parsing
#include <sstream> // Library for string stream operations (used in splitting strings)
#include <vector> // Library for using dynamic arrays
// Define UUIDs for the custom BLE service and characteristic
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" // Unique identifier for the BLE service
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" // Unique identifier for the BLE characteristic
// Declaration of global variables for BLE characteristics and advertising
BLECharacteristic *pConsentCharacteristic; // Pointer to the BLE Characteristic object
BLEAdvertising *pAdvertising; // Pointer to the BLE Advertising object
// Define a structure for consent requests
struct ConsentRequest {
std::string id;
std::string deviceName;
std::string summary;
std::string purposes;
std::string processing;
std::string dataCategory;
std::string measures;
std::string legalBases;
std::string storage;
std::string scale;
std::string duration;
std::string frequency;
std::string location;
};
// Dynamic array to store multiple consent requests
std::vector<ConsentRequest> consentRequests;
bool isAdvertising = false;
// Ensures the device keeps advertising after a user has connected
void ensureAdvertising() {
if (!isAdvertising) {
BLEDevice::startAdvertising();
Serial.println("Advertising started");
isAdvertising = true;
}
}
// Declare function before definition so it can be used
void updateAdvertisingData();
// Callback class for BLE server events (connection and disconnection)
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) override {
updateAdvertisingData();
Serial.println("Device connected");
digitalWrite(LED_BUILTIN, HIGH); // Turn on the built-in LED to indicate connection
delay(200);
digitalWrite(LED_BUILTIN, LOW);
isAdvertising = false;
}
void onDisconnect(BLEServer* pServer) override {
BLEDevice::startAdvertising();
Serial.println("Device disconnected");
digitalWrite(LED_BUILTIN, HIGH); // Turn on the built-in LED to indicate disconnection
delay(200);
digitalWrite(LED_BUILTIN, LOW);
isAdvertising = false;
}
};
// Callback class for handling BLE characteristic write operations
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void handleDeletionRequest(const std::string& partialConsentId) {
auto it = std::remove_if(consentRequests.begin(), consentRequests.end(),
[&partialConsentId](const ConsentRequest& request) {
return request.id.substr(0, partialConsentId.length()) == partialConsentId;
});
if (it != consentRequests.end()) {
consentRequests.erase(it, consentRequests.end());
Serial.print("Consent ID deleted: ");
Serial.println(partialConsentId.c_str());
} else {
Serial.print("Consent ID not found: ");
Serial.println(partialConsentId.c_str());
}
}
void onRead(BLECharacteristic* pCharacteristic) {
std::string value = pCharacteristic->getValue();
Serial.print("Current Value: ");
Serial.println(value.c_str());
}
void onWrite(BLECharacteristic* pCharacteristic) override {
std::string value = pCharacteristic->getValue();
Serial.print("Received request: ");
Serial.println(value.c_str());
if (value.rfind("delete:", 0) == 0) {
Serial.println("Received delete request");
std::string consentId = value.substr(7);
handleDeletionRequest(consentId);
} else {
std::vector<uint8_t> rxValue(value.begin(), value.end());
Serial.println("Received write request");
std::vector<std::string> acceptedIds = split(value, ';');
for (const std::string& id : acceptedIds) {
Serial.print("Consent Accepted: ");
Serial.println(id.c_str());
}
}
}
// Helper function to split a string by a given delimiter and return a vector of substrings
std::string> split(const std::string &s, char delimiter) {
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s); // Use string stream to facilitate splitting
while (std::getline(tokenStream, token, delimiter)) { // Extract tokens delimited by 'delimiter'
tokens.push_back(token);
}
return tokens;
}
};
// Function to dynamically encode a ConsentRequest object into a byte vector
std::vector<uint8_t> encodeConsentRequestDynamic(const ConsentRequest& request) {
std::vector<uint8_t> encodedData;
auto appendData = [&encodedData](const std::string& field) {
uint8_t len = static_cast<uint8_t>(field.length()); // Get the length of the field
encodedData.push_back(len); // Append the length as a byte
encodedData.insert(encodedData.end(), field.begin(), field.end()); // Append the field data
};
// Encode each field of the ConsentRequest
appendData(request.id);
appendData(request.deviceName);
appendData(request.summary);
appendData(request.processing);
appendData(request.purposes);
appendData(request.dataCategory);
appendData(request.measures);
appendData(request.legalBases);
appendData(request.storage);
appendData(request.scale);
appendData(request.duration);
appendData(request.frequency);
appendData(request.location);
return encodedData; // Return the dynamically encoded data
}
// Setup function to initialize the BLE environment
void setup() {
Serial.begin(115200); // Start serial communication at 115200 baud rate
Serial.println("Starting BLE work!");
pinMode(LED_BUILTIN, OUTPUT); // Set the built-in LED as an output
// Initialize the BLE device
BLEDevice::init("ADPC_Beacon");
// Create a BLE server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks()); // Set server callbacks for connect/disconnect events
// Create a BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Set up BLE security
BLESecurity *pSecurity = new BLESecurity();
// Set the authentication mode to require bonding with secure connection
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
// Set the IO capability
pSecurity->setCapability(ESP_IO_CAP_IO);
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
// Create a BLE characteristic for the service
pConsentCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
// Set callbacks for the characteristic to handle write operations
pConsentCharacteristic->setCallbacks(new MyCharacteristicCallbacks());
pService->start(); // Start the service
// Start advertising the BLE service
pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
Serial.println("BLE service is now advertising");
// Populate the consentRequests vector with sample data
consentRequests.push_back({
"q1serviceCustomization",
"Smart Thermostat",
"Customize home heating and cooling preferences.",
"Service Personalization: temperature settings based on preferences and schedule.",
"Access, Store: schedule patterns, temperature preferences",
"Inferred Data: Schedule, Device usage",
"Technical Measures: Data encryption, Anonymization of data",
"Legitimate interest of data subject",
"Human involvement for Control",
"Small scale processing",
"Temporal duration",
"Continous frequency",
"Fixed location"
});
consentRequests.push_back({
"q2activityMonitoring",
"Fitness Tracker",
"Track and analyze physical activity and health data",
"Academic Research: provide insights for fitness goals",
"Collect, Assess: Steps taken, heart rate",
"Collected Personal Data: Health and fitness data",
"Technical Measures: Data encryption, User access controls",
"Vital interest",
"Human involvement for intervention",
"Small scale processing",
"Until event duration",
"Often Frequency",
"Decentralized locations"
});
consentRequests.push_back({
"q3homeSecurity",
"Security Camera",
"Monitor your home with smart security solutions",
"Enforce Security: monitoring for unusual activity",
"Acquire, Pseudonomyse: Video and audio recording, motion",
"Sensitive Data: Video data, Motion events",
"Technical Measures: Data encryption, Limited access",
"Legal Obligation",
"Human not involved",
"Medium scale processing",
"Indeterminate duration",
"Sporadic frequency",
"Random location"
});
}
void updateAdvertisingData() {
static size_t currentIndex = 0;
if (currentIndex >= consentRequests.size()) currentIndex = 0;
// Encode the current consent request into a byte vector
std::vector<uint8_t> encodedData = encodeConsentRequestDynamic(consentRequests[currentIndex]);
// Update the characteristic's value with the new consent request
if (pConsentCharacteristic != nullptr) {
pConsentCharacteristic->setValue(encodedData.data(), encodedData.size());
std::string currentValue = pConsentCharacteristic->getValue();
Serial.print("Current Value: ");
Serial.println(currentValue.c_str());
Serial.print("Updated to consent request: ");
Serial.println(consentRequests[currentIndex].id.c_str());
Serial.print("New Characteristic Value Set: ");
for (auto byte : encodedData) {
Serial.printf("%02X ", byte);
}
Serial.println();
} else {
Serial.println("Error: pConsentCharacteristic is nullptr.");
}
currentIndex++; // Prepare for next update
ensureAdvertising(); // Make sure the device keeps advertising
}
// Main loop function, called repeatedly
void loop() {
ensureAdvertising(); // Continuously ensure that advertising is active
delay(10000);
}