From 68041c4710fc044c13f4107a74ae26badf611fd8 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 1 Sep 2015 11:42:26 +0100 Subject: works --- Makefile | 2 +- ble.c | 416 +++++++++++++++++++++++++++++++++++++++++++++-------------- ble.h | 3 + dfu.c | 115 +++++++++++++++-- dfu.h | 11 +- hexdump.c | 50 +++++++ nrfdfu.c | 5 +- prototypes.h | 35 +++-- 8 files changed, 504 insertions(+), 133 deletions(-) create mode 100644 hexdump.c diff --git a/Makefile b/Makefile index f4a387b..5566f0b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CSRCS=nrfdfu.c util.c zip.c ble.c manifest.c dfu.c +CSRCS=nrfdfu.c util.c zip.c ble.c manifest.c dfu.c hexdump.c BLUEZ_SRCS=bluez/att.c bluez/queue.c bluez/crypto.c bluez/util.c bluez/io-mainloop.c bluez/timeout-mainloop.c bluez/mainloop.c bluez/gatt-db.c bluez/uuid.c bluez/gatt-client.c bluez/gatt-helpers.c PROG=nrfdfu diff --git a/ble.c b/ble.c index 6e16adf..8e8c6c8 100644 --- a/ble.c +++ b/ble.c @@ -1,13 +1,61 @@ #include "project.h" +#include "dfu.h" #include "bluez/gatt-client.h" #include "bluez/mainloop.h" -static int verbose = 1; +static int verbose = 0; #define ATT_CID 4 -static bt_uuid_t fota_uuid,cp_uuid,data_uuid,cccd_uuid; +static bt_uuid_t fota_uuid, cp_uuid, data_uuid, cccd_uuid; + + +static const char * +ecode_to_string (uint8_t ecode) +{ + switch (ecode) + { + case BT_ATT_ERROR_INVALID_HANDLE: + return "Invalid Handle"; + case BT_ATT_ERROR_READ_NOT_PERMITTED: + return "Read Not Permitted"; + case BT_ATT_ERROR_WRITE_NOT_PERMITTED: + return "Write Not Permitted"; + case BT_ATT_ERROR_INVALID_PDU: + return "Invalid PDU"; + case BT_ATT_ERROR_AUTHENTICATION: + return "Authentication Required"; + case BT_ATT_ERROR_REQUEST_NOT_SUPPORTED: + return "Request Not Supported"; + case BT_ATT_ERROR_INVALID_OFFSET: + return "Invalid Offset"; + case BT_ATT_ERROR_AUTHORIZATION: + return "Authorization Required"; + case BT_ATT_ERROR_PREPARE_QUEUE_FULL: + return "Prepare Write Queue Full"; + case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND: + return "Attribute Not Found"; + case BT_ATT_ERROR_ATTRIBUTE_NOT_LONG: + return "Attribute Not Long"; + case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE: + return "Insuficient Encryption Key Size"; + case BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN: + return "Invalid Attribute value len"; + case BT_ATT_ERROR_UNLIKELY: + return "Unlikely Error"; + case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION: + return "Insufficient Encryption"; + case BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE: + return "Group type Not Supported"; + case BT_ATT_ERROR_INSUFFICIENT_RESOURCES: + return "Insufficient Resources"; + default: + return "Unknown error type"; + } +} + + @@ -133,20 +181,21 @@ l2cap_le_att_connect (bdaddr_t * src, bdaddr_t * dst, uint8_t dst_type, void -ble_close (BLE *ble) +ble_close (BLE * ble) { if (!ble) return; + mainloop_finish (); if (ble->notify_id) - bt_gatt_client_unregister_notify(ble->gatt, ble->notify_id); + bt_gatt_client_unregister_notify (ble->gatt, ble->notify_id); if (ble->gatt) - bt_gatt_client_unref(ble->gatt); + bt_gatt_client_unref (ble->gatt); - if (ble->db) - gatt_db_unref(ble->db); + if (ble->db) + gatt_db_unref (ble->db); if (ble->att) bt_att_unref (ble->att); @@ -155,6 +204,7 @@ ble_close (BLE *ble) free (ble); + } @@ -166,81 +216,84 @@ att_disconnect_cb (int err, void *user_data) mainloop_exit_failure (); } -static void print_uuid(const bt_uuid_t *uuid) +static void +print_uuid (const bt_uuid_t * uuid) { - char uuid_str[MAX_LEN_UUID_STR]; - bt_uuid_t uuid128; + char uuid_str[MAX_LEN_UUID_STR]; + bt_uuid_t uuid128; - bt_uuid_to_uuid128(uuid, &uuid128); - bt_uuid_to_string(&uuid128, uuid_str, sizeof(uuid_str)); + bt_uuid_to_uuid128 (uuid, &uuid128); + bt_uuid_to_string (&uuid128, uuid_str, sizeof (uuid_str)); - printf("%s\n", uuid_str); + printf ("%s\n", uuid_str); } -static void scan_desc(struct gatt_db_attribute *attr, void *user_data) +static void +scan_desc (struct gatt_db_attribute *attr, void *user_data) { -BLE *ble=user_data; -uint16_t handle=gatt_db_attribute_get_handle(attr); -const bt_uuid_t *uuid=gatt_db_attribute_get_type(attr); + BLE *ble = user_data; + uint16_t handle = gatt_db_attribute_get_handle (attr); + const bt_uuid_t *uuid = gatt_db_attribute_get_type (attr); - printf("\t\tdesc - handle: 0x%04x, uuid: ",handle); - print_uuid(uuid); + printf ("\t\tdesc - handle: 0x%04x, uuid: ", handle); + print_uuid (uuid); - if (!bt_uuid_cmp(uuid,&cccd_uuid)) - ble->cccd_handle=handle; + if (!bt_uuid_cmp (uuid, &cccd_uuid)) + ble->cccd_handle = handle; } -static void scan_chrc(struct gatt_db_attribute *attr, void *user_data) +static void +scan_chrc (struct gatt_db_attribute *attr, void *user_data) { - BLE *ble=user_data; - uint16_t handle, value_handle; - uint8_t properties; - bt_uuid_t uuid; + BLE *ble = user_data; + uint16_t handle, value_handle; + uint8_t properties; + bt_uuid_t uuid; - if (!gatt_db_attribute_get_char_data(attr, &handle, - &value_handle, - &properties, - &uuid)) - return; + if (!gatt_db_attribute_get_char_data (attr, &handle, + &value_handle, &properties, &uuid)) + return; - printf("\tchar - start: 0x%04x, value: 0x%04x, props: 0x%02x, uuid: ", - handle, value_handle, properties); + printf ("\tchar - start: 0x%04x, value: 0x%04x, props: 0x%02x, uuid: ", + handle, value_handle, properties); - print_uuid(&uuid); + print_uuid (&uuid); - if (!bt_uuid_cmp(&uuid,&data_uuid)) - ble->data_handle=value_handle; + if (!bt_uuid_cmp (&uuid, &data_uuid)) + ble->data_handle = value_handle; - if (!bt_uuid_cmp(&uuid,&cp_uuid)) { - ble->cp_handle=value_handle; - gatt_db_service_foreach_desc(attr, scan_desc, ble); - } + if (!bt_uuid_cmp (&uuid, &cp_uuid)) + { + ble->cp_handle = value_handle; + gatt_db_service_foreach_desc (attr, scan_desc, ble); + } } -static void scan_service(struct gatt_db_attribute *attr, void *user_data) +static void +scan_service (struct gatt_db_attribute *attr, void *user_data) { - BLE *ble = user_data; - uint16_t start, end; - bool primary; - bt_uuid_t uuid; + BLE *ble = user_data; + uint16_t start, end; + bool primary; + bt_uuid_t uuid; - if (!gatt_db_attribute_get_service_data(attr, &start, &end, &primary, - &uuid)) - return; + if (!gatt_db_attribute_get_service_data (attr, &start, &end, &primary, + &uuid)) + return; - gatt_db_service_foreach_char(attr, scan_chrc, ble); + gatt_db_service_foreach_char (attr, scan_chrc, ble); - printf("\n"); + printf ("\n"); } @@ -261,27 +314,29 @@ ready_cb (bool success, uint8_t att_ecode, void *user_data) printf ("GATT discovery procedures complete\n"); - gatt_db_foreach_service(ble->db, &fota_uuid, scan_service, ble); + gatt_db_foreach_service (ble->db, &fota_uuid, scan_service, ble); + + printf ("Handles:\n\tdata: 0x%04x\n\tcp : 0x%04x\n\tcccd: 0x%04x\n", + ble->data_handle, ble->cp_handle, ble->cccd_handle); - printf("Handles:\n\tdata: 0x%04x\n\tcp : 0x%04x\n\tcccd: 0x%04x\n", - ble->data_handle,ble->cp_handle,ble->cccd_handle); + if (ble->cccd_handle && ble->cp_handle && ble->data_handle) + { + mainloop_exit_success (); + return; + } - if (ble->cccd_handle && ble->cp_handle && ble->data_handle) { - mainloop_exit_success (); - return; - } - - mainloop_exit_failure(); + mainloop_exit_failure (); } -void ble_init(void) +void +ble_init (void) { - bt_string_to_uuid(&fota_uuid, "00001530-1212-efde-1523-785feabcd123"); - bt_string_to_uuid(&cp_uuid, "00001531-1212-efde-1523-785feabcd123"); - bt_string_to_uuid(&data_uuid, "00001532-1212-efde-1523-785feabcd123"); - bt_string_to_uuid(&cccd_uuid, "00002902-0000-1000-8000-00805f9b34fb"); + bt_string_to_uuid (&fota_uuid, "00001530-1212-efde-1523-785feabcd123"); + bt_string_to_uuid (&cp_uuid, "00001531-1212-efde-1523-785feabcd123"); + bt_string_to_uuid (&data_uuid, "00001532-1212-efde-1523-785feabcd123"); + bt_string_to_uuid (&cccd_uuid, "00002902-0000-1000-8000-00805f9b34fb"); mainloop_init (); } @@ -294,6 +349,9 @@ ble_open (const char *bdaddr) ble = xmalloc (sizeof (*ble)); memset (ble, 0, sizeof (*ble)); + ble->notify_waiting_for_op = -1; + ble->notify_code = -1; + ble->sec = BT_SECURITY_LOW; ble->dst_type = BDADDR_LE_RANDOM; bacpy (&ble->src_addr, BDADDR_ANY); @@ -364,59 +422,223 @@ ble_open (const char *bdaddr) return NULL; } -static void notify_cb(uint16_t value_handle, const uint8_t *value, - uint16_t length, void *user_data) +static void +notify_cb (uint16_t value_handle, const uint8_t * value, + uint16_t length, void *user_data) { - int i; + int i; + BLE *ble = user_data; - printf("Handle Value Not/Ind: 0x%04x - ", value_handle); + printf ("Handle Value Not/Ind: 0x%04x - ", value_handle); - if (length == 0) { - printf("(0 bytes)\n"); - return; - } + if (length == 0) + { + printf ("(0 bytes)\n"); + return; + } + + printf ("(%u bytes): ", length); + + for (i = 0; i < length; i++) + printf ("%02x ", value[i]); + + printf ("\n"); + + if (value_handle != ble->cp_handle) + return; + if (length != 3) + return; + + if (value[0] != OP_CODE_RESPONSE) + return; + + if (value[1] != ble->notify_waiting_for_op) + return; - printf("(%u bytes): ", length); + ble->notify_code = value[2]; - for (i = 0; i < length; i++) - printf("%02x ", value[i]); + printf ("Got response => 0x%02x\n", value[2]); + mainloop_quit (); - printf("\n"); } -static void register_notify_cb(uint16_t att_ecode, void *user_data) +static void +register_notify_cb (uint16_t att_ecode, void *user_data) { - if (att_ecode) { - printf("Failed to register notify handler " - "- error code: 0x%02x\n", att_ecode); - mainloop_exit_failure(); - return; - } + if (att_ecode) + { + printf ("Failed to register notify handler " + "- error code: 0x%02x\n", att_ecode); + mainloop_exit_failure (); + return; + } + + printf ("Registered notify handler!\n"); + mainloop_exit_success (); +} + + +int +ble_register_notify (BLE * ble) +{ + + + + if (!bt_gatt_client_is_ready (ble->gatt)) + { + printf ("GATT client not initialized\n"); + return EXIT_FAILURE; + } + + ble->notify_id = bt_gatt_client_register_notify (ble->gatt, ble->cp_handle, + register_notify_cb, + notify_cb, ble, NULL); + if (!ble->notify_id) + { + printf ("Failed to register notify handler\n"); + return EXIT_FAILURE; + } + + printf ("requesting notify\n"); + + return mainloop_run (); +} + +static void +write_cb (bool success, uint8_t att_ecode, void *user_data) +{ +//BLE *ble=user_data; + + if (success) + { + mainloop_exit_success (); + } + else + { + printf ("Write failed: %s (0x%02x)\n", + ecode_to_string (att_ecode), att_ecode); + mainloop_exit_failure (); + } +} + + +int +ble_send_cp (BLE * ble, uint8_t * buf, size_t len) +{ + printf ("Sending control:\n"); + hexdump (buf, len); - printf("Registered notify handler!\n"); - mainloop_exit_success(); + if (!bt_gatt_client_write_value (ble->gatt, ble->cp_handle, buf, len, + write_cb, ble, NULL)) + { + printf ("Failed to initiate write procedure\n"); + return EXIT_FAILURE; + } + + return mainloop_run (); } -int ble_register_notify(BLE *ble) { +#if 0 +int +ble_send_data (BLE * ble, uint8_t * buf, size_t len) +{ + size_t mtu = 16, tx; + + printf ("Sending data:\n"); + + + hexdump (buf, (len < 64) ? len : 64); + + while (len) + { + + printf ("%u bytes left\n", (unsigned) len); + tx = (len > mtu) ? mtu : len; - if (!bt_gatt_client_is_ready(ble->gatt)) { - printf("GATT client not initialized\n"); - return EXIT_FAILURE; + if (!bt_gatt_client_write_value (ble->gatt, ble->data_handle, buf, tx, + write_cb, ble, NULL)) + { + printf ("Failed to initiate write procedure\n"); + return EXIT_FAILURE; } - ble->notify_id = bt_gatt_client_register_notify(ble->gatt, ble->cp_handle, - register_notify_cb, - notify_cb, NULL, NULL); - if (!ble->notify_id) { - printf("Failed to register notify handler\n"); - return EXIT_FAILURE; + if (mainloop_run () == EXIT_FAILURE) + return EXIT_FAILURE; + + len -= tx; + buf += tx; + } + + return EXIT_SUCCESS; +} +#else +int +ble_send_data (BLE * ble, uint8_t * buf, size_t len) +{ + if (!bt_gatt_client_write_value (ble->gatt, ble->data_handle, buf, len, + write_cb, ble, NULL)) + { + printf ("Failed to initiate write procedure\n"); + return EXIT_FAILURE; + } + + return mainloop_run (); +} +#endif + + +int +ble_send_data_noresp (BLE * ble, uint8_t * buf, size_t len) +{ + size_t mtu = 16, tx; + + printf ("Sending data:\n"); + + + hexdump (buf, (len < 64) ? len : 64); + + + while (len) + { + + printf ("%u bytes left\n", (unsigned) len); + + tx = (len > mtu) ? mtu : len; + + if (!bt_gatt_client_write_without_response + (ble->gatt, ble->data_handle, false, buf, tx)) + { + printf ("Failed to initiate write procedure\n"); + return EXIT_FAILURE; } - printf("requesting notify\n"); + len -= tx; + buf += tx; + } - return mainloop_run(); + return EXIT_SUCCESS; } + +void +ble_wait_setup (BLE * ble, uint8_t op) +{ + ble->notify_waiting_for_op = op; + ble->notify_code = -1; +} + + +int +ble_wait_run (BLE * ble) +{ + mainloop_run (); + + ble->notify_waiting_for_op = -1; + + printf ("Returning response 0x%02x\n", ble->notify_code); + + return ble->notify_code; +} diff --git a/ble.h b/ble.h index 5073cd6..b59bf90 100644 --- a/ble.h +++ b/ble.h @@ -17,6 +17,9 @@ struct ble uint16_t cp_handle; uint16_t cccd_handle; uint16_t data_handle; + + int notify_waiting_for_op; + int notify_code; }; typedef struct ble BLE; diff --git a/dfu.c b/dfu.c index be1f952..6dd835e 100644 --- a/dfu.c +++ b/dfu.c @@ -1,39 +1,126 @@ #include "project.h" +#include "dfu.h" void dfu (const char *bdaddr, const char *type, const char *version, uint8_t * dat, size_t dat_sz, uint8_t * bin, size_t bin_sz) { - BLE *b; - uint8_t buf[32]; + BLE *b; + uint8_t buf[32]; + uint32_t u32; + uint16_t u16; + if (strcmp (type, "application")) + { + fprintf (stderr, "only know how to flash applications\n"); + exit (EXIT_FAILURE); + } - ble_init(); + ble_init (); + do + { + b = ble_open (bdaddr); + if (!b) + break; - do { + if (ble_register_notify (b)) + break; - b=ble_open (bdaddr); - - if (!b) - break; + buf[0] = OP_CODE_START_DFU; + buf[1] = DFU_UPDATE_APP; /*bit field */ - if (ble_register_notify(b)) break; + ble_wait_setup (b, OP_CODE_START_DFU); - ble_send_cp( + if (ble_send_cp (b, buf, 2)) + break; + + /*4 bytes sd size, 4 bytes bl size, 4 bytes app size */ + + memset (buf, 0, 12); + u32 = bin_sz; + memcpy (&buf[8], &u32, 4); + + if (ble_send_data (b, buf, 12)) + break; + + if (ble_wait_run (b) != BLE_DFU_RESP_VAL_SUCCESS) + break; + + buf[0] = OP_CODE_RECEIVE_INIT; + buf[1] = DFU_INIT_RX; + + if (ble_send_cp (b, buf, 2)) + break; + + ble_wait_setup (b, OP_CODE_RECEIVE_INIT); + if (ble_send_data (b, dat, dat_sz)) + break; + + buf[0] = OP_CODE_RECEIVE_INIT; + buf[1] = DFU_INIT_COMPLETE; + if (ble_send_cp (b, buf, 2)) + break; + + if (ble_wait_run (b) != BLE_DFU_RESP_VAL_SUCCESS) + break; + + +// ble_wait_setup(b,OP_CODE_PKT_RCPT_NOTIF_REQ); + buf[0] = OP_CODE_PKT_RCPT_NOTIF_REQ; + u16 = 0x10; + memcpy (&buf[1], &u16, 2); + + if (ble_send_cp (b, buf, 3)) + break; + +// if (ble_wait_run(b)!=BLE_DFU_RESP_VAL_SUCCESS) +// break; + + + + ble_wait_setup (b, OP_CODE_RECEIVE_FW); + + buf[0] = OP_CODE_RECEIVE_FW; + if (ble_send_cp (b, buf, 1)) + break; + + if (ble_send_data (b, bin, bin_sz)) + break; + + if (ble_wait_run (b) != BLE_DFU_RESP_VAL_SUCCESS) + break; + + ble_wait_setup (b, OP_CODE_VALIDATE); + buf[0] = OP_CODE_VALIDATE; + if (ble_send_cp (b, buf, 1)) + break; + if (ble_wait_run (b) != BLE_DFU_RESP_VAL_SUCCESS) + break; + + buf[0] = OP_CODE_ACTIVATE_N_RESET; + if (ble_send_cp (b, buf, 1)) + break; + + ble_close (b); + return; - ble_close (b); - return; + } + while (0); -} while (0); + if (b) + { + buf[0] = OP_CODE_SYS_RESET; + ble_send_cp (b, buf, 1); + } ble_close (b); - exit(EXIT_FAILURE); + exit (EXIT_FAILURE); } diff --git a/dfu.h b/dfu.h index f85bc62..4ed16e0 100644 --- a/dfu.h +++ b/dfu.h @@ -30,10 +30,9 @@ enum OP_CODE_PKT_RCPT_NOTIF = 17 /**< Value of the Op code field for 'Packets Receipt Notification'.*/ }; -enum { - DFU_MODE_SOFTDEVICE = 1, - DFU_MODE_BOOTLOADER = 2, - DFU_MODE_SD_BL = 3, - DFU_MODE_APPLICATION = 4 -}; +#define DFU_UPDATE_SD 0x01 /**< Bit field indicating update of SoftDevice is ongoing. */ +#define DFU_UPDATE_BL 0x02 /**< Bit field indicating update of bootloader is ongoing. */ +#define DFU_UPDATE_APP 0x04 /**< Bit field indicating update of application is ongoing. */ +#define DFU_INIT_RX 0x00 /**< Op Code identifies for receiving init packet. */ +#define DFU_INIT_COMPLETE 0x01 /**< Op Code identifies for transmission complete of init packet. */ diff --git a/hexdump.c b/hexdump.c new file mode 100644 index 0000000..e664d3c --- /dev/null +++ b/hexdump.c @@ -0,0 +1,50 @@ +#include "project.h" + +void +hexdump (void *_d, int len) +{ + uint8_t *d = (uint8_t *) _d; + int i, j, k; + int e; + + if (!d || len < 0) + return; + + e = len + 15; + e &= ~15; + + for (i = 0; i < e; i += 16) + { + printf (" %05x:", i); + for (j = 0; j < 16; ++j) + { + k = i + j; + + if (k < len) + printf (" %02x", d[k]); + else + printf (" "); + + if (j == 7) + printf (" "); + } + + printf (" "); + for (j = 0; j < 16; ++j) + { + k = i + j; + if (k < len) + { + uint8_t c = d[k]; + if (c < 33) + c = '.'; + if (c > 126) + c = '.'; + printf ("%c", c); + } + if (j == 7) + printf (" "); + } + printf ("\n"); + } +} diff --git a/nrfdfu.c b/nrfdfu.c index ab58464..3f9316c 100644 --- a/nrfdfu.c +++ b/nrfdfu.c @@ -65,11 +65,12 @@ main (int argc, char *argv[]) bin_size = read_file_from_zip (zip, m->bin_file, &bin); - printf ("%u bytes init_data, %u bytes firmware\n",(unsigned) dat_size, (unsigned) bin_size); + printf ("%u bytes init_data, %u bytes firmware\n", (unsigned) dat_size, + (unsigned) bin_size); dfu (bdaddr, m->type, m->dfu_version, dat, dat_size, bin, bin_size); -return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/prototypes.h b/prototypes.h index ab6773c..570f4f7 100644 --- a/prototypes.h +++ b/prototypes.h @@ -1,19 +1,28 @@ /* nrfdfu.c */ -extern int main(int argc, char *argv[]); +extern int main (int argc, char *argv[]); /* util.c */ -extern void *xmalloc(size_t s); -extern void *xrealloc(void *p, size_t s); +extern void *xmalloc (size_t s); +extern void *xrealloc (void *p, size_t s); /* zip.c */ -extern void fatal_zip(struct zip *zip); -extern struct zip *open_zip(const char *fn); -extern size_t read_file_from_zip(struct zip *zip, const char *fn, void *_buf); +extern void fatal_zip (struct zip *zip); +extern struct zip *open_zip (const char *fn); +extern size_t read_file_from_zip (struct zip *zip, const char *fn, + void *_buf); /* ble.c */ -extern void ble_close(BLE *ble); -extern void ble_init(void); -extern BLE *ble_open(const char *bdaddr); -extern int ble_register_notify(BLE *ble); +extern void ble_close (BLE * ble); +extern void ble_init (void); +extern BLE *ble_open (const char *bdaddr); +extern int ble_register_notify (BLE * ble); +extern int ble_send_cp (BLE * ble, uint8_t * buf, size_t len); +extern int ble_send_data (BLE * ble, uint8_t * buf, size_t len); +extern void ble_wait_setup (BLE * ble, uint8_t op); +extern int ble_wait_run (BLE * ble); /* manifest.c */ -extern json_object *_json_object_object_get(json_object *obj, const char *name); -extern struct manifest *parse_manifest(const char *str); +extern json_object *_json_object_object_get (json_object * obj, + const char *name); +extern struct manifest *parse_manifest (const char *str); /* dfu.c */ -extern void dfu(const char *bdaddr, const char *type, const char *version, uint8_t *dat, size_t dat_sz, uint8_t *bin, size_t bin_sz); +extern void dfu (const char *bdaddr, const char *type, const char *version, + uint8_t * dat, size_t dat_sz, uint8_t * bin, size_t bin_sz); +/* hexdump.c */ +extern void hexdump (void *_d, int len); -- cgit v1.2.3