Skip to content

Commit f794a51

Browse files
committed
Hashing out API of DFUService
1 parent feacfdf commit f794a51

File tree

3 files changed

+502
-0
lines changed

3 files changed

+502
-0
lines changed

services/inc/DFUService.h

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
/*
2+
* Mbed-OS Microcontroller Library
3+
* Copyright (c) 2020 Embedded Planet
4+
* Copyright (c) 2020 ARM Limited
5+
* SPDX-License-Identifier: Apache-2.0
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License
18+
*/
19+
20+
#ifndef MBED_OS_EXPERIMENTAL_BLE_SERVICES_SERVICES_INC_DFUSERVICE_H_
21+
#define MBED_OS_EXPERIMENTAL_BLE_SERVICES_SERVICES_INC_DFUSERVICE_H_
22+
23+
#include "ble/common/UUID.h"
24+
#include "ble/BLE.h"
25+
#include "ble/GattServer.h"
26+
#include "ble/Gap.h"
27+
28+
#include "platform/Callback.h"
29+
#include "platform/Span.h"
30+
#include "platform/CircularBuffer.h"
31+
#include "platform/PlatformMutex.h"
32+
33+
#include "BlockDevice.h"
34+
35+
/**
36+
* Maximum length of data (in bytes) that the DFU service
37+
* can receive at one time.
38+
*
39+
* Typically MTU - 3 bytes for overhead
40+
*/
41+
#ifndef MBED_CONF_CORDIO_DESIRED_ATT_MTU
42+
#define BLE_DFU_SERVICE_MAX_DATA_LEN MBED_CONF_BLE_DFU_SERVICE_BUFFER_SIZE
43+
#else
44+
#define BLE_DFU_SERVICE_MAX_DATA_LEN (MBED_CONF_CORDIO_DESIRED_ATT_MTU - 3)
45+
#endif
46+
47+
/**
48+
* RX Buffer Sizes
49+
*/
50+
#ifndef MBED_CONF_BLE_DFU_SERVICE_RX_BUFFER_SIZE
51+
#define MBED_CONF_BLE_DFU_SERVICE_RX_BUFFER_SIZE 256
52+
#endif
53+
54+
/**
55+
* Maximum number of slots available
56+
*/
57+
#ifndef MBED_CONF_BLE_DFU_SERVICE_MAX_SLOTS
58+
#define MBED_CONF_BLE_DFU_SERVICE_MAX_SLOTS 3
59+
#endif
60+
61+
/**
62+
* UUIDs
63+
*/
64+
namespace uuids {
65+
namespace DFUService {
66+
67+
const UUID BaseUUID("53880000-65fd-4651-ba8e-91527f06c887");
68+
const UUID SlotUUID("53880001-65fd-4651-ba8e-91527f06c887");
69+
const UUID OffsetUUID("53880002-65fd-4651-ba8e-91527f06c887");
70+
const UUID BinaryStreamUUID("53880003-65fd-4651-ba8e-91527f06c887");
71+
const UUID ControlUUID("53880004-65fd-4651-ba8e-91527f06c887");
72+
const UUID StatusUUID("53880005-65fd-4651-ba8e-91527f06c887");
73+
74+
}}
75+
76+
77+
/**
78+
* API Brainstorm:
79+
* DFU service will have several characteristics:
80+
* - Current Offset (Read/Write), gives the offset address, in bytes, of the write pointer
81+
* --- Writes to this characteristic while there is data in binary data stream buffer will be rejected.
82+
* A rejected write will initiate flushing the buffer to the selected slot block device.
83+
* Subsequent writes will be rejected until flushing is complete.
84+
* Note: any writes to the binary data stream characteristic while the buffer is being flushed will be ignored
85+
* --- If the delta bit is enabled, any memory sections skipped will be written with bytes copied from the primary application
86+
* - Binary Data stream, variable-length array characteristic for streaming the update in binary.
87+
* The underlying block device will be written at the offset given by current offset for each byte written to this characteristic.
88+
* The offset is incremented for each byte written
89+
* - DFU Control Characteristic
90+
* - Notify/Indicate/Read (for flow control bit mainly)
91+
* - Write (w/ response), ability to add security requirements
92+
* - Bit flags:
93+
* --- DFU Enable, DFU abort = write 0 during update
94+
* --- DFU Commit
95+
* --- Delta mode (any skipped sections will be written with existing app data)
96+
* --- Flow Control Bit (if set, peer should pause writing to binary stream characteristic)
97+
* - Write is only allowed if DFU is currently allowed
98+
* - Allows application/device to prepare for an update (cache/save data, shutdown certain things, erase/prepare flash area)
99+
* - Status characteristic
100+
* - Notify/Indicate/Read
101+
* - Error code (eg: update too large, invalid update (after reboot), etc)
102+
* - Selected Slot
103+
* - Write (w/ response)
104+
* - Write is only allowed if slot has valid block device
105+
* - Deselected slot BD is deinited, selected slot is inited
106+
* - Similar to offset, writes to this characteristic while there is data in the binary data stream buffer
107+
* will flush the buffer to the selected block device before the selected slot change is applied.
108+
* Note: In delta mode, selecting a new slot WILL NOT result in the remaining data in the slot being written with copied application data
109+
* To accomplish this, the peer should write the offset characteristic to the point where data should be copied before changing slots.
110+
*
111+
* Notes:
112+
* - Valid slots are intended to be empirically determined by the peer (as necessary)
113+
* by attempting to set the
114+
*
115+
* - Should writes to the binary data stream be synchronized with flash write waits? Potentially much slower
116+
* - Control bitflags class? Use std::bitset?
117+
*
118+
*/
119+
#if BLE_FEATURE_GATT_SERVER
120+
121+
class DFUService : public ble::GattServer::EventHandler,
122+
public ble::Gap::EventHandler,
123+
private mbed::NonCopyable<DFUService> {
124+
125+
public:
126+
127+
128+
/**
129+
* As per Bluetooth Core specification V5.2, Vol 3, Part F, Table 3.4 (Error Codes)
130+
* ATT Error Codes between 0x80 and 0x9F are reserved for use by the application
131+
*
132+
* These error codes are valid for the DFUService application layer in addition to those
133+
* defined in the GattAuthCallbackReply_t enum.
134+
*/
135+
enum ApplicationError_t {
136+
137+
AUTH_CALLBACK_REPLY_ATTERR_APP_BUSY = 0x019E, /** DFUService is busy (eg: flush in progress) */
138+
AUTH_CALLBACK_REPLY_ATTERR_APP_INVALID_SLOT_NUM = 0x019F, /** Client requested invalid slot index */
139+
140+
};
141+
142+
/**
143+
* Class encapsulating a change to the DFU control characteristic
144+
*/
145+
class ControlChange {
146+
147+
/* Allow DFUService to instantiate ControlChange instances */
148+
friend DFUService;
149+
150+
public:
151+
152+
const DFUService& service() const {
153+
return _dfu_svc;
154+
}
155+
156+
uint8_t value() const {
157+
return _new_value;
158+
}
159+
160+
uint8_t get_changed_bits() const {
161+
return (_old_value ^ _new_value);
162+
}
163+
164+
protected:
165+
166+
ControlChange(DFUService& service, uint8_t value) :
167+
_dfu_svc(service), _old_value(service.get_dfu_control_bits()),
168+
_new_value(value) {
169+
}
170+
171+
protected:
172+
173+
DFUService& _dfu_svc;
174+
175+
uint8_t _old_value;
176+
uint8_t _new_value;
177+
178+
};
179+
180+
public:
181+
182+
/**
183+
* Instantiate a DFUService instance
184+
* @param[in] bd BlockDevice to use for storing update candidates in slot 0
185+
*/
186+
DFUService(mbed::BlockDevice *bd);
187+
188+
virtual ~DFUService();
189+
190+
uint8_t get_dfu_control_bits() const {
191+
return _dfu_control;
192+
}
193+
194+
bool is_dfu_enabled() const {
195+
// TODO return _dfu_contrl & DFU_ENABLED_BIT
196+
}
197+
198+
void start(BLE &ble_interface);
199+
200+
void assign_slot_block_device(uint8_t slot, mbed::BlockDevice *bd);
201+
202+
/**
203+
* Register a callback to be executed when a write request occurs for the
204+
* DFU Control characteristic. The application may then accept or reject the
205+
* requested changes as appropriate.
206+
*
207+
* @param[in] cb Application callback or nullptr to deregister
208+
*
209+
* @note If the application does not explicitly reject the control request,
210+
* the request will be accepted by default.
211+
*/
212+
void on_dfu_control_request(mbed::Callback<GattAuthCallbackReply_t(ControlChange&)> cb) {
213+
_ctrl_req_cb = cb;
214+
}
215+
216+
/**
217+
* Register a callback to be executed when a write is committed to the
218+
* DFU Control characteristic
219+
*
220+
* @param[in] cb Application callback or nullptr to deregister
221+
*
222+
*/
223+
void on_dfu_control_change(mbed::Callback<void(ControlChange&)> cb) {
224+
_ctrl_update_cb = cb;
225+
}
226+
227+
protected:
228+
229+
void set_status();
230+
231+
/** GattServer::EventHandler overrides */
232+
void onDataWritten(const GattWriteCallbackParams &params) override;
233+
234+
/** Gap::EventHandler overrides */
235+
void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override;
236+
237+
/** Internal handlers */
238+
void on_slot_write_request(GattWriteAuthCallbackParams *params);
239+
void on_slot_written(uint8_t new_slot);
240+
241+
void on_offset_write_request(GattWriteAuthCallbackParams *params);
242+
void on_offset_written(uint32_t new_offset);
243+
244+
void on_bds_written(mbed::Span<const uint8_t> data);
245+
246+
void on_dfu_ctrl_write_request(GattWriteAuthCallbackParams *params);
247+
void on_dfu_ctrl_written(uint8_t new_ctrl);
248+
249+
protected:
250+
251+
/** Selected slot */
252+
uint8_t _selected_slot = 0;
253+
254+
/** Current offset address */
255+
uint32_t _current_offset = 0;
256+
257+
/** RX Buffer for binary serial */
258+
uint8_t _rxbuf[BLE_DFU_SERVICE_MAX_DATA_LEN] = { 0 };
259+
260+
/** DFU control */
261+
uint8_t _dfu_control = 0;
262+
263+
/** Update status */
264+
uint8_t _status = 0;
265+
266+
/** Gatt Characteristics */
267+
GattCharacteristic _slot_char;
268+
GattCharacteristic _offset_char;
269+
GattCharacteristic _rx_char;
270+
GattCharacteristic _dfu_ctrl_char;
271+
GattCharacteristic _status_char;
272+
273+
GattCharacteristic* _characteristics[5];
274+
275+
GattService _dfu_service;
276+
277+
GattServer* _server;
278+
279+
/** Slot BlockDevices */
280+
mbed::BlockDevice *_slot_bds[MBED_CONF_BLE_DFU_SERVICE_MAX_SLOTS] = { 0 };
281+
282+
/** Application callbacks */
283+
mbed::Callback<GattAuthCallbackReply_t(ControlChange&)> _ctrl_req_cb = nullptr;
284+
mbed::Callback<void(ControlChange&)> _ctrl_update_cb = nullptr;
285+
286+
/** Internal circular buffer */
287+
mbed::CircularBuffer<uint8_t, MBED_CONF_BLE_DFU_SERVICE_RX_BUFFER_SIZE> _bin_stream_buf;
288+
289+
/** Flush binary stream buffer flag */
290+
bool _flush_bin_buf = false;
291+
292+
/** Mutex */
293+
PlatformMutex _mutex;
294+
295+
};
296+
297+
#endif //BLE_FEATURE_GATT_SERVER
298+
299+
300+
#endif /* MBED_OS_EXPERIMENTAL_BLE_SERVICES_SERVICES_INC_DFUSERVICE_H_ */

0 commit comments

Comments
 (0)