diff options
| author | Bdale Garbee <bdale@gag.com> | 2016-05-06 17:59:39 -0600 | 
|---|---|---|
| committer | Bdale Garbee <bdale@gag.com> | 2016-05-06 17:59:39 -0600 | 
| commit | ac7be4a40df88ee3a0992e041635e4ac4cf5ac48 (patch) | |
| tree | ee3c747b2ee98b772e02dce604b58878e9336def /ao-tools/lib/ao-dfu.c | |
| parent | b53c78e75879d647935a30acb88fdd69467617a7 (diff) | |
| parent | ce4c8a8ad57515e851207b0a82f3af791bb30d3e (diff) | |
Merge branch 'master' into branch-1.6
Diffstat (limited to 'ao-tools/lib/ao-dfu.c')
| -rw-r--r-- | ao-tools/lib/ao-dfu.c | 202 | 
1 files changed, 202 insertions, 0 deletions
| diff --git a/ao-tools/lib/ao-dfu.c b/ao-tools/lib/ao-dfu.c new file mode 100644 index 00000000..b6778495 --- /dev/null +++ b/ao-tools/lib/ao-dfu.c @@ -0,0 +1,202 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <stdarg.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include "ao-hex.h" +#include "ao-dfu.h" + +static uint32_t	dfu_crc; +static FILE	*dfu_file; +static int	dfu_failed; +static int	dfu_error; + +static uint32_t update_crc(uint32_t crc, uint8_t byte) +{ +	int j; +	uint32_t mask; + +	crc = crc ^ byte; +	for (j = 0; j < 8; j++) { +		mask = -(crc & 1); +		crc = (crc >> 1) ^ (0xEDB88320 & mask); +	} +	return crc; +} + +static void dfu_init(FILE *file) +{ +	dfu_crc = 0xffffffff; +	dfu_file = file; +	dfu_failed = 0; +	dfu_error = 0; +} + +static int dfu_fini(void) +{ +	if (fflush(dfu_file) == EOF) { +		if (!dfu_failed) { +			dfu_failed = 1; +			dfu_error = errno; +		} +	} +	if (dfu_failed) +		errno = dfu_error; +	return !dfu_failed; +} + +static void dfu_8(uint8_t byte) { +	if (putc(byte, dfu_file) == EOF) { +		if (!dfu_failed) { +			dfu_failed = 1; +			dfu_error = errno; +		} +	} +	dfu_crc = update_crc(dfu_crc, byte); +} + +static void dfu_pad(int len) { +	while (len--) +		dfu_8(0); +} + +static void dfu_string(char *string) { +	char	c; + +	while ((c = *string++)) +		dfu_8((uint8_t) c); +} + +static void dfu_string_pad(char *string, int len) { +	char	c; + +	while ((c = *string++)) { +		dfu_8((uint8_t) c); +		len--; +	} +	dfu_pad(len); +} + +static void dfu_block(uint8_t *bytes, int len) { +	while (len--) +		dfu_8(*bytes++); +} + +static void dfu_lsb16(uint16_t value) { +	dfu_8(value); +	dfu_8(value>>8); +} + +static void dfu_lsb32(uint32_t value) { +	dfu_8(value); +	dfu_8(value >> 8); +	dfu_8(value >> 16); +	dfu_8(value >> 24); +} + +static uint32_t dfu_image_size(struct ao_hex_image *image) { +	return 8 + image->length; +} + +static uint32_t dfu_images_size(int num_image, struct ao_hex_image images[]) +{ +	uint32_t	size = 0; +	int		i; + +	for (i = 0; i < num_image; i++) +		size += dfu_image_size(&images[i]); +	return size; +} + +static void dfu_image(struct ao_hex_image *image) +{ +	dfu_lsb32(image->address); +	dfu_lsb32(image->length); +	dfu_block(image->data, image->length); +} + +static void dfu_target(char *name, int num_image, struct ao_hex_image images[]) +{ +	uint32_t	images_size = dfu_images_size(num_image, images); +	int		i; + +	dfu_string("Target"); +	dfu_8(0); +	if (name) { +		dfu_8(1); +		dfu_pad(3); +		dfu_string_pad(name, 255); +	} else { +		dfu_8(0); +		dfu_pad(3); +		dfu_pad(255); +	} +	dfu_lsb32(images_size); +	dfu_lsb32(num_image); +	for (i = 0; i < num_image; i++) +		dfu_image(&images[i]); +} + +static uint32_t dfu_target_size(int num_image, struct ao_hex_image images[]) +{ +	return 274 + dfu_images_size(num_image, images); +} + +static uint32_t +dfu_size(int num_image, struct ao_hex_image images[]) +{ +	uint32_t	size = 0; +	size += 11;	/* DFU Prefix */ + +	size += dfu_target_size(num_image, images); + +	return size; +} + +int +ao_dfu_write(FILE *file, struct ao_dfu_info *info, int num_image, struct ao_hex_image images[]) +{ +	uint32_t	total_size; + +	total_size = dfu_size(num_image, images); + +	dfu_init(file); +	/* DFU Prefix */ +	dfu_string(DFU_SIGNATURE); +	dfu_8(0x01); +	dfu_lsb32(total_size); +	dfu_8(0x01); + +	dfu_target("ST...", num_image, images); + +	/* DFU Suffix */ +	dfu_lsb16(info->bcdDevice); +	dfu_lsb16(info->idProduct); +	dfu_lsb16(info->idVendor); +	dfu_lsb16(DFU_SPEC_VERSION); +	dfu_string("UFD"); +	dfu_8(16); +	dfu_lsb32(dfu_crc); +	return dfu_fini(); +} + | 
