Skip to content

Commit 70bda92

Browse files
author
Abbas Bracken Ziad
authored
Add Link Loss Service (#14)
* Add Link Loss Service * Set auth reply if alert level is out of range
1 parent 3a86915 commit 70bda92

File tree

3 files changed

+284
-0
lines changed

3 files changed

+284
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2020 ARM Limited
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#ifndef LINK_LOSS_SERVICE_H
19+
#define LINK_LOSS_SERVICE_H
20+
21+
#if BLE_FEATURE_GATT_SERVER
22+
23+
#include "ble/BLE.h"
24+
#include "ble/Gap.h"
25+
#include "events/EventQueue.h"
26+
#include "ble/gap/ChainableGapEventHandler.h"
27+
28+
#include <chrono>
29+
30+
/**
31+
* Link Loss Service
32+
*
33+
* @par purpose
34+
* The link loss service uses the Alert Level characteristic, as defined in
35+
* https://www.bluetooth.com/specifications/assigned-numbers/, to cause an alert
36+
* in the device when the link is lost.
37+
*
38+
* @par usage
39+
* The on_alert_requested() and on_alert_end() event handlers should be overridden
40+
* by your application. For example, in the former case, you could alert the user by
41+
* flashing lights, making noises, moving, etc.
42+
*
43+
* This service requires access to gap events. Please register a
44+
* ChainableGapEventHandler with Gap and pass it to this service.
45+
*
46+
* @note The specification for the link loss service can be found here:
47+
* https://www.bluetooth.com/specifications/gatt
48+
*
49+
* @attention The user should not instantiate more than a single link loss service
50+
*/
51+
class LinkLossService : private ble::Gap::EventHandler {
52+
public:
53+
enum class AlertLevel : uint8_t {
54+
NO_ALERT = 0,
55+
MILD_ALERT = 1,
56+
HIGH_ALERT = 2
57+
};
58+
59+
struct EventHandler {
60+
/**
61+
* On alert requested
62+
*
63+
* This function is called if the client disconnects ungracefully
64+
*
65+
* @attention This is an abstract function and should be overridden by the user.
66+
*/
67+
virtual void on_alert_requested(AlertLevel) { }
68+
/**
69+
* On alert end
70+
*
71+
* This function is called if the alert is stopped
72+
*
73+
* @attention This is an abstract function and should be overridden by the user.
74+
*/
75+
virtual void on_alert_end() { }
76+
};
77+
78+
/**
79+
* Constructor
80+
*
81+
* Initialize the internal BLE, EventQueue and ChainableGapEventHandler objects to @p ble, @p event_queue
82+
* and @p chainable_gap_event_handler, respectively. Furthermore, configure the alert level characteristic
83+
* with the appropriate UUID and initialize it to 0x00 ("No Alert").
84+
*
85+
* @param ble BLE object to host the link loss service
86+
* @param event_queue EventQueue object to configure events
87+
* @param chainable_gap_event_handler ChainableGapEventHandler object to register multiple Gap events
88+
*
89+
* @attention The Initializer must be called after instantiating a link loss service.
90+
*/
91+
LinkLossService(BLE &ble, events::EventQueue &event_queue, ChainableGapEventHandler &chainable_gap_event_handler);
92+
93+
/**
94+
* Destructor
95+
*
96+
* Cancel the pending event queue timeout
97+
*/
98+
~LinkLossService();
99+
100+
LinkLossService(const LinkLossService&) = delete;
101+
LinkLossService &operator=(const LinkLossService&) = delete;
102+
103+
/**
104+
* Initializer
105+
*
106+
* Set the onDataWritten() function as the write authorization callback for the alert level characteristic.
107+
* Add the link loss service to the BLE device and chain of GAP event handlers.
108+
*/
109+
void init();
110+
111+
/**
112+
* Set event handler
113+
*
114+
* @param handler EventHandler object to handle events raised by the link loss service
115+
*/
116+
void set_event_handler(EventHandler* handler);
117+
118+
/**
119+
* Set alert level
120+
*
121+
* @param level New alert level
122+
*/
123+
void set_alert_level(AlertLevel level);
124+
125+
/**
126+
* Set alert timeout
127+
*
128+
* @param timeout Event queue timeout measured in ms
129+
*/
130+
void set_alert_timeout(std::chrono::milliseconds timeout);
131+
132+
/**
133+
* Get alert level
134+
*
135+
* @return AlertLevel The current alert level
136+
*/
137+
AlertLevel get_alert_level();
138+
139+
/**
140+
* Stop alert
141+
*
142+
* Cancel the pending event queue timeout
143+
*/
144+
void stop_alert();
145+
146+
private:
147+
void onConnectionComplete(const ble::ConnectionCompleteEvent &event) override;
148+
149+
void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override;
150+
151+
void onDataWritten(GattWriteAuthCallbackParams *write_request);
152+
153+
BLE &_ble;
154+
events::EventQueue &_event_queue;
155+
ChainableGapEventHandler &_chainable_gap_event_handler;
156+
157+
ReadWriteGattCharacteristic<AlertLevel> _alert_level_char;
158+
AlertLevel _alert_level = AlertLevel::NO_ALERT;
159+
std::chrono::milliseconds _alert_timeout = std::chrono::milliseconds(0);
160+
EventHandler *_alert_handler = nullptr;
161+
162+
bool _in_alert = false;
163+
int _event_queue_handle = 0;
164+
};
165+
166+
#endif // BLE_FEATURE_GATT_SERVER
167+
168+
#endif // LINK_LOSS_SERVICE_H

services/LinkLoss/mbed_lib.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "ble-service-link-loss"
3+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2020 ARM Limited
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#if BLE_FEATURE_GATT_SERVER
19+
20+
#include "ble-service-link-loss/LinkLossService.h"
21+
22+
LinkLossService::LinkLossService(BLE &ble, events::EventQueue &event_queue, ChainableGapEventHandler &chainable_gap_event_handler) :
23+
_ble(ble),
24+
_event_queue(event_queue),
25+
_chainable_gap_event_handler(chainable_gap_event_handler),
26+
_alert_level_char(GattCharacteristic::UUID_ALERT_LEVEL_CHAR, &_alert_level)
27+
{
28+
}
29+
30+
LinkLossService::~LinkLossService()
31+
{
32+
_event_queue.cancel(_event_queue_handle);
33+
}
34+
35+
void LinkLossService::init()
36+
{
37+
GattCharacteristic *charTable[] = { &_alert_level_char };
38+
GattService linkLossService(GattService::UUID_LINK_LOSS_SERVICE, charTable, 1);
39+
40+
_alert_level_char.setWriteAuthorizationCallback(this, &LinkLossService::onDataWritten);
41+
42+
ble_error_t error = _ble.gattServer().addService(linkLossService);
43+
44+
if (error == BLE_ERROR_NONE) {
45+
_chainable_gap_event_handler.addEventHandler(this);
46+
}
47+
}
48+
49+
void LinkLossService::set_event_handler(EventHandler* handler)
50+
{
51+
_alert_handler = handler;
52+
}
53+
54+
void LinkLossService::set_alert_level(AlertLevel level)
55+
{
56+
_alert_level = level;
57+
}
58+
59+
void LinkLossService::set_alert_timeout(std::chrono::milliseconds timeout)
60+
{
61+
_alert_timeout = timeout;
62+
}
63+
64+
LinkLossService::AlertLevel LinkLossService::get_alert_level()
65+
{
66+
return _alert_level;
67+
}
68+
69+
void LinkLossService::stop_alert()
70+
{
71+
_event_queue.cancel(_event_queue_handle);
72+
_event_queue_handle = 0;
73+
if (_in_alert) {
74+
_in_alert = false;
75+
if (_alert_handler) {
76+
_alert_handler->on_alert_end();
77+
}
78+
}
79+
}
80+
81+
void LinkLossService::onConnectionComplete(const ble::ConnectionCompleteEvent &event)
82+
{
83+
if (event.getStatus() == BLE_ERROR_NONE) {
84+
stop_alert();
85+
}
86+
}
87+
88+
void LinkLossService::onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event)
89+
{
90+
AlertLevel level = get_alert_level();
91+
if (_alert_handler != nullptr && event.getReason() == ble::disconnection_reason_t::CONNECTION_TIMEOUT &&
92+
level != AlertLevel::NO_ALERT && !_in_alert) {
93+
_in_alert = true;
94+
_alert_handler->on_alert_requested(level);
95+
if (_alert_timeout > std::chrono::milliseconds(0)) {
96+
_event_queue_handle = _event_queue.call_in(_alert_timeout, [this] { stop_alert(); });
97+
}
98+
}
99+
}
100+
101+
void LinkLossService::onDataWritten(GattWriteAuthCallbackParams *write_request)
102+
{
103+
const uint8_t level = *write_request->data;
104+
105+
if (level <= (uint8_t)(AlertLevel::HIGH_ALERT)) {
106+
set_alert_level((AlertLevel) level);
107+
} else {
108+
// The alert level is out of range
109+
write_request->authorizationReply = static_cast<GattAuthCallbackReply_t>(0xFF);
110+
}
111+
}
112+
113+
#endif // BLE_FEATURE_GATT_SERVER

0 commit comments

Comments
 (0)