mirror of
				https://github.com/0xFEEDC0DE64/arduino-esp32.git
				synced 2025-10-31 22:21:39 +01:00 
			
		
		
		
	
		
			
	
	
		
			193 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Arduino
		
	
	
	
	
	
		
		
			
		
	
	
			193 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Arduino
		
	
	
	
	
	
|   | /*
 | ||
|  |    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() | ||
|  | { | ||
|  | } |