2828static const uint8_t kEddystoneUIDFrameTypeID = 0x00 ;
2929static const uint8_t kEddystoneURLFrameTypeID = 0x10 ;
3030static const uint8_t kEddystoneTLMFrameTypeID = 0x20 ;
31+ static const uint8_t kEddystoneEIDFrameTypeID = 0x30 ;
3132
3233// Note that for these Eddystone structures, the endianness of the individual fields is big-endian,
3334// so you'll want to translate back to host format when necessary.
@@ -41,6 +42,12 @@ typedef struct __attribute__((packed)) {
4142 uint8_t RFU[2 ];
4243} ESSEddystoneUIDFrameFields;
4344
45+ typedef struct __attribute__ ((packed)) {
46+ uint8_t frameType;
47+ int8_t txPower;
48+ uint8_t beaconID[8 ];
49+ } ESSEddystoneEIDFrameFields;
50+
4451// Test equality, ensuring that nil is equal to itself.
4552static inline BOOL IsEqualOrBothNil (id a, id b) {
4653 return ((a == b) || (a && b && [a isEqual: b]));
@@ -75,6 +82,8 @@ - (instancetype)initWithType:(ESSBeaconType)beaconType
7582- (NSString *)description {
7683 if (self.beaconType == kESSBeaconTypeEddystone ) {
7784 return [NSString stringWithFormat: @" ESSBeaconID: beaconID=%@ " , self .beaconID];
85+ } else if (self.beaconType == kESSBeaconTypeEddystoneEID ) {
86+ return [NSString stringWithFormat: @" ESSBeaconID (EID): beaconID=%@ " , self .beaconID];
7887 } else {
7988 return [NSString stringWithFormat: @" ESSBeaconID with invalid type %lu " ,
8089 (unsigned long )self .beaconType];
@@ -115,9 +124,7 @@ @implementation ESSBeaconInfo
115124 * Given the advertising frames from CoreBluetooth for a device with the Eddystone Service ID,
116125 * figure out what type of frame it is.
117126 */
118- + (ESSFrameType)frameTypeForFrame : (NSDictionary *)advFrameList {
119- NSData *frameData = advFrameList[[self eddystoneServiceID ]];
120-
127+ + (ESSFrameType)frameTypeForFrame : (NSData *)frameData {
121128 // It's an Eddystone ADV frame. Now check if it's a UID (ID) or TLM (telemetry) frame.
122129 if (frameData) {
123130 uint8_t frameType;
@@ -130,28 +137,19 @@ + (ESSFrameType)frameTypeForFrame:(NSDictionary *)advFrameList {
130137 return kESSEddystoneURLFrameType ;
131138 case kEddystoneTLMFrameTypeID :
132139 return kESSEddystoneTelemetryFrameType ;
140+ case kEddystoneEIDFrameTypeID :
141+ return kESSEddystoneEIDFrameType ;
133142 }
134143 }
135144 }
136145
137146 return kESSEddystoneUnknownFrameType ;
138147}
139148
140- + (NSData *)telemetryDataForFrame : (NSDictionary *)advFrameList {
141- // NOTE: We assume that you've already called [ESSBeaconInfo frameTypeForFrame] to confirm that
142- // this actually IS a telemetry frame.
143- NSAssert ([ESSBeaconInfo frameTypeForFrame: advFrameList] == kESSEddystoneTelemetryFrameType ,
144- @" This should be a TLM frame, but it's not. Whooops" );
145- return advFrameList[[self eddystoneServiceID ]];
146- }
147-
148- + (NSURL *)URLForForFrame : (NSDictionary *)advFrameList {
149- // NOTE: We assume that you've already called [ESSBeaconInfo frameTypeForFrame] to confirm that
150- // this actually IS a URL frame.
151- NSAssert ([ESSBeaconInfo frameTypeForFrame: advFrameList] == kESSEddystoneURLFrameType ,
149+ + (NSURL *)parseURLFromFrameData : (NSData *)URLFrameData {
150+ NSAssert ([ESSBeaconInfo frameTypeForFrame: URLFrameData] == kESSEddystoneURLFrameType ,
152151 @" This should be a URL frame, but it's not. Whooops" );
153- NSData *URLFrameData = advFrameList[[self eddystoneServiceID ]];
154-
152+
155153 if (!(URLFrameData.length > 0 )) {
156154 return nil ;
157155 }
@@ -172,23 +170,23 @@ + (NSURL *)URLForForFrame:(NSDictionary *)advFrameList {
172170- (instancetype )initWithBeaconID : (ESSBeaconID *)beaconID
173171 txPower : (NSNumber *)txPower
174172 RSSI : (NSNumber *)RSSI
175- URL : (NSURL *)URL
176173 telemetry : (NSData *)telemetry {
177174 if ((self = [super init ]) != nil ) {
178175 _beaconID = beaconID;
179176 _txPower = txPower;
180177 _RSSI = RSSI;
181- _URL = URL;
182178 _telemetry = [telemetry copy ];
183179 }
184180
185181 return self;
186182}
187183
188184+ (instancetype )beaconInfoForUIDFrameData : (NSData *)UIDFrameData
189- URL : (NSURL *)URL
190185 telemetry : (NSData *)telemetry
191186 RSSI : (NSNumber *)RSSI {
187+ NSAssert ([ESSBeaconInfo frameTypeForFrame: UIDFrameData] == kESSEddystoneUIDFrameType ,
188+ @" This should be a UID frame, but it's not. Whooops" );
189+
192190 // Make sure this frame has the correct frame type identifier
193191 uint8_t frameType;
194192 [UIDFrameData getBytes: &frameType length: 1 ];
@@ -197,26 +195,60 @@ + (instancetype)beaconInfoForUIDFrameData:(NSData *)UIDFrameData
197195 }
198196
199197 ESSEddystoneUIDFrameFields uidFrame;
200-
198+
201199 if ([UIDFrameData length ] == sizeof (ESSEddystoneUIDFrameFields)
202200 || [UIDFrameData length ] == sizeof (ESSEddystoneUIDFrameFields) - sizeof (uidFrame.RFU )) {
203-
201+
204202 [UIDFrameData getBytes: &uidFrame length: (sizeof (ESSEddystoneUIDFrameFields)
205203 - sizeof (uidFrame.RFU))];
206-
204+
207205 NSData *beaconIDData = [NSData dataWithBytes: &uidFrame.beaconID
208206 length: sizeof (uidFrame.beaconID)];
209-
207+
210208 ESSBeaconID *beaconID = [[ESSBeaconID alloc ] initWithType: kESSBeaconTypeEddystone
211209 beaconID: beaconIDData];
212210 if (beaconID == nil ) {
213211 return nil ;
214212 }
215-
213+
216214 return [[ESSBeaconInfo alloc ] initWithBeaconID: beaconID
217215 txPower: @(uidFrame.txPower)
218216 RSSI: RSSI
219- URL: URL
217+ telemetry: telemetry];
218+ } else {
219+ return nil ;
220+ }
221+ }
222+
223+ + (instancetype )beaconInfoForEIDFrameData : (NSData *)EIDFrameData
224+ telemetry : (NSData *)telemetry
225+ RSSI : (NSNumber *)RSSI {
226+ NSAssert ([ESSBeaconInfo frameTypeForFrame: EIDFrameData] == kESSEddystoneEIDFrameType ,
227+ @" This should be an EID frame, but it's not. Whooops" );
228+
229+ // Make sure this frame has the correct frame type identifier
230+ uint8_t frameType;
231+ [EIDFrameData getBytes: &frameType length: 1 ];
232+ if (frameType != kEddystoneEIDFrameTypeID ) {
233+ return nil ;
234+ }
235+
236+ ESSEddystoneEIDFrameFields eidFrame;
237+
238+ if ([EIDFrameData length ] == sizeof (ESSEddystoneEIDFrameFields)) {
239+ [EIDFrameData getBytes: &eidFrame length: sizeof (ESSEddystoneEIDFrameFields)];
240+ NSData *beaconIDData = [NSData dataWithBytes: &eidFrame.beaconID
241+ length: sizeof (eidFrame.beaconID)];
242+
243+ ESSBeaconID *beaconID = [[ESSBeaconID alloc ] initWithType: kESSBeaconTypeEddystoneEID
244+ beaconID: beaconIDData];
245+ if (beaconID == nil ) {
246+ return nil ;
247+ }
248+
249+ return [[ESSBeaconInfo alloc ] initWithBeaconID: beaconID
250+ txPower: @(eidFrame.txPower)
251+ RSSI: RSSI
220252 telemetry: telemetry];
221253 } else {
222254 return nil ;
@@ -225,14 +257,10 @@ + (instancetype)beaconInfoForUIDFrameData:(NSData *)UIDFrameData
225257
226258- (NSString *)description {
227259 NSString *str = [NSString stringWithFormat: @" Eddystone, id: %@ , RSSI: %@ , txPower: %@ " ,
228- _beaconID, _RSSI, _txPower];
229- if (_URL) {
230- str = [str stringByAppendingFormat: @" , URL: %@ " , _URL];
231- }
260+ _beaconID, _RSSI, _txPower];
232261 return str;
233262}
234263
235-
236264+ (CBUUID *)eddystoneServiceID {
237265 static CBUUID *_singleton;
238266 static dispatch_once_t oncePredicate;
@@ -245,15 +273,13 @@ + (CBUUID *)eddystoneServiceID {
245273}
246274
247275+ (ESSBeaconInfo *)testBeaconFromBeaconIDString : (NSString *)beaconID {
248-
249276 NSData *beaconIDData = [ESSBeaconInfo hexStringToNSData: beaconID];
250-
251277 ESSBeaconID *beaconIDObj = [[ESSBeaconID alloc ] initWithType: kESSBeaconTypeEddystone
252278 beaconID: beaconIDData];
279+
253280 return [[ESSBeaconInfo alloc ] initWithBeaconID: beaconIDObj
254281 txPower: @(-20 )
255282 RSSI: @(-100 )
256- URL: nil
257283 telemetry: nil ];
258284}
259285
0 commit comments