Skip to content

Commit 4442c36

Browse files
committed
Bug fixes and more verbose trace messages
1 parent 673d8d9 commit 4442c36

File tree

2 files changed

+88
-44
lines changed

2 files changed

+88
-44
lines changed

services/inc/DFUService.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,6 @@ class DFUService : public ble::GattServer::EventHandler,
238238

239239
public:
240240

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-
247241
/**
248242
* Instantiate a DFUService instance
249243
* @param[in] bd BlockDevice to use for storing update candidates in slot 0
@@ -383,6 +377,10 @@ class DFUService : public ble::GattServer::EventHandler,
383377
/** GattServer::EventHandler overrides */
384378
void onDataWritten(const GattWriteCallbackParams &params) override;
385379

380+
void onUpdatesEnabled(const GattUpdatesEnabledCallbackParams &params) override;
381+
382+
void onUpdatesDisabled(const GattUpdatesDisabledCallbackParams &params) override;
383+
386384
/** Gap::EventHandler overrides */
387385
void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override;
388386

services/src/DFUService/DFUService.cpp

Lines changed: 84 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,19 @@ DFUService::DFUService(mbed::BlockDevice *bd, events::EventQueue &queue, const c
7575
_dfu_ctrl_char(uuids::DFUService::ControlUUID, &_dfu_control, 1, 1,
7676
(GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |
7777
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
78-
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY |
79-
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE),
80-
nullptr, 0, false),
78+
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)),
8179
_status_char(uuids::DFUService::StatusUUID, &_status, 1, 1,
8280
(GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |
83-
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY |
84-
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE),
85-
nullptr, 0, false),
81+
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)),
8682
/* FW Rev Char will be dropped by GattServer if val in nullptr, len is 0, and it's readable */
8783
_firmware_rev_char(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR,
8884
(uint8_t *) fw_rev,
8985
(fw_rev != nullptr) ? strlen(fw_rev) : 0, /* Min length */
9086
(fw_rev != nullptr) ? strlen(fw_rev) : 0, /* Max length */
9187
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ,
92-
_fw_descs, 1, true),
88+
_fw_descs,
89+
(dev_desc != nullptr) ? 1 : 0,
90+
true),
9391
_dfu_service(uuids::DFUService::BaseUUID,
9492
_characteristics,
9593
(fw_rev != nullptr) ?
@@ -156,11 +154,30 @@ void DFUService::onDataWritten(const GattWriteCallbackParams &params) {
156154
}
157155
}
158156

157+
void DFUService::onUpdatesEnabled(const GattUpdatesEnabledCallbackParams &params) {
158+
if(params.attHandle == _dfu_ctrl_char.getValueHandle()) {
159+
TRACE_IF(tr_debug("Updates enabled for control characteristic"));
160+
} else if(params.attHandle == _status_char.getValueHandle()) {
161+
TRACE_IF(tr_debug("Updates enabled for status characteristic"))
162+
}
163+
}
164+
165+
void DFUService::onUpdatesDisabled(const GattUpdatesDisabledCallbackParams &params) {
166+
if(params.attHandle == _dfu_ctrl_char.getValueHandle()) {
167+
TRACE_IF(tr_debug("Updates disabled for control characteristic"));
168+
} else if(params.attHandle == _status_char.getValueHandle()) {
169+
TRACE_IF(tr_debug("Updates disabled for status characteristic"))
170+
}
171+
}
172+
173+
159174
void DFUService::set_status(uint8_t status) {
175+
TRACE_IF(tr_debug("notifying status: %d", status));
160176
_server->write(_status_char.getValueHandle(), &status, 1, false);
161177
}
162178

163179
void DFUService::set_dfu_ctrl(uint8_t bits) {
180+
TRACE_IF(tr_debug("notifying ctrl: %d", bits));
164181
_server->write(_dfu_ctrl_char.getValueHandle(), &bits, 1, false);
165182
}
166183

@@ -189,13 +206,16 @@ void DFUService::on_slot_write_request(GattWriteAuthCallbackParams *params) {
189206
}
190207

191208
void DFUService::on_slot_written(uint8_t new_slot) {
192-
TRACE_IF(tr_debug("slot written: %d", new_slot));
193-
if(_slot_bds[new_slot] != nullptr) {
194-
mbed::ScopedLock<PlatformMutex> lock(_mutex);
195-
_slot_bds[_selected_slot]->deinit();
196-
_selected_slot = new_slot;
197-
/* Initialize and erase the selected slot */
198-
_queue.call(mbed::callback(this, &DFUService::init_selected_slot));
209+
/* Ignore if selecting the same slot */
210+
if(_selected_slot != new_slot) {
211+
TRACE_IF(tr_debug("slot written: %d", new_slot));
212+
if(_slot_bds[new_slot] != nullptr) {
213+
mbed::ScopedLock<PlatformMutex> lock(_mutex);
214+
_slot_bds[_selected_slot]->deinit();
215+
_selected_slot = new_slot;
216+
/* Initialize and erase the selected slot */
217+
_queue.call(mbed::callback(this, &DFUService::init_selected_slot));
218+
}
199219
}
200220
}
201221

@@ -220,26 +240,31 @@ void DFUService::on_offset_written(uint32_t new_offset) {
220240
void DFUService::on_bds_written(mbed::Span<const uint8_t> data) {
221241

222242
uint8_t seq_id = *data.data();
223-
/* 7-bit sequence ID rolls over at 127 */
224-
uint8_t expected_id = ((_seq_id + 1) & 0x7F);
225-
226243
TRACE_IF(tr_debug("bds written, sequence num: %d, %i bytes in payload", seq_id, data.size()-1));
227244

245+
/* Ignore 0-length writes */
246+
if((data.size() - 1) == 0) {
247+
TRACE_IF(tr_warn("zero-length packet written, ignoring"));
248+
return;
249+
}
250+
228251
/* Writes to the bds characteristic will be ignored if the flow control bit is set */
229252
if(!_flush_bin_buf && !(_dfu_control & DFU_CTRL_FC_PAUSE_BIT)) {
230253

231254
/* Check sequence number and make sure it's what we expected */
232-
if(seq_id == expected_id) {
233-
_seq_id = expected_id;
255+
if(seq_id == _seq_id) {
256+
/* 7-bit sequence ID rolls over at 127 */
257+
_seq_id++;
258+
_seq_id &= 0x7F;
234259
_bin_stream_buf.push(data.subspan(1));
235260
if(_bin_stream_buf.size() >= MBED_CONF_BLE_DFU_SERVICE_RX_FC_PAUSE_THRESHOLD) {
236261
set_fc_bit();
237262
}
238263
schedule_write();
239264
} else {
240265
/* Otherwise, notify the client that the expected sequence ID did not match using the status characteristic */
241-
TRACE_IF(tr_warn("sequence number does not match; expected: %d, actual: %d", expected_id, seq_id));
242-
set_status(DFU_STATE_SYNC_LOSS_BIT | expected_id);
266+
TRACE_IF(tr_warn("sequence number does not match; expected: %d, actual: %d", _seq_id, seq_id));
267+
set_status(DFU_STATE_SYNC_LOSS_BIT | _seq_id);
243268
}
244269
}
245270
}
@@ -260,12 +285,6 @@ void DFUService::on_dfu_ctrl_write_request(
260285
/* Forward request to the application */
261286
params->authorizationReply = _ctrl_req_cb(change);
262287
TRACE_IF(tr_debug("dfu_ctrl write request: accepted (by application)"));
263-
264-
if(params->authorizationReply == AUTH_CALLBACK_REPLY_SUCCESS) {
265-
/* If DFU is being enabled, clear the currently-selected update slot */
266-
_queue.call(mbed::callback(this, &DFUService::init_selected_slot));
267-
}
268-
269288
} else {
270289
/* If no application handler, accept by default */
271290
TRACE_IF(tr_debug("dfu_ctrl write request: accepted"));
@@ -276,55 +295,78 @@ void DFUService::on_dfu_ctrl_write_request(
276295
void DFUService::on_dfu_ctrl_written(uint8_t new_ctrl) {
277296
TRACE_IF(tr_debug("dfu_ctrl written: %d", new_ctrl));
278297
mbed::ScopedLock<PlatformMutex> lock(_mutex);
298+
ControlChange change(*this, new_ctrl);
279299
/* Call application handler for control updates, if available */
280300
if(_ctrl_update_cb) {
281-
ControlChange change(*this, new_ctrl);
282301
_ctrl_update_cb(change);
302+
}
283303

284-
if(change.get_changed_bits() & DFU_CTRL_ENABLE_BIT) {
285-
TRACE_IF(tr_debug("dfu mode enabled"));
286-
}
304+
if(change.get_changed_bits() & DFU_CTRL_ENABLE_BIT) {
305+
TRACE_IF(tr_debug("dfu mode %s", (change.value() & DFU_CTRL_ENABLE_BIT) ? "enabled" : "aborted"));
287306

288-
if(change.get_changed_bits() & DFU_CTRL_DELTA_MODE_EN_BIT) {
289-
TRACE_IF(tr_debug("delta mode enabled"));
307+
if(change.value() & DFU_CTRL_ENABLE_BIT) {
308+
/* If DFU is being enabled, clear the currently-selected update slot */
309+
_queue.call(mbed::callback(this, &DFUService::init_selected_slot));
290310
}
311+
}
291312

292-
if(change.get_changed_bits() & DFU_CTRL_COMMIT_BIT) {
293-
TRACE_IF(tr_debug("dfu commit"));
294-
}
313+
if(change.get_changed_bits() & DFU_CTRL_DELTA_MODE_EN_BIT) {
314+
TRACE_IF(tr_debug("delta mode %s", (change.value() & DFU_CTRL_DELTA_MODE_EN_BIT) ? "enabled" : "disabled"));
315+
}
316+
317+
if(change.get_changed_bits() & DFU_CTRL_COMMIT_BIT) {
318+
TRACE_IF(tr_debug("dfu commit"));
295319
}
320+
296321
_dfu_control = new_ctrl;
297322
}
298323

299324
void DFUService::init_selected_slot(void) {
300325
mbed::ScopedLock<PlatformMutex> lock(_mutex); // TODO mutex lock necessary here?
326+
TRACE_IF(tr_debug("initializing slot %d", _selected_slot))
301327
mbed::BlockDevice* slot = _slot_bds[_selected_slot];
302328
slot->init();
303329
slot->erase(0, slot->size());
330+
// Send a neutral notification of the status characteristic to tell the client we're ready
331+
set_status(DFU_STATE_IDLE);
304332
}
305333

306334

307335
void DFUService::process_buffer(void) {
336+
337+
/* TODO Rework the whole writing buffered data stuff */
338+
308339
mbed::BlockDevice* slot = _slot_bds[_selected_slot];
309340
/* Attempt to write as many multiples of program size as possible at once */
310341

311342
/**
312343
* TODO is there a better way to do this? Without dynamic allocation, we would
313344
* have to program byte-by-byte. This would likely be a significant hit in speed.
314345
*/
315-
bd_size_t write_size = (_bin_stream_buf.size() / slot->get_program_size());
346+
bd_size_t write_size = (_bin_stream_buf.size() / slot->get_program_size()) * slot->get_program_size();
347+
TRACE_IF(tr_debug("processing buffer: %lu => %lu",
348+
_bin_stream_buf.size(),
349+
write_size));
350+
if(write_size == 0) {
351+
/* Skip 0-length writes */
352+
_scheduled_write = 0;
353+
return;
354+
}
316355
uint8_t *temp_buf = new uint8_t[write_size];
317356
_bin_stream_buf.pop(temp_buf, write_size);
318357
int result = slot->program(temp_buf, _current_offset, write_size);
319358
if(result) {
359+
TRACE_IF(tr_err("programming memory error: %d", result));
320360
set_status(DFU_STATE_FLASH_ERROR);
321361
}
322362
_current_offset += write_size;
323363
delete[] temp_buf;
324364

325365
/* If the buffer isn't empty and a flush should be performed, pad the write */
326366
if(_bin_stream_buf.size() && _flush_bin_buf) {
327-
367+
TRACE_IF(tr_debug("flushing buffer: %lu => %lu",
368+
_bin_stream_buf.size(),
369+
write_size));
328370
write_size = slot->get_program_size();
329371
temp_buf = new uint8_t[write_size];
330372
/* Pad the write buffer with the BD's erase value */
@@ -341,6 +383,10 @@ void DFUService::process_buffer(void) {
341383
delete[] temp_buf;
342384
flush_complete();
343385
}
386+
387+
_scheduled_write = 0;
388+
schedule_write();
389+
344390
}
345391

346392

0 commit comments

Comments
 (0)