aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Kramkowski <tk@the-tk.com>2017-05-22 17:01:47 +0100
committerTomasz Kramkowski <tk@the-tk.com>2017-05-23 13:34:35 +0100
commit8d6359867cb6bbed1edbd1de475caaa72c8427ab (patch)
tree2c73387059d69aeadd5557917c31874909acd7f0
parente2b122f129b969633ba4ca1ca15b21ee13db7f19 (diff)
downloadhktool-8d6359867cb6bbed1edbd1de475caaa72c8427ab.tar.gz
hktool-8d6359867cb6bbed1edbd1de475caaa72c8427ab.tar.xz
hktool-8d6359867cb6bbed1edbd1de475caaa72c8427ab.zip
wip
-rw-r--r--Makefile26
-rw-r--r--halfkay.h7
-rw-r--r--hktool.1.in (renamed from hktool.1)40
-rw-r--r--hktool.c6
-rw-r--r--params.c399
-rw-r--r--params.h10
6 files changed, 183 insertions, 305 deletions
diff --git a/Makefile b/Makefile
index 8871eaa..d460268 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION != git describe --tags 2>/dev/null || echo "0.1"
PROG := hktool
-MANPAGE := hktool.1
+MANPAGE := $(PROG).1
WARNINGS := -Wall -Wcast-align -Wcast-qual -Wextra -Wpedantic -Wformat=2 \
-Winit-self -Wmissing-prototypes -Wpointer-arith -Wshadow \
@@ -10,33 +10,37 @@ WARNINGS := -Wall -Wcast-align -Wcast-qual -Wextra -Wpedantic -Wformat=2 \
PKG_CONFIG ?= pkg-config
LIBS := libusb-1.0
-CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_POSIX_C_SOURCE=200112L
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_POSIX_C_SOURCE=200112L -DDATADIR=\"$(datarootdir)/$(PROG)\"
CFLAGS = -std=c11 -O2 -flto $(WARNINGS) -MMD -MP $(shell $(PKG_CONFIG) --cflags $(LIBS))
LDFLAGS = -Wl,--as-needed -O2 -flto
LDLIBS = $(shell $(PKG_CONFIG) --libs $(LIBS))
OBJ := hktool.o halfkay.o params.o util.o eprintf.o
-PREFIX ?= /usr/local
+prefix ?= /usr/local
+exec_prefix ?= $(prefix)
-bindir = /bin
-datarootdir = /share
-mandir = /man
+bindir = $(exec_prefix)/bin
+datarootdir = $(prefix)/share
+mandir = $(datarootdir)/man
+man1dir = $(mandir)/man1
-all: $(PROG)
+all: $(PROG) $(MANPAGE)
$(PROG): $(OBJ)
+%: %.in
+ $(CPP) $(CPPFLAGS) $< > $@
debug: all
debug: CFLAGS += -ggdb -Og -Werror
debug: LDFLAGS += -ggdb -Og
install: $(PROG) $(MANPAGE)
- install -Dm755 -s $(PROG) -t $(DESTDIR)$(PREFIX)$(bindir)
- install -Dm644 ./data/* -t $(DESTDIR)$(PREFIX)$(datarootdir)/$(PROG)
- install -Dm644 $(MANPAGE) -t $(DESTDIR)$(PREFIX)$(mandir)/man1
+ install -Dm755 -s $(PROG) -t $(DESTDIR)$(bindir)
+ install -Dm644 ./data/* -t $(DESTDIR)$(datarootdir)/$(PROG)
+ install -Dm644 $(MANPAGE) -t $(DESTDIR)$(man1dir)
clean:
- $(RM) $(OBJ) $(OBJ:.o=.d) $(PROG)
+ $(RM) $(OBJ) $(OBJ:.o=.d) $(PROG) $(MANPAGE)
-include $(OBJ:.o=.d)
diff --git a/halfkay.h b/halfkay.h
index b7b6360..2d459e3 100644
--- a/halfkay.h
+++ b/halfkay.h
@@ -21,12 +21,7 @@
#ifndef HALFKAY_H
#define HALFKAY_H
-struct flashparams {
- size_t memsz;
- size_t blksz;
- size_t cmdsz;
- size_t addrshft;
-};
+#include "params.h"
int flash(const struct flashparams *fp, const char *file);
int reboot(const struct flashparams *fp);
diff --git a/hktool.1 b/hktool.1.in
index 3eb8bce..4171db1 100644
--- a/hktool.1
+++ b/hktool.1.in
@@ -1,11 +1,11 @@
'\" t
-.TH "HKTOOL" "1" "2016-05-22" "hktool 0.1" "hktool Manual"
+.TH "HKTOOL" "1" "2017-05-22" "hktool 0.1" "hktool Manual"
.SH "NAME"
hktool \- a simple HalfKay protocol flashing tool
.SH "SYNOPSIS"
-.BR hktool\ [ -hlvr ]
+.BR hktool\ [ -hilvr ]
.RB [ -f
.IR file ]
.RB [ -- ]
@@ -19,14 +19,15 @@ intel hex files. Converting from intel hex files to binary data can be easily
done with
.BR objcopy (1).
The main advantages of hktool over the teensy loader command line tool is that
-devices are not hard coded, additionally, the command line interface is
-noticeably simpler.
+the list of devices which can be flashed is not hard coded, additionally, the
+command line interface is noticeably simpler.
.SH "OPTIONS"
.BI \-f\ file
.RS
Flash specified binary file to the device. Specifying '-' as the file name
-causes hktool to read input from stdin.
+causes hktool to read input from stdin (provide a relative or absolute path if
+you wish to flash a file named '-').
.RE
.B \-h
@@ -34,6 +35,11 @@ causes hktool to read input from stdin.
Show help.
.RE
+.B \-i
+.RS
+Show detailed device information.
+.RE
+
.B \-l
.RS
Show a list of supported devices.
@@ -56,15 +62,21 @@ device parameter file and passing it to hktool as a relative path in the mcu
argument, or by adding more device parameter files to the hktool data
directories.
-hktool searches for data in the hktool subdirectory of any directories found in
-the XDG_DATA_DIRS environment variable (which should be a colon delimited list
-of directories), if this variable is not set or empty then hktool proceeds as
-if XDG_DATA_DIRS was set to "/usr/local/share:/usr/local". Device parameter
-files should bear the name of the device and should be located directly in the
-hktool subdirectory of the aforementioned locations. If two or more files are
-found to have the same name, the file which was found first will be used.
-Directories are processed in the order that they appear in the XDG_DATA_DIRS
-environment variable.
+hktool searches for parameter files in the directory specified in the
+HKTOOL_DATADIR environment variable. If this variable is not set or empty, then
+hktool proceeds as if HKTOOL_DATADIR was set to DATADIR. Device parameter files
+should bear the name of the device and should be located directly inside the
+search directory.
+
+"hktool searches for data in the hktool subdirectory of any directories found in
+"the XDG_DATA_DIRS environment variable (which should be a colon delimited list
+"of directories), if this variable is not set or empty then hktool proceeds as
+"if XDG_DATA_DIRS was set to "/usr/local/share:/usr/local". Device parameter
+"files should bear the name of the device and should be located directly in the
+"hktool subdirectory of the aforementioned locations. If two or more files are
+"found to have the same name, the file which was found first will be used.
+"Directories are processed in the order that they appear in the XDG_DATA_DIRS
+"environment variable.
The format of the device parameter files is very simple. These files should
consist of only one line detailing the flashing parameters and optionally the
diff --git a/hktool.c b/hktool.c
index dad7915..cee133e 100644
--- a/hktool.c
+++ b/hktool.c
@@ -81,7 +81,7 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
break;
case 'l':
- listparams();
+ getparams(NULL, NULL);
return EXIT_SUCCESS;
break;
case 'v':
@@ -109,8 +109,8 @@ int main(int argc, char **argv)
if (argc - optind > 1)
eprintf("Invalid number of arguments\nUsage: %s %s", argv[0], usage);
- if (getparams(&fp, argv[optind]) != 0)
- return EXIT_FAILURE;
+ if (getparams(&fp, argv[optind]) == false)
+ eprintf("Could not find flash parameters for '%s'", argv[optind]);
if (doflash)
if (flash(&fp, flashfile) != 0)
diff --git a/params.c b/params.c
index 3fe324c..08272d6 100644
--- a/params.c
+++ b/params.c
@@ -18,18 +18,18 @@
*/
#include <assert.h>
-#include <ctype.h>
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <glob.h>
-#include <limits.h>
+#include <sys/stat.h>
+#include <ctype.h>
-#include "halfkay.h"
-/*#include "log.h"*/
#include "eprintf.h"
#include "params.h"
#include "util.h"
@@ -37,305 +37,168 @@
/* TODO: make this dynamic */
#define SZMAX_PFILE 1024
-struct params {
- char *chip;
- char *board;
- struct flashparams fp;
-};
-
-static int paramc = 0;
-static struct params *paramv = NULL;
-
-/* addparams: add a param definition to the param list */
-static void addparams(struct params *p)
-{
- static int avail = 1;
-
- for (int i = 0; i < paramc; i++) {
- if (xstrcasecmp(paramv[i].chip, p->chip) != 0)
- continue;
- return;
- }
-
- if (paramc >= avail - 1) {
- avail *= 2;
- if ((unsigned)avail >= INT_MAX / 2 / sizeof *paramv)
- eprintf("Too many parameter files (%d)", paramc);
- paramv = erealloc(paramv, avail * sizeof *paramv);
- }
-
- paramv[paramc].chip = estrdup(p->chip);
- paramv[paramc].board = p->board != NULL ? estrdup(p->board) : NULL;
- paramv[paramc].fp = p->fp;
- paramc++;
-}
-
-static void freeparams(struct params *p)
-{
- free(p->chip);
- free(p->board);
- free(p);
-}
-
-/* atosz: convert string to size_t */
-static int atosz(size_t *size, char *str)
-{
- unsigned long long val;
- char *endptr;
-
- assert(size);
- assert(str);
-
- /* for some silly reason strtoull actually allows negatives */
- if (str[0] == '-')
- return -1;
-
- errno = 0;
- val = strtoull(str, &endptr, 0);
- if (errno || *endptr)
- return -1;
-
- if (val > SIZE_MAX)
- return -1;
-
- *size = val;
+#ifndef DATADIR
+#define DATADIR "hktool"
+#endif
- return 0;
-}
-
-/* TODO: remove the need for freeparams by not allocating this */
/* readparams: read a file's param definition */
-static struct params *readparams(const char *file)
+static void readparams(struct flashparams *fp, const char *file)
{
- const char *chip, *board;
- struct flashparams fp;
- struct params *par;
+ char cont[SZMAX_PFILE], *pos;
size_t contsz;
- char cont[SZMAX_PFILE], *tok;
FILE *f;
assert(file);
-
- chip = file;
- for (size_t i = 0; i < strlen(file); i++)
- if (file[i] == '/')
- chip = &file[i + 1];
-
- assert(chip[0]);
+ assert(fp);
f = fopen(file, "r");
- if (f == NULL) {
- weprintf("Could not open '%s':", file);
- NULL;
- }
+ if (f == NULL)
+ eprintf("Could not open '%s':", file);
contsz = fread(cont, 1, SZMAX_PFILE, f);
- if (contsz >= sizeof cont) {
- weprintf("Parameter file '%s' is longer than %zu", file,
- sizeof cont - 1);
- contsz = sizeof cont - 1;
- }
- for (size_t i = 0; i < contsz; i++) {
- if (cont[i] == '\0') {
- weprintf("Parameter file '%s' contains null byte", file);
- cont[i] = ' ';
- } else if (isspace(cont[i]) || !isprint(cont[i])) {
- cont[i] = ' ';
+ if (contsz >= sizeof cont)
+ eprintf("Parameter file '%s' is longer than %zu", file, sizeof cont - 1);
+
+ pos = cont;
+ for (int i = 0; i < 4; i++) {
+ char *end;
+ unsigned long long val;
+
+ errno = 0;
+ val = strtoull(pos, &end, 0);
+ if (pos == end)
+ eprintf("Parameter file '%s' is malformed (offset:%zd not a number)", file, pos - cont);
+ pos = end;
+
+ if (errno == ERANGE || val > SIZE_MAX)
+ eprintf("Parameter file '%s' is malformed (offset:%zd number too large)", file, pos - cont);
+
+ switch (i) {
+ case 0: fp->memsz = val; break;
+ case 1: fp->blksz = val; break;
+ case 2: fp->cmdsz = val; break;
+ case 3: fp->addrshft = val; break;
}
}
- cont[contsz] = '\0';
-
- tok = strtok(cont, " ");
- if (tok == NULL)
- goto fail;
- if (atosz(&fp.memsz, tok) != 0)
- goto fail;
-
- tok = strtok(NULL, " ");
- if (tok == NULL)
- goto fail;
- if (atosz(&fp.blksz, tok) != 0)
- goto fail;
-
- tok = strtok(NULL, " ");
- if (tok == NULL)
- goto fail;
- if (atosz(&fp.cmdsz, tok) != 0)
- goto fail;
-
- tok = strtok(NULL, " ");
- if (tok == NULL)
- goto fail;
- if (atosz(&fp.addrshft, tok) != 0)
- goto fail;
-
- board = strtok(NULL, "");
-
- par = emalloc(sizeof *par);
- par->chip = estrdup(chip);
- par->board = board != NULL ? estrdup(board) : NULL;
- par->fp = fp;
-
-fail:
- if (par == NULL)
- weprintf("Parameter file '%s' is malformed", file);
- fclose(f);
- return par;
+ fclose(f);
}
-/* getdirs: returns a NULL terminated list of data paths */
-static char **getdirs(void)
+static void printcname(const char *file)
{
- static const char *globsuffix = "/hktool/*";
- char **dirs, *xddirs, *tok;
- int len = 0, avail = 1;
-
- xddirs = getenv("XDG_DATA_DIRS");
- if (!xddirs || !*xddirs)
- xddirs = "/usr/local/share:/usr/share";
- xddirs = estrdup(xddirs);
+ bool wasspace;
+ FILE *f;
+ int c, field;
- dirs = emalloc(sizeof *dirs);
+ assert(file);
- for (char *s = xddirs; tok = strtok(s, ":"), tok != NULL; s = NULL) {
- size_t slen;
+ f = fopen(file, "r");
+ if (f == NULL) {
+ printf(": Malformed file '%s'", file);
+ return;
+ }
- if (tok[0] == '\\')
+ field = 0;
+ wasspace = false;
+ while (c = fgetc(f), c != EOF) {
+ if (isspace(c)) {
+ wasspace = true;
continue;
-
- if (len >= avail - 1) {
- avail *= 2;
- if ((unsigned)avail >= INT_MAX / 2 / sizeof *dirs)
- eprintf("Too many data dirs (%d)", len);
- dirs = erealloc(dirs, avail * sizeof *dirs);
}
-
- if (SIZE_MAX - (strlen(tok) + 1) < strlen(globsuffix))
- eprintf("Data dir too long (\"%.20s\")", tok);
- slen = strlen(tok) + strlen(globsuffix) + 1;
- dirs[len] = emalloc(slen);
- snprintf(dirs[len], slen, "%s%s", tok, globsuffix);
- len++;
+ if (wasspace) {
+ wasspace = false;
+ field++;
+ }
+ if (field >= 4) {
+ ungetc(c, f);
+ break;
+ }
}
- free(xddirs);
-
- dirs[len++] = NULL;
- dirs = erealloc(dirs, len * sizeof *dirs);
-
- return dirs;
-}
-
-/* freedirs: frees list returned by getdirs */
-static void freedirs(char **dirs)
-{
- assert(dirs);
+ if (c == EOF)
+ return;
- for (size_t i = 0; dirs[i]; i++)
- free(dirs[i]);
- free(dirs);
+ printf(": ");
+ while (c = fgetc(f), c != EOF)
+ if (c != '\n')
+ putchar(c);
}
-/* loadparams: locate and load all param files */
-static void loadparams(void)
+/* getparams: Locate a parameter file and load it or show names of all files */
+bool getparams(struct flashparams *fp, const char *name)
{
- char **dirs;
- glob_t globbuf;
-
- if (paramv != NULL)
- return;
-
- dirs = getdirs();
-
- for (int i = 0; dirs[i]; i++) {
- int ret;
-
- ret = glob(dirs[i], i != 0 ? GLOB_APPEND : 0, NULL, &globbuf);
- if (ret == GLOB_NOSPACE)
- eprintf("glob ran out of memory");
- if (ret == GLOB_NOMATCH)
- continue;
- if (ret == GLOB_ABORTED) {
- weprintf("A call to glob resulted in a read error");
- continue;
+ char pathbuf[PATH_MAX], *dirname, *fullpath;
+ struct dirent *de;
+ size_t pathsize;
+ bool found;
+ DIR *dir;
+
+ assert((fp == NULL && name == NULL) || (fp != NULL && name != NULL));
+
+ fullpath = pathbuf;
+ pathsize = sizeof pathbuf;
+
+ dirname = getenv("HKTOOL_DATADIR");
+ if (dirname == NULL || strlen(dirname) == 0)
+ dirname = DATADIR;
+
+ dir = opendir(dirname);
+ if (dir == NULL)
+ eprintf("Could not open directory '%s':", dirname);
+
+ if (name == NULL)
+ printf("Searching '%s' for Device Parameter Files:\n", dirname);
+
+ found = false;
+ while (errno = 0, de = readdir(dir), de != NULL) {
+ bool ismatch, doprint;
+
+ doprint = name == NULL;
+ if (doprint)
+ ismatch = strcmp(de->d_name, name) == 0;
+ else
+ ismatch = false;
+
+ if (doprint || ismatch) {
+ int size;
+
+ size = snprintf(NULL, 0, "%s/%s", dirname, de->d_name);
+ assert(size > 0);
+ if ((size_t)size > pathsize) {
+ if (fullpath == pathbuf)
+ fullpath = NULL;
+ fullpath = erealloc(fullpath, size);
+ pathsize = size;
+ }
+ size = snprintf(fullpath, pathsize, "%s/%s", dirname, de->d_name);
+ assert(size > 0);
+ assert((size_t)size < pathsize);
}
- }
- freedirs(dirs);
-
- for (size_t i = 0; i < globbuf.gl_pathc; i++) {
- struct params *par;
- par = readparams(globbuf.gl_pathv[i]);
- if (par == NULL)
+ if (doprint) {
+ printf("%s", de->d_name);
+ printcname(fullpath);
+ putchar('\n');
continue;
- addparams(par);
- freeparams(par);
- }
-
- globfree(&globbuf);
-}
-
-static int b16len(size_t n)
-{
- return snprintf(NULL, 0, "%zx", n);
-}
-
-/* listparams: display a list of found parameter files */
-void listparams(void)
-{
- int lengths[5] = { 0 };
-
- loadparams();
+ };
- for (int i = 0; i < paramc; i++) {
- int clengths[5];
+ if (!ismatch)
+ continue;
- clengths[0] = strlen(paramv[i].chip);
- clengths[1] = b16len(paramv[i].fp.memsz);
- clengths[2] = b16len(paramv[i].fp.blksz);
- clengths[3] = b16len(paramv[i].fp.cmdsz);
- clengths[4] = b16len(paramv[i].fp.addrshft);
- for (int j = 0; j < 5; j++)
- if (clengths[j] > lengths[j])
- lengths[j] = clengths[j];
+ readparams(fp, fullpath);
+ found = true;
+ errno = 0;
+ break;
}
+ if (errno)
+ weprintf("Could not read directory '%s':", dirname);
- for (int i = 0; i < paramc; i++)
- printf("%-*s - (0x%.*zx 0x%.*zx 0x%.*zx 0x%.*zx) %s\n",
- lengths[0], paramv[i].chip,
- lengths[1], paramv[i].fp.memsz, lengths[2], paramv[i].fp.blksz,
- lengths[3], paramv[i].fp.cmdsz, lengths[4], paramv[i].fp.addrshft,
- paramv[i].board != NULL ? paramv[i].board : "");
-}
-
-/* getparams: return the flash params for the specified MCU */
-int getparams(struct flashparams *fp, const char *mcufile)
-{
- assert(fp);
- assert(mcufile);
-
- loadparams();
-
- if (strchr(mcufile, '/') != NULL) {
- struct params *par;
- par = readparams(mcufile);
- if (par == NULL)
- return -1;
- *fp = par->fp;
- freeparams(par);
- return 0;
- }
-
- for (int i = 0; i < paramc; i++) {
- if (xstrcasecmp(paramv[i].chip, mcufile) == 0) {
- *fp = paramv[i].fp;
- return 0;
- }
- }
+ if (fullpath != pathbuf)
+ free(fullpath);
- weprintf("'%s' is not a valid MCU name", mcufile);
+ if (closedir(dir) == -1)
+ eprintf("Could not close directory '%s':", dirname);
- return -1;
+ return found;
}
diff --git a/params.h b/params.h
index 069d4fd..6417063 100644
--- a/params.h
+++ b/params.h
@@ -20,9 +20,13 @@
#ifndef PARAMS_H
#define PARAMS_H
-#include "halfkay.h"
+struct flashparams {
+ size_t memsz;
+ size_t blksz;
+ size_t cmdsz;
+ size_t addrshft;
+};
-void listparams(void);
-int getparams(struct flashparams *fp, const char *mcufile);
+bool getparams(struct flashparams *fp, const char *name);
#endif /* PARAMS_H */