diff options
author | root <root@lamia.panaceas.james.local> | 2015-09-01 00:41:49 +0100 |
---|---|---|
committer | root <root@lamia.panaceas.james.local> | 2015-09-01 00:41:49 +0100 |
commit | 475922ce345bb0443cf4fdef00efa86676a1bf62 (patch) | |
tree | 89e3eb13232da02bddfeffaff8588765c403b71f | |
download | nrfdfu-475922ce345bb0443cf4fdef00efa86676a1bf62.tar.gz nrfdfu-475922ce345bb0443cf4fdef00efa86676a1bf62.tar.bz2 nrfdfu-475922ce345bb0443cf4fdef00efa86676a1bf62.zip |
fish
-rw-r--r-- | Makefile | 35 | ||||
-rw-r--r-- | ble.c | 147 | ||||
-rw-r--r-- | ble.h | 13 | ||||
-rw-r--r-- | dfu.c | 13 | ||||
-rw-r--r-- | dfu.h | 33 | ||||
-rw-r--r-- | manifest.c | 73 | ||||
-rw-r--r-- | manifest.h | 7 | ||||
-rw-r--r-- | nrfdfu.c | 74 | ||||
-rw-r--r-- | project.h | 25 | ||||
-rw-r--r-- | prototypes.h | 16 | ||||
-rw-r--r-- | util.c | 18 | ||||
-rw-r--r-- | zip.c | 83 |
12 files changed, 537 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..08587b8 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +CSRCS=nrfdfu.c util.c zip.c ble.c manifest.c dfu.c + +PROG=nrfdfu + +OPT=-g + + +CPROTO=cproto +ZIP_INCLUDES=$(shell pkg-config --cflags libzip) +ZIP_LIBS=$(shell pkg-config --libs libzip) +JSON_C_INCLUDES=$(shell pkg-config --cflags json-c) +JSON_C_LIBS=$(shell pkg-config --libs json-c) +BLUEZ_INCLUDES=$(shell pkg-config --cflags bluez) +BLUEZ_LIBS=$(shell pkg-config --libs bluez) + + +INCLUDES=${ZIP_INCLUDES} ${JSON_C_INCLUDES} ${BLUEZ_INCLUDES} +LIBS=${ZIP_LIBS} ${JSON_C_LIBS} ${BLUEZ_LIBS} +CPPFLAGS=${DEFINES} ${INCLUDES} +CFLAGS=${OPT} +OBJS=${CSRCS:%.c=%.o} + + +all: ${PROG} + +${PROG}:${OBJS} + ${CC} ${CFLAGS} ${LDFLAGS} -o ${PROG} ${OBJS} ${LIBS} + +protos: + echo > prototypes.h + ${CPROTO} ${CPPFLAGS} -e -v ${CSRCS} > prototypes.new + mv prototypes.new prototypes.h + +clean: + /bin/rm -f ${OBJS} @@ -0,0 +1,147 @@ +#include "project.h" + +static int verbose = 1; + +#define ATT_CID 4 + + + +static int +l2cap_le_att_connect (bdaddr_t * src, bdaddr_t * dst, uint8_t dst_type, + int sec) +{ + int sock; + struct sockaddr_l2 srcaddr, dstaddr; + struct bt_security btsec; + + if (verbose) + { + char srcaddr_str[18], dstaddr_str[18]; + + ba2str (src, srcaddr_str); + ba2str (dst, dstaddr_str); + + printf ("btgatt-client: Opening L2CAP LE connection on ATT " + "channel:\n\t src: %s\n\tdest: %s\n", srcaddr_str, dstaddr_str); + } + + sock = socket (PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (sock < 0) + { + perror ("Failed to create L2CAP socket"); + return -1; + } + + /* Set up source address */ + memset (&srcaddr, 0, sizeof (srcaddr)); + srcaddr.l2_family = AF_BLUETOOTH; + srcaddr.l2_cid = htobs (ATT_CID); + srcaddr.l2_bdaddr_type = 0; + bacpy (&srcaddr.l2_bdaddr, src); + + if (bind (sock, (struct sockaddr *) &srcaddr, sizeof (srcaddr)) < 0) + { + perror ("Failed to bind L2CAP socket"); + close (sock); + return -1; + } + + /* Set the security level */ + memset (&btsec, 0, sizeof (btsec)); + btsec.level = sec; + if (setsockopt (sock, SOL_BLUETOOTH, BT_SECURITY, &btsec, + sizeof (btsec)) != 0) + { + fprintf (stderr, "Failed to set L2CAP security level\n"); + close (sock); + return -1; + } + + /* Set up destination address */ + memset (&dstaddr, 0, sizeof (dstaddr)); + dstaddr.l2_family = AF_BLUETOOTH; + dstaddr.l2_cid = htobs (ATT_CID); + dstaddr.l2_bdaddr_type = dst_type; + bacpy (&dstaddr.l2_bdaddr, dst); + + printf ("Connecting to device..."); + fflush (stdout); + + if (connect (sock, (struct sockaddr *) &dstaddr, sizeof (dstaddr)) < 0) + { + perror (" Failed to connect"); + close (sock); + return -1; + } + + printf (" Done\n"); + + return sock; +} + + + +void ble_finish(struct ble *ble) +{ +if (!ble) return; + +if (ble->att) bt_att_unref(ble->att); +if (ble->fd>0) close(ble->fd); + +free(ble); +} + + +struct ble *ble_start (const char *bdaddr) +{ + struct ble *ble; + + ble=xmalloc(sizeof(*ble)); + memset(ble,0,sizeof(*ble)); + + ble->sec = BT_SECURITY_LOW; + ble->dst_type = BDADDR_LE_RANDOM; + bacpy (&ble->src_addr, BDADDR_ANY); + + if (str2ba (bdaddr, &ble->dst_addr) < 0) + { + fprintf (stderr, "Invalid remote address: %s\n", bdaddr); + ble_finish(ble); + return NULL; + } + + + ble->fd = l2cap_le_att_connect (&ble->src_addr, &ble->dst_addr, ble->dst_type, ble->sec); + if (ble->fd < 0) + { + perror ("l2cap_le_att_connect"); + ble_finish(ble); + return NULL; + } + + + ble->att = bt_att_new(ble->fd); + + if (!ble->att) { + fprintf(stderr, "Failed to initialze ATT transport layer\n"); + ble_finish(ble); + return NULL; + } + + if (!bt_att_set_close_on_unref(ble->att, true)) { + fprintf(stderr, "Failed to set up ATT transport layer\n"); + ble_finish(ble); + return NULL; + } + + if (!bt_att_register_disconnect(ble->att, att_disconnect_cb, NULL, + NULL)) { + fprintf(stderr, "Failed to set ATT disconnect handler\n"); + ble_finish(ble); + return NULL; + } + + + + printf ("Connected!\n"); +} @@ -0,0 +1,13 @@ +struct ble { + bdaddr_t src_addr, dst_addr; + int sec; + uint8_t dst_type; + + int fd; + + struct bt_att *att; + struct gatt_db *db; + struct bt_gatt_client *gatt; +}; + + @@ -0,0 +1,13 @@ +#include "project.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) +{ + + + bt_thing (bdaddr); + + + +} @@ -0,0 +1,33 @@ + + +#define BLE_DFU_SERVICE_UUID 0x1530 /**< The UUID of the DFU Service. */ +#define BLE_DFU_PKT_CHAR_UUID 0x1532 /**< The UUID of the DFU Packet Characteristic. */ +#define BLE_DFU_CTRL_PT_UUID 0x1531 /**< The UUID of the DFU Control Point. */ +#define BLE_DFU_STATUS_REP_UUID 0x1533 /**< The UUID of the DFU Status Report Characteristic. */ +#define BLE_DFU_REV_CHAR_UUID 0x1534 /**< The UUID of the DFU Revision Characteristic. */ + +typedef enum +{ + BLE_DFU_RESP_VAL_SUCCESS = 1, /**< Success.*/ + BLE_DFU_RESP_VAL_INVALID_STATE, /**< Invalid state.*/ + BLE_DFU_RESP_VAL_NOT_SUPPORTED, /**< Operation not supported.*/ + BLE_DFU_RESP_VAL_DATA_SIZE, /**< Data size exceeds limit.*/ + BLE_DFU_RESP_VAL_CRC_ERROR, /**< CRC Error.*/ + BLE_DFU_RESP_VAL_OPER_FAILED /**< Operation failed.*/ +} ble_dfu_resp_val_t; + +enum +{ + OP_CODE_START_DFU = 1, /**< Value of the Op code field for 'Start DFU' command.*/ + OP_CODE_RECEIVE_INIT = 2, /**< Value of the Op code field for 'Initialize DFU parameters' command.*/ + OP_CODE_RECEIVE_FW = 3, /**< Value of the Op code field for 'Receive firmware image' command.*/ + OP_CODE_VALIDATE = 4, /**< Value of the Op code field for 'Validate firmware' command.*/ + OP_CODE_ACTIVATE_N_RESET = 5, /**< Value of the Op code field for 'Activate & Reset' command.*/ + OP_CODE_SYS_RESET = 6, /**< Value of the Op code field for 'Reset System' command.*/ + OP_CODE_IMAGE_SIZE_REQ = 7, /**< Value of the Op code field for 'Report received image size' command.*/ + OP_CODE_PKT_RCPT_NOTIF_REQ = 8, /**< Value of the Op code field for 'Request packet receipt notification.*/ + OP_CODE_RESPONSE = 16, /**< Value of the Op code field for 'Response.*/ + OP_CODE_PKT_RCPT_NOTIF = 17 /**< Value of the Op code field for 'Packets Receipt Notification'.*/ +}; + + diff --git a/manifest.c b/manifest.c new file mode 100644 index 0000000..795e833 --- /dev/null +++ b/manifest.c @@ -0,0 +1,73 @@ +#include "project.h" + + +json_object * +_json_object_object_get (json_object * obj, const char *name) +{ + json_object *sub; + return json_object_object_get_ex (obj, name, &sub) ? sub : NULL; +} + + +static void +dump_manifest (struct manifest *m) +{ + printf ("Manifest:\n"); + printf (" type : %s\n", m->type); + printf (" dfu_version: %s\n", m->dfu_version); + printf (" dat_file : %s\n", m->dat_file); + printf (" bin_file : %s\n", m->bin_file); +} + + + +struct manifest * +parse_manifest (const char *str) +{ + json_object *json, *manifest; + enum json_type type; + enum json_tokener_error jerr = json_tokener_success; + struct manifest *m; + + + m = xmalloc (sizeof (*m)); + memset (m, 0, sizeof (*m)); + + json = json_tokener_parse_verbose (str, &jerr); + + manifest = _json_object_object_get (json, "manifest"); + + m->dfu_version = + json_object_get_string (_json_object_object_get + (manifest, "dfu_version")); + + json_object_object_foreach (manifest, key, val) + { + if (!strcmp (key, "dfu_version")) + continue; + + m->type = key; + + m->bin_file = + json_object_get_string (_json_object_object_get (val, "bin_file")); + m->dat_file = + json_object_get_string (_json_object_object_get (val, "dat_file")); + break; + } + + + dump_manifest (m); + + + if (!m->dfu_version || !m->type || !m->bin_file || !m->dat_file) + { + fprintf (stderr, "Failed to process manifest\n"); + exit (EXIT_FAILURE); + } + + + + + + return m; +} diff --git a/manifest.h b/manifest.h new file mode 100644 index 0000000..5588535 --- /dev/null +++ b/manifest.h @@ -0,0 +1,7 @@ +struct manifest { + const char *type; + const char *dat_file; + const char *bin_file; + const char *dfu_version; +}; + diff --git a/nrfdfu.c b/nrfdfu.c new file mode 100644 index 0000000..96f99d9 --- /dev/null +++ b/nrfdfu.c @@ -0,0 +1,74 @@ +#include "project.h" + +static void +usage (char *name) +{ + fprintf (stderr, "Usage: %s -b bdaddr -p pkg_file\n", name); + exit (EXIT_FAILURE); +} + + + + + + + + + + + +int +main (int argc, char *argv[]) +{ + char *bdaddr = NULL; + char *pkg_fn = NULL; + int opt; + struct zip *zip; + char *m_str; + struct manifest *m; + + uint8_t *bin; + size_t bin_size; + + uint8_t *dat; + size_t dat_size; + + + + while ((opt = getopt (argc, argv, "b:p:")) != -1) + { + switch (opt) + { + case 'b': + bdaddr = optarg; + break; + case 'p': + pkg_fn = optarg; + break; + default: /* '?' */ + usage (argv[0]); + } + } + + if ((!bdaddr) || (!pkg_fn)) + usage (argv[0]); + + + zip = open_zip (pkg_fn); + + read_file_from_zip (zip, "manifest.json", &m_str); + + m = parse_manifest (m_str); + + dat_size = read_file_from_zip (zip, m->dat_file, &dat); + + bin_size = read_file_from_zip (zip, m->bin_file, &bin); + + + printf ("%d bytes init_data, %d bytes firmware\n", dat_size, bin_size); + + + dfu (bdaddr, m->type, m->dfu_version, dat, dat_size, bin, bin_size); + + +} diff --git a/project.h b/project.h new file mode 100644 index 0000000..4d8853e --- /dev/null +++ b/project.h @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdint.h> +#include <string.h> + +#include <zip.h> +#include <json.h> + + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +#include <bluetooth/l2cap.h> +//#include <bluetooth/uuid.h> + + +#include "manifest.h" +#include "ble.h" + +#include "prototypes.h" + + + diff --git a/prototypes.h b/prototypes.h new file mode 100644 index 0000000..015fb69 --- /dev/null +++ b/prototypes.h @@ -0,0 +1,16 @@ +/* nrfdfu.c */ +extern int main(int argc, char *argv[]); +/* util.c */ +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); +/* ble.c */ +extern int bt_thing(const char *bdaddr); +/* manifest.c */ +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); @@ -0,0 +1,18 @@ +#include "project.h" + + +void * +xmalloc (size_t s) +{ + char *ret = malloc (s); + if (!ret) + abort (); +} + +void * +xrealloc (void *p, size_t s) +{ + char *ret = realloc (p, s); + if (!ret) + abort (); +} @@ -0,0 +1,83 @@ +#include "project.h" + +void +fatal_zip (struct zip *zip) +{ + fprintf (stderr, "zip error: %s\n", zip_strerror (zip)); + exit (EXIT_FAILURE); +} + + + + + +struct zip * +open_zip (const char *fn) +{ + struct zip *ret; + int fd; + int error; + + + fd = open (fn, O_RDONLY); + if (fd < 0) + { + perror ("open"); + exit (EXIT_FAILURE); + } + + ret = zip_fdopen (fd, 0, &error); + + if (!ret) + { + fprintf (stderr, "filed to open zip file %s: %d\n", fn, error); + exit (EXIT_FAILURE); + } + + return ret; +} + + +size_t +read_file_from_zip (struct zip * zip, const char *fn, void *_buf) +{ + struct zip_file *f; + size_t size = 0, buf_sz = 1024; + ssize_t red; + uint8_t *buf; + + f = zip_fopen (zip, fn, 0); + + if (!f) + fatal_zip (zip); + + buf = xmalloc (buf_sz + 1); + + for (;;) + { + + red = zip_fread (f, buf + size, buf_sz - size); + + if (red < 0) + fatal_zip (zip); + + if (!red) + break; + + size += red; + if (size == buf_sz) + { + buf_sz <<= 1; + buf = xrealloc (buf, buf_sz); + } + + } + + buf[size] = 0; + + zip_fclose (f); + + *(void **) _buf = (void *) buf; + + return size; +} |