From 475922ce345bb0443cf4fdef00efa86676a1bf62 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 1 Sep 2015 00:41:49 +0100 Subject: fish --- Makefile | 35 ++++++++++++++ ble.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ble.h | 13 ++++++ dfu.c | 13 ++++++ dfu.h | 33 ++++++++++++++ manifest.c | 73 +++++++++++++++++++++++++++++ manifest.h | 7 +++ nrfdfu.c | 74 ++++++++++++++++++++++++++++++ project.h | 25 ++++++++++ prototypes.h | 16 +++++++ util.c | 18 ++++++++ zip.c | 83 +++++++++++++++++++++++++++++++++ 12 files changed, 537 insertions(+) create mode 100644 Makefile create mode 100644 ble.c create mode 100644 ble.h create mode 100644 dfu.c create mode 100644 dfu.h create mode 100644 manifest.c create mode 100644 manifest.h create mode 100644 nrfdfu.c create mode 100644 project.h create mode 100644 prototypes.h create mode 100644 util.c create mode 100644 zip.c 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} diff --git a/ble.c b/ble.c new file mode 100644 index 0000000..9f0b683 --- /dev/null +++ b/ble.c @@ -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"); +} diff --git a/ble.h b/ble.h new file mode 100644 index 0000000..634191e --- /dev/null +++ b/ble.h @@ -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; +}; + + diff --git a/dfu.c b/dfu.c new file mode 100644 index 0000000..d59acac --- /dev/null +++ b/dfu.c @@ -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); + + + +} diff --git a/dfu.h b/dfu.h new file mode 100644 index 0000000..54a6ac2 --- /dev/null +++ b/dfu.h @@ -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 +#include +#include +#include +#include +#include + +#include +#include + + +#include +#include +#include +#include +//#include + + +#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); diff --git a/util.c b/util.c new file mode 100644 index 0000000..554b4f9 --- /dev/null +++ b/util.c @@ -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 (); +} diff --git a/zip.c b/zip.c new file mode 100644 index 0000000..f54278a --- /dev/null +++ b/zip.c @@ -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; +} -- cgit v1.2.3