aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@lamia.panaceas.james.local>2015-09-01 00:41:49 +0100
committerroot <root@lamia.panaceas.james.local>2015-09-01 00:41:49 +0100
commit475922ce345bb0443cf4fdef00efa86676a1bf62 (patch)
tree89e3eb13232da02bddfeffaff8588765c403b71f
downloadnrfdfu-475922ce345bb0443cf4fdef00efa86676a1bf62.tar.gz
nrfdfu-475922ce345bb0443cf4fdef00efa86676a1bf62.tar.bz2
nrfdfu-475922ce345bb0443cf4fdef00efa86676a1bf62.zip
fish
-rw-r--r--Makefile35
-rw-r--r--ble.c147
-rw-r--r--ble.h13
-rw-r--r--dfu.c13
-rw-r--r--dfu.h33
-rw-r--r--manifest.c73
-rw-r--r--manifest.h7
-rw-r--r--nrfdfu.c74
-rw-r--r--project.h25
-rw-r--r--prototypes.h16
-rw-r--r--util.c18
-rw-r--r--zip.c83
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}
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 <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);
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;
+}