Skip to content

Commit 673d8d9

Browse files
committed
First compiling version of DFUService
1 parent ff2f113 commit 673d8d9

File tree

2 files changed

+395
-66
lines changed

2 files changed

+395
-66
lines changed

services/inc/DFUService.h

Lines changed: 185 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,12 @@
3030
#include "platform/CircularBuffer.h"
3131
#include "platform/PlatformMutex.h"
3232

33+
#include "events/EventQueue.h"
34+
3335
#include "BlockDevice.h"
3436

37+
#include "descriptors/CharacteristicUserDescriptionDescriptor.h"
38+
3539
/**
3640
* Maximum length of data (in bytes) that the DFU service
3741
* can receive at one time.
@@ -45,10 +49,35 @@
4549
#endif
4650

4751
/**
48-
* RX Buffer Sizes
52+
* RX Buffer Size
53+
* This should be at least 1.5X the maximum MTU you expect to accept
54+
* Defaults to 2.5X maximum MTU
4955
*/
5056
#ifndef MBED_CONF_BLE_DFU_SERVICE_RX_BUFFER_SIZE
51-
#define MBED_CONF_BLE_DFU_SERVICE_RX_BUFFER_SIZE 256
57+
#define MBED_CONF_BLE_DFU_SERVICE_RX_BUFFER_SIZE ((BLE_DFU_SERVICE_MAX_DATA_LEN << 1) +\
58+
(BLE_DFU_SERVICE_MAX_DATA_LEN >> 1))
59+
#endif
60+
61+
/**
62+
* RX Buffer Flow Control Pause Threshold
63+
* This is the maximum number of bytes that can be placed into the RX buffer
64+
* before the server automatically sets the flow control pause bit.
65+
*
66+
* By default this is 2X the maximum MTU
67+
*/
68+
#ifndef MBED_CONF_BLE_DFU_SERVICE_RX_FC_PAUSE_THRESHOLD
69+
#define MBED_CONF_BLE_DFU_SERVICE_RX_FC_PAUSE_THRESHOLD (BLE_DFU_SERVICE_MAX_DATA_LEN << 1)
70+
#endif
71+
72+
/**
73+
* RX Buffer Flow Control Unpause Threshold
74+
* This is the maximum number of bytes that can be in the RX buffer
75+
* before the server automatically clears the flow control pause bit.
76+
*
77+
* By default this is 1X the maximum MTU
78+
*/
79+
#ifndef MBED_CONF_BLE_DFU_SERVICE_RX_FC_UNPAUSE_THRESHOLD
80+
#define MBED_CONF_BLE_DFU_SERVICE_RX_FC_UNPAUSE_THRESHOLD BLE_DFU_SERVICE_MAX_DATA_LEN
5281
#endif
5382

5483
/**
@@ -58,18 +87,29 @@
5887
#define MBED_CONF_BLE_DFU_SERVICE_MAX_SLOTS 3
5988
#endif
6089

90+
/**
91+
* Bit flags
92+
*/
93+
#define DFU_CTRL_ENABLE_BIT (1 << 0)
94+
#define DFU_CTRL_COMMIT_BIT (1 << 1)
95+
#define DFU_CTRL_DELTA_MODE_EN_BIT (1 << 2)
96+
#define DFU_CTRL_FC_PAUSE_BIT (1 << 7)
97+
98+
/* Bitmask of read-only bits in the DFU Ctrl bit set */
99+
#define DFU_CTRL_READONLY_BITS (DFU_CTRL_FC_PAUSE_BIT)
100+
61101
/**
62102
* UUIDs
63103
*/
64104
namespace uuids {
65105
namespace DFUService {
66106

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");
107+
extern const char BaseUUID[];
108+
extern const char SlotUUID[];
109+
extern const char OffsetUUID[];
110+
extern const char BinaryStreamUUID[];
111+
extern const char ControlUUID[];
112+
extern const char StatusUUID[];
73113

74114
}}
75115

@@ -99,6 +139,8 @@ namespace DFUService {
99139
* - Status characteristic
100140
* - Notify/Indicate/Read
101141
* - Error code (eg: update too large, invalid update (after reboot), etc)
142+
* - If highest bit is set it indicates a sync lost notification
143+
* ---> The 7LSB will then indicate the expected sequence ID that did not match. The client should restart transmission from this sequence ID.
102144
* - Selected Slot
103145
* - Write (w/ response)
104146
* - Write is only allowed if slot has valid block device
@@ -133,9 +175,26 @@ class DFUService : public ble::GattServer::EventHandler,
133175
* defined in the GattAuthCallbackReply_t enum.
134176
*/
135177
enum ApplicationError_t {
136-
178+
AUTH_CALLBACK_REPLY_ATTERR_APP_NOT_ALLOWED = 0x019C, /** Response when client attempts to enable DFU when disallowed */
179+
AUTH_CALLBACK_REPLY_ATTERR_APP_READONLY = 0x019D, /** A write request was made that modifies data that is read-only */
137180
AUTH_CALLBACK_REPLY_ATTERR_APP_BUSY = 0x019E, /** DFUService is busy (eg: flush in progress) */
138181
AUTH_CALLBACK_REPLY_ATTERR_APP_INVALID_SLOT_NUM = 0x019F, /** Client requested invalid slot index */
182+
};
183+
184+
/**
185+
* DFU-specific status codes
186+
*/
187+
enum StatusCode_t{
188+
DFU_STATE_IDLE = 0x00, /** Neutral state */
189+
DFU_STATE_UPDATE_SUCCESSFUL = 0x01,
190+
DFU_STATE_UNKNOWN_FAILURE = 0x02,
191+
DFU_STATE_VALIDATION_FAILURE = 0x03, /** Validation/Authentication of update candidate failed */
192+
DFU_STATE_INSTALLATION_FAILURE = 0x04, /** Installation of update candidate failed */
193+
DFU_STATE_APPLICATION_OVERSIZE = 0x05, /** Update candidate exceeded memory bounds */
194+
DFU_STATE_FLASH_ERROR = 0x06, /** Flash error */
195+
DFU_STATE_HARDWARE_ERROR = 0x07, /** Hardware failure */
196+
197+
DFU_STATE_SYNC_LOSS_BIT = 0x80, /** If the MSbit is set in the status, the 7LSB indicate the sequence ID at which sync was lost */
139198

140199
};
141200

@@ -179,11 +238,27 @@ class DFUService : public ble::GattServer::EventHandler,
179238

180239
public:
181240

241+
/**
242+
* Protip: as a general rule, when using delegated constructors, you should
243+
* fully specify (ie: initialize all members in the initializer list) the version
244+
* of the constructor that takes the largest number of arguments.
245+
*/
246+
182247
/**
183248
* Instantiate a DFUService instance
184249
* @param[in] bd BlockDevice to use for storing update candidates in slot 0
250+
* @param[in] queue EventQueue to process memory writes on
251+
* @param[in] fw_rev Optional, Current firmware revision string
252+
* @param[in] dev_desc Optional, Description of the device that this firmware is executed on
253+
*
254+
* @note The optional parameters MUST be supplied if your GattServer has multiple DFUService
255+
* instances available. They are optional if your GattServer has only one DFUService instance.
256+
* Each DFUService must implement a firmware revision characteristic with an
257+
* associated characteristic user description descriptor that uniquely identifies
258+
* the device that executes the firmware targeted by the DFUService.
185259
*/
186-
DFUService(mbed::BlockDevice *bd);
260+
DFUService(mbed::BlockDevice *bd, events::EventQueue &queue,
261+
const char *fw_rev = nullptr, const char *dev_desc = nullptr);
187262

188263
virtual ~DFUService();
189264

@@ -192,7 +267,7 @@ class DFUService : public ble::GattServer::EventHandler,
192267
}
193268

194269
bool is_dfu_enabled() const {
195-
// TODO return _dfu_contrl & DFU_ENABLED_BIT
270+
return (_dfu_control & DFU_CTRL_ENABLE_BIT);
196271
}
197272

198273
void start(BLE &ble_interface);
@@ -226,7 +301,84 @@ class DFUService : public ble::GattServer::EventHandler,
226301

227302
protected:
228303

229-
void set_status();
304+
/**
305+
* Initialize and erase the selected flash slot
306+
*
307+
* @note This function may run for several seconds while erasing the currently
308+
* selected slot, depending on the size of the slot and flash speed.
309+
*/
310+
void init_selected_slot(void);
311+
312+
/**
313+
* Internal function to process buffered binary serial data
314+
*/
315+
void process_buffer(void);
316+
317+
/**
318+
* Schedule a serialized call to process_buffer on the event queue.
319+
*
320+
* @note this function has no effect if a write has already been scheduled
321+
*/
322+
void schedule_write(void) {
323+
if(!_scheduled_write) {
324+
_scheduled_write = _queue.call(
325+
mbed::callback(this, &DFUService::process_buffer));
326+
}
327+
}
328+
329+
/**
330+
* Set the status of the DFUService and notify any subscribed peers
331+
*/
332+
void set_status(uint8_t status);
333+
334+
/**
335+
* Set the DFU control characteristic and notify any subscribedd peers
336+
*/
337+
void set_dfu_ctrl(uint8_t ctrl);
338+
339+
/**
340+
* Sets the flow control pause bit and notifies any subscribed peers
341+
*
342+
* @note This will not have any effect if the bit is already set
343+
*/
344+
inline void set_fc_bit(void) {
345+
mbed::ScopedLock<PlatformMutex> lock(_mutex);
346+
if(!(_dfu_control & DFU_CTRL_FC_PAUSE_BIT)) {
347+
set_dfu_ctrl(_dfu_control | DFU_CTRL_FC_PAUSE_BIT);
348+
}
349+
}
350+
351+
/**
352+
* Clears the flow control pause bit and notifies any subscribed peers
353+
*
354+
* @note This will not have any effect if the bit is already cleared
355+
*/
356+
inline void clear_fc_bit(void) {
357+
mbed::ScopedLock<PlatformMutex> lock(_mutex);
358+
if(_dfu_control & DFU_CTRL_FC_PAUSE_BIT) {
359+
set_dfu_ctrl(_dfu_control & ~(DFU_CTRL_FC_PAUSE_BIT));
360+
}
361+
}
362+
363+
/**
364+
* Initiates a binary data stream buffer flush and sets the flow control bit
365+
*/
366+
inline void initiate_flush(void) {
367+
mbed::ScopedLock<PlatformMutex> lock(_mutex);
368+
/* Initiate a flush and set the FC pause bit */
369+
_flush_bin_buf = true;
370+
set_fc_bit();
371+
schedule_write();
372+
}
373+
374+
/**
375+
* Completes a binary data stream buffer flush and clears the flow control bit
376+
*/
377+
void flush_complete(void) {
378+
mbed::ScopedLock<PlatformMutex> lock(_mutex);
379+
_flush_bin_buf = false;
380+
clear_fc_bit();
381+
}
230382

231383
/** GattServer::EventHandler overrides */
232384
void onDataWritten(const GattWriteCallbackParams &params) override;
@@ -263,21 +415,31 @@ class DFUService : public ble::GattServer::EventHandler,
263415
/** Update status */
264416
uint8_t _status = 0;
265417

418+
/** Optional firmware revision and description strings */
419+
const char *_fw_rev_str;
420+
421+
/** Optional firmware characteristic user description descriptor */
422+
CharacteristicUserDescriptionDescriptor _fw_cudd;
423+
424+
/** GattCharacteristic constructor requires a list of pointers to descriptors... */
425+
GattAttribute *_fw_descs[1] = { (GattAttribute *) &_fw_cudd };
426+
266427
/** Gatt Characteristics */
267428
GattCharacteristic _slot_char;
268429
GattCharacteristic _offset_char;
269430
GattCharacteristic _rx_char;
270431
GattCharacteristic _dfu_ctrl_char;
271432
GattCharacteristic _status_char;
433+
GattCharacteristic _firmware_rev_char;
272434

273-
GattCharacteristic* _characteristics[5];
435+
GattCharacteristic *_characteristics[6];
274436

275437
GattService _dfu_service;
276438

277-
GattServer* _server;
439+
GattServer *_server;
278440

279441
/** Slot BlockDevices */
280-
mbed::BlockDevice *_slot_bds[MBED_CONF_BLE_DFU_SERVICE_MAX_SLOTS] = { 0 };
442+
mbed::BlockDevice *_slot_bds[MBED_CONF_BLE_DFU_SERVICE_MAX_SLOTS];
281443

282444
/** Application callbacks */
283445
mbed::Callback<GattAuthCallbackReply_t(ControlChange&)> _ctrl_req_cb = nullptr;
@@ -292,6 +454,14 @@ class DFUService : public ble::GattServer::EventHandler,
292454
/** Mutex */
293455
PlatformMutex _mutex;
294456

457+
events::EventQueue &_queue;
458+
459+
/** Queued event ID for scheduling flash writes */
460+
uint32_t _scheduled_write = 0;
461+
462+
/** Sequence ID for synchronization with client */
463+
uint8_t _seq_id = 0;
464+
295465
};
296466

297467
#endif //BLE_FEATURE_GATT_SERVER

0 commit comments

Comments
 (0)