Skip to content

Commit c1a427a

Browse files
committed
add EddyStone URL
Expand BLEAdvertising.addUuid() to take list of uuid
1 parent 27192fe commit c1a427a

File tree

7 files changed

+330
-9
lines changed

7 files changed

+330
-9
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
- Add the option to advertise for a specific time. There are multiple timeouts: initial fast advertising mode, slow advertising mode, and an optional delay to stop advertising entirely. Values can be set in multiple of timeout ticks (0.625ms per unit) or in ms (approximate since it gets converted to 0.625ms units). The optional timeout to stop advertising entire is set via the `.start(timeout)` parameter.
3838
- Blue LED will blink 2x in fast mode than slow mode.
3939
- Default timeout to slow mode = 30 seconds. Default adv intervals are fast mode = 20 ms, slow = 152.5 ms
40+
- Expand addUuid(), addService() to take a list of UUID
4041
- Add new example `advance_adv`
4142

4243
### BLEGAP (To support multiple connections, etc.)

libraries/Bluefruit52Lib/src/BLEAdvertising.cpp

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,82 @@ bool BLEAdvertisingData::addData(uint8_t type, const void* data, uint8_t len)
6363

6464
bool BLEAdvertisingData::addUuid(BLEUuid bleuuid)
6565
{
66-
switch ( bleuuid.size() )
66+
return addUuid(&bleuuid, 1);
67+
}
68+
69+
bool BLEAdvertisingData::addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2)
70+
{
71+
BLEUuid bleuuid[] = { bleuuid1, bleuuid2 };
72+
return addUuid(bleuuid, 2);
73+
}
74+
75+
bool BLEAdvertisingData::addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3)
76+
{
77+
BLEUuid bleuuid[] = { bleuuid1, bleuuid2, bleuuid3};
78+
return addUuid(bleuuid, 3);
79+
}
80+
81+
bool BLEAdvertisingData::addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3, BLEUuid bleuuid4)
82+
{
83+
BLEUuid bleuuid[] = { bleuuid1, bleuuid2, bleuuid3, bleuuid4 };
84+
return addUuid(bleuuid, 4);
85+
}
86+
87+
bool BLEAdvertisingData::addUuid(BLEUuid bleuuid[], uint8_t count)
88+
{
89+
uint16_t uuid16_list[15];
90+
uint8_t uuid16_count = 0;
91+
92+
uint8_t const* uuid128 = NULL;
93+
94+
for(uint8_t i=0; i<count; i++)
6795
{
68-
case 16:
69-
return addData(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE, &bleuuid._uuid.uuid, 2);
70-
break;
96+
switch ( bleuuid[i].size() )
97+
{
98+
case 16:
99+
uuid16_list[uuid16_count++] = bleuuid[i]._uuid.uuid;
100+
break;
71101

72-
case 128:
73-
return addData(BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE, bleuuid._uuid128, 16);
74-
break;
102+
case 128:
103+
// cannot fit more than one uuid128
104+
if ( uuid128 ) return false;
105+
uuid128 = bleuuid[i]._uuid128;
106+
break;
75107

76-
default: break;
108+
default: break;
109+
}
77110
}
78111

79-
return false;
112+
if (uuid16_count)
113+
{
114+
VERIFY( addData(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, uuid16_list, 2*uuid16_count) );
115+
}
116+
117+
if (uuid128)
118+
{
119+
VERIFY( addData(BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, uuid128, 16) );
120+
}
121+
122+
return true;
80123
}
81124

125+
//bool BLEAdvertisingData::addService(BLEService& service[], uint8_t count)
126+
//{
127+
// for(uint8_t i=0; i<count; i++)
128+
// {
129+
//
130+
// }
131+
//}
132+
//
133+
//bool BLEAdvertisingData::addService(BLEClientService& service[], uint8_t count)
134+
//{
135+
// for(uint8_t i=0; i<count; i++)
136+
// {
137+
//
138+
// }
139+
//}
140+
141+
82142
bool BLEAdvertisingData::addService(BLEService& service)
83143
{
84144
return addUuid(service.uuid);

libraries/Bluefruit52Lib/src/BLEAdvertising.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,18 @@ class BLEAdvertisingData
7474
bool addAppearance(uint16_t appearance);
7575

7676
bool addUuid(BLEUuid bleuuid);
77+
bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2);
78+
bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3);
79+
bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3, BLEUuid bleuuid4);
80+
81+
bool addUuid(BLEUuid bleuuid[], uint8_t count);
82+
7783
bool addService(BLEService& service);
7884
bool addService(BLEClientService& service);
7985

86+
// bool addService(BLEService& service[], uint8_t count);
87+
// bool addService(BLEClientService& service[], uint8_t count);
88+
8089
// Custom API
8190
uint8_t count(void);
8291
uint8_t* getData(void);

libraries/Bluefruit52Lib/src/BLEUuid.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class BLEUuid
9696
#define UUID16_SVC_BMS 0x181E
9797
#define UUID16_SVC_CGM 0x181F
9898
#define UUID16_SVC_PLX 0x1822
99+
#define UUID16_SVC_EDDYSTONE 0xFEAA
99100

100101
// Characteristic UUID
101102
#define UUID16_CHR_REMOVABLE 0x2A3A

libraries/Bluefruit52Lib/src/bluefruit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#include "services/BLEHidGeneric.h"
7575
#include "services/BLEHidAdafruit.h"
7676
#include "services/BLEMidi.h"
77+
#include "services/EddyStone.h"
7778

7879
#include "clients/BLEAncs.h"
7980
#include "clients/BLEClientUart.h"
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/**************************************************************************/
2+
/*!
3+
@file EddyStone.cpp
4+
@author hathach
5+
6+
@section LICENSE
7+
8+
Software License Agreement (BSD License)
9+
10+
Copyright (c) 2017, Adafruit Industries (adafruit.com)
11+
All rights reserved.
12+
13+
Redistribution and use in source and binary forms, with or without
14+
modification, are permitted provided that the following conditions are met:
15+
1. Redistributions of source code must retain the above copyright
16+
notice, this list of conditions and the following disclaimer.
17+
2. Redistributions in binary form must reproduce the above copyright
18+
notice, this list of conditions and the following disclaimer in the
19+
documentation and/or other materials provided with the distribution.
20+
3. Neither the name of the copyright holders nor the
21+
names of its contributors may be used to endorse or promote products
22+
derived from this software without specific prior written permission.
23+
24+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
25+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
28+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34+
*/
35+
/**************************************************************************/
36+
37+
#include "bluefruit.h"
38+
39+
/*------------------------------------------------------------------*/
40+
/* EddyStone URL
41+
*------------------------------------------------------------------*/
42+
char const * const prefix_scheme[] =
43+
{
44+
[0] = "http://www." ,
45+
[1] = "https://www." ,
46+
[2] = "http://" ,
47+
[3] = "https://"
48+
};
49+
enum { PREFIX_COUNT = sizeof(prefix_scheme)/sizeof(char*) };
50+
51+
char const * const url_expansion[] =
52+
{
53+
[0 ] = ".com/" ,
54+
[1 ] = ".org/" ,
55+
[2 ] = ".edu/" ,
56+
[3 ] = ".net/" ,
57+
[4 ] = ".info/" ,
58+
[5 ] = ".biz/" ,
59+
[6 ] = ".gov/" ,
60+
61+
[7 ] = ".com" ,
62+
[8 ] = ".org" ,
63+
[9 ] = ".edu" ,
64+
[10] = ".net" ,
65+
[11] = ".info" ,
66+
[12] = ".biz" ,
67+
[13] = ".gov" ,
68+
};
69+
70+
enum { EXPANNSION_COUNT = sizeof(url_expansion)/sizeof(char*) };
71+
72+
EddyStoneUrl::EddyStoneUrl(void)
73+
{
74+
_rssi = 0;
75+
_url = NULL;
76+
}
77+
78+
EddyStoneUrl::EddyStoneUrl(int8_t rssiAt0m, const char* url)
79+
{
80+
_rssi = rssiAt0m;
81+
_url = url;
82+
}
83+
84+
bool EddyStoneUrl::setUrl(const char* url)
85+
{
86+
_url = url;
87+
}
88+
89+
void EddyStoneUrl::setRssi(int8_t rssiAt0m)
90+
{
91+
_rssi = rssiAt0m;
92+
}
93+
94+
char const* findExpansion(char const* p_url, uint8_t * p_idx)
95+
{
96+
for(uint8_t i=0; i<EXPANNSION_COUNT; i++)
97+
{
98+
char const * substr = strstr(p_url, url_expansion[i]);
99+
100+
if ( substr )
101+
{
102+
*p_idx = i;
103+
return substr;
104+
}
105+
}
106+
107+
return NULL;
108+
}
109+
110+
bool EddyStoneUrl::start(void)
111+
{
112+
enum { URL_MAXLEN = 17 };
113+
struct ATTR_PACKED {
114+
uint16_t eddy_uuid;
115+
116+
uint8_t frame_type;
117+
int8_t rssi;
118+
uint8_t url_scheme;
119+
uint8_t urlencode[URL_MAXLEN];
120+
}eddy =
121+
{
122+
.eddy_uuid = UUID16_SVC_EDDYSTONE,
123+
.frame_type = EDDYSTONE_TYPE_URL,
124+
.rssi = _rssi,
125+
.url_scheme = 0xff
126+
};
127+
128+
const char* url = _url;
129+
130+
// Detect url scheme
131+
for(uint8_t i=0; i<PREFIX_COUNT; i++)
132+
{
133+
uint8_t prelen = strlen(prefix_scheme[i]);
134+
if ( !memcmp(url, prefix_scheme[i], prelen) )
135+
{
136+
eddy.url_scheme = i;
137+
url += prelen;
138+
139+
break;
140+
}
141+
}
142+
VERIFY( eddy.url_scheme < PREFIX_COUNT );
143+
144+
// Encode url data
145+
uint8_t len = 0;
146+
147+
while(*url)
148+
{
149+
uint8_t ex_code;
150+
char const * expansion = findExpansion(url, &ex_code);
151+
152+
// copy url up to the found expansion, if expansion is found, one more
153+
// byte must be reserved for it
154+
uint8_t cp_num = (expansion) ? (expansion-url) : strlen(url);
155+
if ( cp_num > URL_MAXLEN-(len + (expansion ? 1:0)) )
156+
{
157+
LOG_LV1(EDDYSTONE, "url is too long");
158+
return false;
159+
}
160+
161+
memcpy(eddy.urlencode+len, url, cp_num);
162+
url += cp_num;
163+
len += cp_num;
164+
165+
// copy expansion code if found
166+
if (expansion)
167+
{
168+
eddy.urlencode[len++] = ex_code;
169+
url += strlen(url_expansion[ex_code]);
170+
}
171+
}
172+
173+
// Add UUID16 list with EddyStone
174+
VERIFY ( Bluefruit.Advertising.addUuid(UUID16_SVC_EDDYSTONE) );
175+
176+
// Add Eddystone Service Data
177+
VERIFY ( Bluefruit.Advertising.addData(BLE_GAP_AD_TYPE_SERVICE_DATA, &eddy, len + 5) );
178+
179+
return true;
180+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**************************************************************************/
2+
/*!
3+
@file EddyStone.h
4+
@author hathach
5+
6+
@section LICENSE
7+
8+
Software License Agreement (BSD License)
9+
10+
Copyright (c) 2017, Adafruit Industries (adafruit.com)
11+
All rights reserved.
12+
13+
Redistribution and use in source and binary forms, with or without
14+
modification, are permitted provided that the following conditions are met:
15+
1. Redistributions of source code must retain the above copyright
16+
notice, this list of conditions and the following disclaimer.
17+
2. Redistributions in binary form must reproduce the above copyright
18+
notice, this list of conditions and the following disclaimer in the
19+
documentation and/or other materials provided with the distribution.
20+
3. Neither the name of the copyright holders nor the
21+
names of its contributors may be used to endorse or promote products
22+
derived from this software without specific prior written permission.
23+
24+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
25+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
28+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34+
*/
35+
/**************************************************************************/
36+
#ifndef EDDYSTONE_H_
37+
#define EDDYSTONE_H_
38+
39+
#include "bluefruit_common.h"
40+
41+
#include "BLECharacteristic.h"
42+
#include "BLEService.h"
43+
44+
enum
45+
{
46+
EDDYSTONE_TYPE_UID = 0x00,
47+
EDDYSTONE_TYPE_URL = 0x10,
48+
EDDYSTONE_TYPE_TLM = 0x20,
49+
EDDYSTONE_TYPE_EID = 0x30,
50+
};
51+
52+
class EddyStoneUrl
53+
{
54+
private:
55+
int8_t _rssi;
56+
const char* _url;
57+
58+
public:
59+
EddyStoneUrl(void);
60+
EddyStoneUrl(int8_t rssiAt0m, const char* url = NULL);
61+
62+
bool setUrl(const char* url);
63+
void setRssi(int8_t rssiAt0m);
64+
65+
bool start(void);
66+
};
67+
68+
69+
#endif /* EDDYSTONE_H_ */

0 commit comments

Comments
 (0)