... | ... |
@@ -0,0 +1,123 @@ |
1 |
+/* |
|
2 |
+ Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp |
|
3 |
+ Ported to Arduino ESP32 by pcbreflux |
|
4 |
+*/ |
|
5 |
+ |
|
6 |
+ |
|
7 |
+/* |
|
8 |
+ Create a BLE server that will send periodic iBeacon frames. |
|
9 |
+ The design of creating the BLE server is: |
|
10 |
+ 1. Create a BLE Server |
|
11 |
+ 2. Create advertising data |
|
12 |
+ 3. Start advertising. |
|
13 |
+ 4. wait |
|
14 |
+ 5. Stop advertising. |
|
15 |
+ 6. deep sleep |
|
16 |
+ |
|
17 |
+*/ |
|
18 |
+#include <heltec.h> |
|
19 |
+#include "sys/time.h" |
|
20 |
+ |
|
21 |
+#include "BLEDevice.h" |
|
22 |
+#include "BLEUtils.h" |
|
23 |
+#include "BLEBeacon.h" |
|
24 |
+#include "esp_bt_device.h" |
|
25 |
+ |
|
26 |
+#include "beacon.h" |
|
27 |
+#include "display.h" |
|
28 |
+#include "button.h" |
|
29 |
+ |
|
30 |
+BLEAdvertising *pAdvertising; |
|
31 |
+ |
|
32 |
+ |
|
33 |
+//----------------------------------------------------------------------------------- |
|
34 |
+ |
|
35 |
+ |
|
36 |
+void setBeacon() { |
|
37 |
+ BLEBeacon oBeacon = BLEBeacon(); |
|
38 |
+ oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) |
|
39 |
+ oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); |
|
40 |
+ oBeacon.setMajor(0); |
|
41 |
+ oBeacon.setMinor(0); |
|
42 |
+ BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); |
|
43 |
+ BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); |
|
44 |
+ oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 |
|
45 |
+ oAdvertisementData.setCompleteServices(BLEUUID(BEACON_SERVICE_UUID)); |
|
46 |
+ |
|
47 |
+ memcpy(&advertising_data[AD_IDX_NAMESPACE], beacon_namespace, 10); |
|
48 |
+ memcpy(&advertising_data[AD_IDX_INSTANCE], beacon_inst, 3); |
|
49 |
+ advertising_data[AD_IDX_TYPE] = beacon_type; |
|
50 |
+ advertising_data[AD_IDX_NUM] = beacon_num[0]; |
|
51 |
+ advertising_data[AD_IDX_NUM+1] = beacon_num[1]; |
|
52 |
+ std::string strServiceData = ""; |
|
53 |
+ strServiceData += (char)21; // Len |
|
54 |
+ strServiceData += (char)0x16; // Fame Type |
|
55 |
+ strServiceData += (char)0xaa; |
|
56 |
+ strServiceData += (char)0xfe; |
|
57 |
+ for(int i =0; i < ADVERT_SZ; i++ ) { |
|
58 |
+ strServiceData += (char)advertising_data[i]; // Len |
|
59 |
+ } |
|
60 |
+ sprintf(instanceStr,"%02x%02x%02x%02x%02x%02x", |
|
61 |
+ advertising_data[AD_IDX_INSTANCE_ALL+AD_SHIFT], advertising_data[AD_IDX_INSTANCE_ALL+AD_SHIFT+1], |
|
62 |
+ advertising_data[AD_IDX_INSTANCE_ALL+AD_SHIFT+2], advertising_data[AD_IDX_INSTANCE_ALL+AD_SHIFT+3], |
|
63 |
+ advertising_data[AD_IDX_INSTANCE_ALL+AD_SHIFT+4], advertising_data[AD_IDX_INSTANCE_ALL+AD_SHIFT+5]); |
|
64 |
+ DisplayButtonStatus(); |
|
65 |
+ |
|
66 |
+ uint8_t *ptr=(uint8_t*)strServiceData.c_str(); |
|
67 |
+ for(int i = 0; i < 36; i++ ) { |
|
68 |
+ Serial.printf("%02x", ptr[i]); |
|
69 |
+ } |
|
70 |
+ Serial.println(""); |
|
71 |
+ oAdvertisementData.addData(strServiceData); |
|
72 |
+ pAdvertising->setAdvertisementData(oAdvertisementData); |
|
73 |
+ pAdvertising->setScanResponseData(oScanResponseData); |
|
74 |
+} |
|
75 |
+ |
|
76 |
+void setup() { |
|
77 |
+ #ifdef _HELTEC_H_ |
|
78 |
+ Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Enable*/, true /*Serial Enable*/, false /*LoRa use PABOOST*/, 0 /*LoRa RF working band*/); |
|
79 |
+ Heltec.display->clear(); |
|
80 |
+ #endif //_HELTEC_H_ |
|
81 |
+ Serial.begin(115200); |
|
82 |
+ |
|
83 |
+ |
|
84 |
+ |
|
85 |
+ Serial.printf("------------------------------"); |
|
86 |
+ |
|
87 |
+ //BLE MAC Address will be new_mac + 2 |
|
88 |
+ esp_base_mac_addr_set(new_mac); |
|
89 |
+ sprintf(macStr,"%02x:%02x:%02x:%02x:%02x:%02x", new_mac[0], new_mac[1], new_mac[2], new_mac[3], new_mac[4], new_mac[5]); |
|
90 |
+ |
|
91 |
+ beaconTypeStr = "Init Safe"; |
|
92 |
+ |
|
93 |
+ // Create the BLE Device |
|
94 |
+ BLEDevice::init(BEACON_NAME); |
|
95 |
+} |
|
96 |
+ |
|
97 |
+void loop() { |
|
98 |
+ |
|
99 |
+ //PRG Button |
|
100 |
+ pollPrg(); |
|
101 |
+ |
|
102 |
+ Serial.println("DeviceAddress: "+String(macStr)); |
|
103 |
+ |
|
104 |
+ // Create the BLE Server |
|
105 |
+ pAdvertising = BLEDevice::getAdvertising(); |
|
106 |
+ BLEDevice::startAdvertising(); |
|
107 |
+ setBeacon(); |
|
108 |
+ // Start advertising |
|
109 |
+ pAdvertising->addServiceUUID(BLEUUID(BEACON_SERVICE_UUID)); |
|
110 |
+ |
|
111 |
+ beacon_count++; |
|
112 |
+ ad_running = 1; |
|
113 |
+ DisplayButtonStatus(); |
|
114 |
+ pAdvertising->start(); |
|
115 |
+ Serial.println("Advertizing started type : "+beaconTypeStr); |
|
116 |
+ delay(BEACON_ADV_DURATION); |
|
117 |
+ pAdvertising->stop(); |
|
118 |
+ ad_running = 0; |
|
119 |
+ DisplayButtonStatus(); |
|
120 |
+ Serial.println("Advertizing stopped."); |
|
121 |
+ |
|
122 |
+ delay(BEACON_SLEEP_ADV); |
|
123 |
+} |
... | ... |
@@ -0,0 +1,53 @@ |
1 |
+#ifndef _BEACON_H |
|
2 |
+#define _BEACON_H |
|
3 |
+ |
|
4 |
+#define BEACON_SLEEP_ADV 2000 //2s between uptime |
|
5 |
+#define BEACON_ADV_DURATION 200 //200ms |
|
6 |
+#define BEACON_UUID "7c8a68a6-ddd0-11e9-8a34-2a2ae2dbcce4" |
|
7 |
+#define BEACON_SERVICE_UUID "feaa" |
|
8 |
+#define BEACON_NAME "FakeESP" |
|
9 |
+enum EN_BEACON_TYPE { |
|
10 |
+ EN_BEACON_TYPE_entry = 0x01, |
|
11 |
+ EN_BEACON_TYPE_exit = 0x02, |
|
12 |
+ EN_BEACON_TYPE_hazard = 0x03, |
|
13 |
+ EN_BEACON_TYPE_safe = 0x04, |
|
14 |
+ EN_BEACON_TYPE_other = 0x05, |
|
15 |
+ EN_BEACON_TYPE_num = 5 |
|
16 |
+}; |
|
17 |
+ |
|
18 |
+uint8_t beacon_type = EN_BEACON_TYPE_safe; |
|
19 |
+String beaconTypeStr = ""; |
|
20 |
+ |
|
21 |
+// Fake MAC Address for BLE beacon |
|
22 |
+uint8_t new_mac[8] = {0xAC, 0x23, 0x3F, 0xCA, 0xFE, 0x01}; |
|
23 |
+ |
|
24 |
+// Fake Complete Instance |
|
25 |
+uint8_t advert_instance[7] = {0x54, 0x43, 0x4c, 0x03, 0x00, 0x00, 0x0a}; |
|
26 |
+// Fake Complete Namespace |
|
27 |
+uint8_t beacon_namespace[10] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; |
|
28 |
+ |
|
29 |
+// Fake Partial Instance |
|
30 |
+// 0x54434cXXYYYY |
|
31 |
+// XX : Beacon Type |
|
32 |
+// YY : Beacon Number |
|
33 |
+uint8_t beacon_inst[3] = { 0x54, 0x43, 0x4c };//Instance ID on 3 bytes |
|
34 |
+uint8_t beacon_num[2] = { 0x00, 0x0b };//11th beacon |
|
35 |
+ |
|
36 |
+ |
|
37 |
+//#define ADVERT_SZ 22 |
|
38 |
+//char advertising_data[ADVERT_SZ]={ 0x15, 0x16, 0xAA, 0xFE, 0x00, 0xE8, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x54, 0x43, 0x4C, 0x04, 0x00, 0x0b }; |
|
39 |
+//#define AD_IDX_NAMESPACE 6 |
|
40 |
+//#define AD_IDX_INSTANCE 16 |
|
41 |
+//#define AD_IDX_TYPE 19 |
|
42 |
+//#define AD_IDX_NUM 20 |
|
43 |
+ |
|
44 |
+#define ADVERT_SZ 18 |
|
45 |
+char advertising_data[ADVERT_SZ]={ 0x00, 0xE8, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x54, 0x43, 0x4C, 0x04, 0x00, 0x0b }; |
|
46 |
+#define AD_IDX_NAMESPACE 2 |
|
47 |
+#define AD_IDX_INSTANCE_ALL 9 |
|
48 |
+#define AD_IDX_INSTANCE 12 |
|
49 |
+#define AD_IDX_TYPE 15 |
|
50 |
+#define AD_IDX_NUM 16 |
|
51 |
+#define AD_SHIFT 3 |
|
52 |
+ |
|
53 |
+#endif //_BEACON_H |
... | ... |
@@ -0,0 +1,48 @@ |
1 |
+#ifndef _BUTTON_H |
|
2 |
+#define _BUTTON_H |
|
3 |
+ |
|
4 |
+#include "beacon.h" |
|
5 |
+ |
|
6 |
+int buttonState = 0; // variable for reading the pushbutton status |
|
7 |
+const int BUTTON_PRG = 0; // PRG Button |
|
8 |
+const int ledPin = 13; // the number of the LED pin |
|
9 |
+ |
|
10 |
+void pollPrg() |
|
11 |
+{ |
|
12 |
+ buttonState = digitalRead(BUTTON_PRG); |
|
13 |
+ if (buttonState == LOW) { |
|
14 |
+ Serial.println("pollPrg: Call"); |
|
15 |
+ switch( beacon_type ) { |
|
16 |
+ case EN_BEACON_TYPE_entry: |
|
17 |
+ beacon_type = EN_BEACON_TYPE_hazard; |
|
18 |
+ beaconTypeStr="Hazard"; |
|
19 |
+ break; |
|
20 |
+ case EN_BEACON_TYPE_hazard: |
|
21 |
+ beacon_type = EN_BEACON_TYPE_safe; |
|
22 |
+ beaconTypeStr="Safe"; |
|
23 |
+ break; |
|
24 |
+ case EN_BEACON_TYPE_safe: |
|
25 |
+ beacon_type = EN_BEACON_TYPE_exit; |
|
26 |
+ beaconTypeStr="Exit"; |
|
27 |
+ break; |
|
28 |
+ case EN_BEACON_TYPE_exit: |
|
29 |
+ beacon_type = EN_BEACON_TYPE_other; |
|
30 |
+ beaconTypeStr="Other"; |
|
31 |
+ break; |
|
32 |
+ case EN_BEACON_TYPE_other: |
|
33 |
+ beacon_type = EN_BEACON_TYPE_entry; |
|
34 |
+ beaconTypeStr="Entry"; |
|
35 |
+ break; |
|
36 |
+ default: |
|
37 |
+ beacon_type = EN_BEACON_TYPE_safe; |
|
38 |
+ beaconTypeStr="Safe"; |
|
39 |
+ break; |
|
40 |
+ } |
|
41 |
+ Serial.println("Switching to "+beaconTypeStr); |
|
42 |
+ } |
|
43 |
+ DisplayButtonStatus(); |
|
44 |
+} |
|
45 |
+ |
|
46 |
+#endif //_BUTTON_H |
|
47 |
+ |
|
48 |
+ |
... | ... |
@@ -0,0 +1,36 @@ |
1 |
+#ifndef _DISPLAY_H |
|
2 |
+#define _DISPLAY_H |
|
3 |
+ |
|
4 |
+#include "beacon.h" |
|
5 |
+ |
|
6 |
+// Display Constants |
|
7 |
+#define LINE1 0 |
|
8 |
+#define LINE2 12 |
|
9 |
+#define LINE3 24 |
|
10 |
+#define LINE4 36 |
|
11 |
+#define LINE5 48 |
|
12 |
+#define LINEBOTTOM 54 |
|
13 |
+ |
|
14 |
+// Display String Variables for updating all screen at once |
|
15 |
+//--------------------------------------------------------------------- |
|
16 |
+char instanceStr[12] = ""; |
|
17 |
+char macStr[18] = ""; |
|
18 |
+int ad_running = 0; |
|
19 |
+uint32_t beacon_count = 0; |
|
20 |
+ |
|
21 |
+//--------------------------------------------------------------------- |
|
22 |
+void DisplayButtonStatus() { |
|
23 |
+ #ifdef _HELTEC_H_ |
|
24 |
+ Heltec.display->clear(); |
|
25 |
+ Heltec.display->drawString(0, LINE1, "MAC: "+String(macStr)); |
|
26 |
+ Heltec.display->drawString(0, LINE2, "I : "+String(instanceStr)); |
|
27 |
+ Heltec.display->drawString(0, LINE4, beaconTypeStr); |
|
28 |
+ Heltec.display->drawString(0, LINEBOTTOM, "Cnt: "+String(beacon_count)); |
|
29 |
+ if( 1 == ad_running ) { |
|
30 |
+ String running="X"; |
|
31 |
+ Heltec.display->drawString(120, LINEBOTTOM, running); |
|
32 |
+ } |
|
33 |
+ Heltec.display->display(); |
|
34 |
+ #endif //_HELTEC_H_ |
|
35 |
+} |
|
36 |
+#endif //_DISPLAY_H |