diff options
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/.gitignore | 6 | ||||
| -rw-r--r-- | src/test/Makefile | 48 | ||||
| -rw-r--r-- | src/test/ao_aes_test.c | 52 | ||||
| -rw-r--r-- | src/test/ao_aprs_test.c | 132 | ||||
| -rw-r--r-- | src/test/ao_fat_test.c | 565 | ||||
| -rw-r--r-- | src/test/ao_flight_test.c | 451 | ||||
| -rw-r--r-- | src/test/ao_gps_test.c | 8 | ||||
| -rw-r--r-- | src/test/ao_gps_test_skytraq.c | 10 | ||||
| -rw-r--r-- | src/test/ao_gps_test_ublox.c | 409 | ||||
| -rw-r--r-- | src/test/ao_micropeak_test.c | 220 | ||||
| -rwxr-xr-x | src/test/plotmicro | 16 | ||||
| -rwxr-xr-x | src/test/plotmm | 11 | ||||
| -rwxr-xr-x | src/test/run-mm | 41 | 
13 files changed, 1919 insertions, 50 deletions
diff --git a/src/test/.gitignore b/src/test/.gitignore index 5d528ab9..90af6517 100644 --- a/src/test/.gitignore +++ b/src/test/.gitignore @@ -1,3 +1,5 @@ +ao_aprs_data.wav +ao_aprs_test  ao_flight_test  ao_flight_test_baro  ao_flight_test_accel @@ -5,5 +7,9 @@ ao_gps_test  ao_gps_test_skytraq  ao_convert_test  ao_convert_pa_test +ao_fat_test  ao_fec_test +ao_flight_test_mm  ao_flight_test_noisy_accel +ao_micropeak_test +ao_aes_test diff --git a/src/test/Makefile b/src/test/Makefile index db3cc04b..169c1dc6 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,36 +1,46 @@ -vpath % ..:../core:../drivers:../util +vpath % ..:../core:../drivers:../util:../micropeak:../aes -PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_test +PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \ +	ao_gps_test ao_gps_test_skytraq ao_gps_test_ublox ao_convert_test ao_convert_pa_test ao_fec_test \ +	ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test + +INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h  KALMAN=make-kalman  -CFLAGS=-I.. -I. -I../core -I../drivers -O3 -g -Wall +CFLAGS=-I.. -I. -I../core -I../drivers -I../micropeak -O0 -g -Wall -all: $(PROGS) +all: $(PROGS) ao_aprs_data.wav  clean: -	rm -f $(PROGS) run-out.baro run-out.full +	rm -f $(PROGS) ao_aprs_data.wav run-out.baro run-out.full  install: -ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h +ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h $(INCS)  	cc $(CFLAGS) -o $@ $< -ao_flight_test_noisy_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h ao_kalman.h +ao_flight_test_noisy_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)  	cc -DNOISY_ACCEL=1 $(CFLAGS) -o $@ $< -ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalman.c altitude.h ao_kalman.h +ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalman.c $(INCS)  	cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 ao_flight_test.c -ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalman.c altitude.h ao_kalman.h +ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalman.c $(INCS)  	cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c +ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) +	cc -DTELEMEGA=1 $(CFLAGS) -o $@ $< -lm +  ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h  	cc $(CFLAGS) -o $@ $<  ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_host.h  	cc $(CFLAGS) -o $@ $< +ao_gps_test_ublox: ao_gps_test_ublox.c ao_gps_ublox.c ao_gps_print.c ao_host.h ao_gps_ublox.h +	cc $(CFLAGS) -o $@ $< +  ao_convert_test: ao_convert_test.c ao_convert.c altitude.h  	cc $(CFLAGS) -o $@ $< @@ -43,5 +53,23 @@ ao_kalman.h: $(KALMAN)  ao_fec_test: ao_fec_test.c ao_fec_tx.c ao_fec_rx.c  	cc $(CFLAGS) -DAO_FEC_DEBUG=1 -o $@ ao_fec_test.c ../core/ao_fec_tx.c ../core/ao_fec_rx.c -lm +ao_aprs_test: ao_aprs_test.c ao_aprs.c +	cc $(CFLAGS) -o $@ ao_aprs_test.c + +SOX_INPUT_ARGS=--type raw --encoding unsigned-integer -b 8 -c 1 -r 9600 +SOX_OUTPUT_ARGS=--type wav + +ao_aprs_data.wav: ao_aprs_test +	./ao_aprs_test | sox $(SOX_INPUT_ARGS) - $(SOX_OUTPUT_ARGS) $@ +  check: ao_fec_test ao_flight_test ao_flight_test_baro run-tests -	./ao_fec_test && ./run-tests
\ No newline at end of file +	./ao_fec_test && ./run-tests + +ao_micropeak_test: ao_micropeak_test.c ao_microflight.c ao_kalman.h +	cc $(CFLAGS) -o $@ ao_micropeak_test.c -lm + +ao_fat_test: ao_fat_test.c ao_fat.c ao_bufio.c +	cc $(CFLAGS) -o $@ ao_fat_test.c -lssl + +ao_aes_test: ao_aes_test.c ao_aes.c ao_aes_tables.c +	cc $(CFLAGS) -o $@ ao_aes_test.c diff --git a/src/test/ao_aes_test.c b/src/test/ao_aes_test.c new file mode 100644 index 00000000..dcedbfca --- /dev/null +++ b/src/test/ao_aes_test.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2013 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. + */ + +#define __pdata +#define __data +#define __xdata +#define __code +#define __reentrant + +#include <string.h> +#include <stdio.h> + +#define AO_AES_TEST	1 + +#include "../aes/ao_aes_tables.c" +#include "../aes/ao_aes.c" + +static uint8_t key[16]; +static uint8_t text[16]; +static uint8_t cbc[16]; + +int +main (int argc, char **argv) +{ +	int i; + +	ao_aes_init(); +	ao_aes_set_mode(ao_aes_mode_cbc_mac); +	ao_aes_set_key(key); +	ao_aes_zero_iv(); +	ao_aes_run(text, cbc); + +	printf ("CBC"); +	for (i = 0; i < sizeof (cbc); i++) +		printf (" %02x", cbc[i]); +	printf ("\n"); +	return 0; +} diff --git a/src/test/ao_aprs_test.c b/src/test/ao_aprs_test.c new file mode 100644 index 00000000..69147786 --- /dev/null +++ b/src/test/ao_aprs_test.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2012 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> + +#include <ao_telemetry.h> + +struct ao_telemetry_location ao_gps_data; + +#define AO_APRS_TEST + +typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len); + +#define DEBUG 0 +#if DEBUG +void +ao_aprs_bit(uint8_t bit) +{ +	static int	seq = 0; +	printf ("%6d %d\n", seq++, bit ? 1 : 0); +} +#else +void +ao_aprs_bit(uint8_t bit) +{ +	putchar (bit ? 0xc0 : 0x40); +} +#endif + +void +ao_radio_send_aprs(ao_radio_fill_func fill); + +#include <ao_aprs.c> + +/* + * @section copyright_sec Copyright + * + * Copyright (c) 2001-2009 Michael Gray, KD7LMO + + + * + * + * @section gpl_sec GNU General Public License + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  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 + *   + + */ + +static void +audio_gap(int secs) +{ +#if !DEBUG +	int	samples = secs * 9600; + +	while (samples--) +		ao_aprs_bit(0); +#endif +} + +// This is where we go after reset. +int main(int argc, char **argv) +{ +    audio_gap(1); + +    ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000; +    ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000; +    ao_gps_data.altitude = 84; + +    /* Transmit one packet */ +    ao_aprs_send(); + +    tncBuffer[strlen((char *) tncBuffer) - 2] = '\0'; +    fprintf(stderr, "packet: %s\n", tncBuffer); + +    exit(0); +} + +void +ao_radio_send_aprs(ao_radio_fill_func fill) +{ +	int16_t	len; +	uint8_t	done = 0; +	uint8_t	buf[16], *b, c; +	uint8_t bit; + +	while (!done) { +		len = (*fill)(buf, sizeof (buf)); +		if (len < 0) { +			done = 1; +			len = -len; +		} +		b = buf; +		while (len--) { +			c = *b++; +			for (bit = 0; bit < 8; bit++) { +				ao_aprs_bit(c & 0x80); +				c <<= 1; +			} +		} +	} +} diff --git a/src/test/ao_fat_test.c b/src/test/ao_fat_test.c new file mode 100644 index 00000000..d1309024 --- /dev/null +++ b/src/test/ao_fat_test.c @@ -0,0 +1,565 @@ +/* + * Copyright © 2013 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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <getopt.h> +#include <math.h> +#include <unistd.h> +#include <fcntl.h> +#include <openssl/md5.h> + +#define AO_FAT_TEST + +void +ao_mutex_get(uint8_t *mutex) +{ +} + +void +ao_mutex_put(uint8_t *mutex) +{ +} + +void +ao_panic(uint8_t panic) +{ +	printf ("panic %d\n", panic); +	abort(); +} + +#define AO_PANIC_BUFIO	15 + +#define ao_cmd_success	0 + +uint8_t ao_cmd_status; +uint32_t ao_cmd_lex_u32; + +void +ao_cmd_decimal() +{ +} + +#define ao_cmd_register(x) + +struct ao_cmds { +	void		(*func)(void); +	const char	*help; +}; + +int fs_fd; + +uint64_t	total_reads, total_writes; + +uint8_t +ao_sdcard_read_block(uint32_t block, uint8_t *data) +{ +	++total_reads; +	lseek(fs_fd, block * 512, 0); +	return read(fs_fd, data, 512) == 512; +} + +uint8_t +ao_sdcard_write_block(uint32_t block, uint8_t *data) +{ +	++total_writes; +	lseek(fs_fd, block * 512, 0); +	return write(fs_fd, data, 512) == 512; +} + +struct fs_param { +	int	fat; +	int	blocks; +} fs_params[] = { +	{ .fat = 16, .blocks = 16384 }, +	{ .fat = 32, .blocks = 16384 }, +	{ .fat = 16, .blocks = 65536 }, +	{ .fat = 32, .blocks = 65536 }, +	{ .fat = 16, .blocks = 1048576 }, +	{ .fat = 32, .blocks = 1048576 }, +	{ .fat = 0, .blocks = 0 }, +}; + +char		*fs = "fs.fat"; +struct fs_param	*param; + +void +ao_sdcard_init(void) +{ +	char	cmd[1024]; + +	if (fs_fd) { +		close(fs_fd); +		fs_fd = 0; +	} +	snprintf(cmd, sizeof(cmd), "rm -f %s && mkfs.vfat -F %d -C %s %d", +		 fs, param->fat, fs, param->blocks); +	if (system (cmd) != 0) { +		fprintf(stderr, "'%s' failed\n", cmd); +		exit(1); +	} +	fs_fd = open(fs, 2); +	if (fs_fd < 0) { +		perror (fs); +		exit(1); +	} +} + +#include "ao_bufio.c" +void +check_bufio(char *where) +{ +	int	b; + +	for (b = 0; b < AO_NUM_BUF; b++) { +		if (ao_bufio[b].busy) { +			printf ("%s: buffer %d busy. block %d seqno %u\n", +				where, b, ao_bufio[b].block, ao_bufio[b].seqno & 0xffff); +			abort(); +		} +	} +} + + +void +check_fat(void); + +#include "ao_fat.c" + +/* Get the next cluster entry in the chain */ +static cluster_t +ao_fat_entry_raw_read(cluster_t cluster, uint8_t fat) +{ +	sector_t		sector; +	cluster_offset_t	offset; +	uint8_t			*buf; +	cluster_t		ret; + +	if (fat32) +		cluster <<= 2; +	else +		cluster <<= 1; +	sector = cluster >> SECTOR_SHIFT; +	offset = cluster & SECTOR_MASK; +	buf = _ao_fat_sector_get(fat_start + fat * sectors_per_fat + sector); +	if (!buf) +		return 0; +	if (fat32) +		ret = get_u32(buf + offset); +	else +		ret = get_u16(buf + offset); +	_ao_fat_sector_put(buf, 0); +	return ret; +} + +void +dump_fat(void) +{ +	int	e; + +	printf ("\n **** FAT ****\n\n"); +	for (e = 0; e < number_cluster; e++) { +		if ((e & 0xf) == 0x0) +			printf ("%04x: ", e); +		if (fat32) +			printf (" %08x", ao_fat_entry_raw_read(e, 0)); +		else +			printf (" %04x", ao_fat_entry_raw_read(e, 0)); +		if ((e & 0xf) == 0xf) +			putchar ('\n'); +	} +	if (e & 0xf) +		putchar('\n'); +} + +void +fat_list(void) +{ +	dirent_t		entry = 0; +	struct ao_fat_dirent	dirent; + +	printf ("  **** Root directory ****\n"); +	while (ao_fat_readdir(&entry, &dirent)) { +		printf ("%04x: %-8.8s.%-3.3s %02x %04x %d\n", +			entry, +			dirent.name, +			dirent.name + 8, +			dirent.attr, +			dirent.cluster, +			dirent.size); +	} + +	printf ("  **** End of root directory ****\n"); +} + +void +fatal(char *msg, ...) +{ +//	dump_fat(); +//	fat_list(); + +	va_list	l; +	va_start(l, msg); +	vfprintf(stderr, msg, l); +	va_end(l); + +	abort(); +} + +void +check_fat(void) +{ +	cluster_t	e; +	int		f; + +	for (e = 0; e < number_cluster; e++) { +		cluster_t	v = ao_fat_entry_raw_read(e, 0); +		for (f = 1; f < number_fat; f++) { +			cluster_t	o = ao_fat_entry_raw_read(e, f); +			if (o != v) +				fatal ("fats differ at %08x (0 %08x %d %08x)\n", e, v, f, o); +		} +	} +} + +cluster_t +check_file(dirent_t dent, cluster_t first_cluster, dirent_t *used) +{ +	cluster_t	clusters = 0; +	cluster_t	cluster; + +	if (!first_cluster) +		return 0; +	 +	for (cluster = first_cluster; +	     fat32 ? !AO_FAT_IS_LAST_CLUSTER(cluster) : !AO_FAT_IS_LAST_CLUSTER16(cluster); +	     cluster = ao_fat_entry_raw_read(cluster, 0)) +	{ +		if (!_ao_fat_cluster_valid(cluster)) +			fatal("file %d: invalid cluster %08x\n", dent, cluster); +		if (used[cluster]) +			fatal("file %d: duplicate cluster %08x also in file %d\n", dent, cluster, used[cluster]-1); +		used[cluster] = dent; +		clusters++; +	} +	return clusters; +} + +void +check_fs(void) +{ +	dirent_t	r; +	cluster_t	cluster, chain; +	dirent_t	*used; +	uint8_t		*dent; + +	check_fat(); + +	used = calloc(sizeof (dirent_t), number_cluster); + +	for (r = 0; (dent = _ao_fat_root_get(r)); r++) { +		cluster_t	clusters; +		offset_t	size; +		cluster_t	first_cluster; +		char		name[11]; + +		if (!dent) +			fatal("cannot map dent %d\n", r); +		memcpy(name, dent+0, 11); +		first_cluster = get_u16(dent + 0x1a); +		if (fat32) +			first_cluster |= (cluster_t) get_u16(dent + 0x14) << 16; +		size = get_u32(dent + 0x1c); +		_ao_fat_root_put(dent, r, 0); + +		if (name[0] == AO_FAT_DENT_END) { +			break; +		} + +		clusters = check_file(r + 1, first_cluster, used); +		if (size == 0) { +			if (clusters != 0) +				fatal("file %d: zero sized, but %d clusters\n", clusters); +		} else { +			if (size > clusters * bytes_per_cluster) +				fatal("file %d: size %u beyond clusters %d (%u)\n", +				      r, size, clusters, clusters * bytes_per_cluster); +			if (size <= (clusters - 1) * bytes_per_cluster) +				fatal("file %d: size %u too small clusters %d (%u)\n", +				      r, size, clusters, clusters * bytes_per_cluster); +		} +	} +	if (!fat32) { +		for (; r < root_entries; r++) { +			uint8_t	*dent = _ao_fat_root_get(r); +			if (!dent) +				fatal("cannot map dent %d\n", r); +			if (dent[0] != AO_FAT_DENT_END) +				fatal("found non-zero dent past end %d\n", r); +			_ao_fat_root_put(dent, r, 0); +		} +	} else { +		check_file((dirent_t) -1, root_cluster, used); +	} + +	for (cluster = 0; cluster < 2; cluster++) { +		chain = ao_fat_entry_raw_read(cluster, 0); + +		if (fat32) { +			if ((chain & 0xffffff8) != 0xffffff8) +				fatal("cluster %d: not marked busy\n", cluster); +		} else { +			if ((chain & 0xfff8) != 0xfff8) +				fatal("cluster %d: not marked busy\n", cluster); +		} +	} +	for (; cluster < number_cluster; cluster++) { +		chain = ao_fat_entry_raw_read(cluster, 0); + +		if (chain != 0) { +			if (used[cluster] == 0) +				fatal("cluster %d: marked busy, but not in any file\n", cluster); +		} else { +			if (used[cluster] != 0) +				fatal("cluster %d: marked free, but found in file %d\n", cluster, used[cluster]-1); +		} +	} +} + +#define NUM_FILES	100 +#define LINES_FILE	500000 + +uint32_t		sizes[NUM_FILES]; + +unsigned char		md5[NUM_FILES][MD5_DIGEST_LENGTH]; + +void +micro_test_fs(void) +{ +	int8_t	fd; +	char	name[] = "FOO        "; +	char	buf[512]; +	int	len; + +	printf ("write once\n"); +	if ((fd = ao_fat_creat(name)) >= 0) { +		ao_fat_write(fd, "hello world\n", 12); +		ao_fat_close(fd); +	} + +	printf ("read first\n"); +	if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { +		len = ao_fat_read(fd, buf, sizeof(buf)); +		write (1, buf, len); +		ao_fat_close(fd); +	} +	 +	printf ("write again\n"); +	if ((fd = ao_fat_creat(name)) >= 0) { +		ao_fat_write(fd, "hi\n", 3); +		ao_fat_close(fd); +	} + +	printf ("read again\n"); +	if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { +		len = ao_fat_read(fd, buf, sizeof(buf)); +		write (1, buf, len); +		ao_fat_close(fd); +	} + +	printf ("write 3\n"); +	if ((fd = ao_fat_creat(name)) >= 0) { +		int	l; +		char	c; + +		for (l = 0; l < 10; l++) { +			for (c = ' '; c < '~'; c++) +				ao_fat_write(fd, &c, 1); +			c = '\n'; +			ao_fat_write(fd, &c, 1); +		} +		ao_fat_close(fd); +	} + +	printf ("read 3\n"); +	if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { +		while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0) +			write (1, buf, len); +		ao_fat_close(fd); +	} + +	check_fs(); +	printf ("all done\n"); +} + + +void +short_test_fs(void) +{ +	int	len; +	int8_t	fd; +	char	buf[345]; + +	if ((fd = ao_fat_open("HELLO   TXT",AO_FAT_OPEN_READ)) >= 0) { +		printf ("File contents for HELLO.TXT\n"); +		while ((len = ao_fat_read(fd, buf, sizeof(buf)))) +			write(1, buf, len); +		ao_fat_close(fd); +	} +	 +	if ((fd = ao_fat_creat("NEWFILE TXT")) >= 0) { +		printf ("Create new file\n"); +		for (len = 0; len < 2; len++) +			ao_fat_write(fd, "hello, world!\n", 14); +		ao_fat_seek(fd, 0, AO_FAT_SEEK_SET); +		printf ("read new file\n"); +		while ((len = ao_fat_read(fd, buf, sizeof (buf)))) +			write (1, buf, len); +		ao_fat_close(fd); +	} + +	check_fs(); +} + +void +long_test_fs(void) +{ +	char	name[12]; +	int	id; +	MD5_CTX	ctx; +	unsigned char	md5_check[MD5_DIGEST_LENGTH]; +	char buf[337]; +	int	len; +	int8_t	fd; +	uint64_t	total_file_size = 0; + +	total_reads = total_writes = 0; + +	printf ("   **** Creating %d files\n", NUM_FILES); + +	memset(sizes, '\0', sizeof (sizes)); +	for (id = 0; id < NUM_FILES; id++) { +		sprintf(name, "D%07dTXT", id); +		if ((id % ((NUM_FILES+49)/50)) == 0) { +			printf ("."); fflush(stdout); +		} +		if ((fd = ao_fat_creat(name)) >= 0) { +			int j; +			char	line[64]; +			check_bufio("file created"); +			MD5_Init(&ctx); +			for (j = 0; j < LINES_FILE; j++) { +				int len, ret; +				sprintf (line, "Hello, world %d %d\r\n", id, j); +				len = strlen(line); +				ret = ao_fat_write(fd, line, len); +				if (ret <= 0) +					break; +				total_file_size += ret; +				MD5_Update(&ctx, line, ret); +				sizes[id] += ret; +				if (ret != len) +					printf ("write failed %d\n", ret); +			} +			ao_fat_close(fd); +			MD5_Final(&md5[id][0], &ctx); +			check_bufio("file written"); +		} +	} + +	printf ("\n   **** Write IO: read %llu write %llu data sectors %llu\n", total_reads, total_writes, (total_file_size + 511) / 512); + +	check_bufio("all files created"); +	printf ("   **** All done creating files\n"); +	check_fs(); + +	total_reads = total_writes = 0; + +	printf ("   **** Comparing %d files\n", NUM_FILES); + +	for (id = 0; id < NUM_FILES; id++) { +		uint32_t size; +		sprintf(name, "D%07dTXT", id); +		size = 0; +		if ((id % ((NUM_FILES+49)/50)) == 0) { +			printf ("."); fflush(stdout); +		} +		if ((fd = ao_fat_open(name, AO_FAT_OPEN_READ)) >= 0) { +			MD5_Init(&ctx); +			while ((len = ao_fat_read(fd, buf, sizeof(buf))) > 0) { +				MD5_Update(&ctx, buf, len); +				size += len; +			} +			ao_fat_close(fd); +			MD5_Final(md5_check, &ctx); +			if (size != sizes[id]) +				fatal("file %d: size differs %d written %d read\n", +				      id, sizes[id], size); +			if (memcmp(md5_check, &md5[id][0], sizeof (md5_check)) != 0) +				fatal ("file %d: checksum failed\n", id); +			check_bufio("file shown"); +		} +	} +	printf ("\n  **** Read IO: read %llu write %llu\n", total_reads, total_writes); +} + +char *params[] = { +	"-F 16 -C %s 16384", +	"-F 32 -C %s 16384", +	"-F 16 -C %s 65536", +	"-F 32 -C %s 65536", +	"-F 16 -C %s 1048576", +	"-F 32 -C %s 1048576", +	NULL +}; + +void +do_test(void (*test)(void)) +{ +	ao_fat_init(); + +	check_bufio("top"); +	_ao_fat_setup(); + +	check_fs(); +	check_bufio("after setup"); +	(*test)(); +	ao_fat_unmount(); +} + +int +main(int argc, char **argv) +{ +	int	p; + +	if (argv[1]) +		fs = argv[1]; + +	for (p = 0; fs_params[p].fat; p++) { +		param = &fs_params[p]; + +		do_test(micro_test_fs); +		do_test(short_test_fs); +		do_test(long_test_fs); +	} +	unlink (fs); + +	return 0; +} diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index b9e291ce..99bed7ee 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -35,6 +35,21 @@  #define AO_MS_TO_SPEED(ms)	((int16_t) ((ms) * 16))  #define AO_MSS_TO_ACCEL(mss)	((int16_t) ((mss) * 16)) +#if TELEMEGA +#define AO_ADC_NUM_SENSE	6 +#define HAS_MS5607		1 +#define HAS_MPU6000		1 +#define HAS_MMA655X		1 + +struct ao_adc { +	int16_t			sense[AO_ADC_NUM_SENSE]; +	int16_t			v_batt; +	int16_t			v_pbatt; +	int16_t			accel_ref; +	int16_t			accel; +	int16_t			temp; +}; +#else  /*   * One set of samples read from the A/D converter   */ @@ -48,6 +63,13 @@ struct ao_adc {  	int16_t		sense_m;	/* main continuity sense */  }; +#ifndef HAS_ACCEL +#define HAS_ACCEL 1 +#define HAS_ACCEL_REF 0 +#endif + +#endif +  #define __pdata  #define __data  #define __xdata @@ -58,12 +80,9 @@ struct ao_adc {  #define HAS_IGNITE 1  #define HAS_USB 1  #define HAS_GPS 1 -#ifndef HAS_ACCEL -#define HAS_ACCEL 1 -#define HAS_ACCEL_REF 0 -#endif  #include <ao_data.h> +#include <ao_log.h>  #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))  #define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) @@ -72,7 +91,6 @@ struct ao_adc {  /*   * Above this height, the baro sensor doesn't work   */ -#define AO_MAX_BARO_HEIGHT	12000  #define AO_BARO_SATURATE	13000  #define AO_MIN_BARO_VALUE	ao_altitude_to_pres(AO_BARO_SATURATE) @@ -83,19 +101,6 @@ struct ao_adc {  #define ACCEL_NOSE_UP	(ao_accel_2g >> 2) -enum ao_flight_state { -	ao_flight_startup = 0, -	ao_flight_idle = 1, -	ao_flight_pad = 2, -	ao_flight_boost = 3, -	ao_flight_fast = 4, -	ao_flight_coast = 5, -	ao_flight_drogue = 6, -	ao_flight_main = 7, -	ao_flight_landed = 8, -	ao_flight_invalid = 9 -}; -  extern enum ao_flight_state ao_flight_state;  #define FALSE 0 @@ -190,7 +195,14 @@ struct ao_cmds {  #define ao_xmemcmp(d,s,c) memcmp(d,s,c)  #define AO_NEED_ALTITUDE_TO_PRES 1 +#if TELEMEGA +#include "ao_convert_pa.c" +#include <ao_ms5607.h> +struct ao_ms5607_prom	ms5607_prom; +#include "ao_ms5607_convert.c" +#else  #include "ao_convert.c" +#endif  struct ao_config {  	uint16_t	main_deploy; @@ -218,16 +230,20 @@ typedef int16_t	accel_t;  extern uint16_t	ao_sample_tick; -extern int16_t	ao_sample_height; +extern alt_t	ao_sample_height;  extern accel_t	ao_sample_accel;  extern int32_t	ao_accel_scale; -extern int16_t	ao_ground_height; -extern int16_t	ao_sample_alt; +extern alt_t	ao_ground_height; +extern alt_t	ao_sample_alt; + +double ao_sample_qangle;  int ao_sample_prev_tick;  uint16_t	prev_tick; +  #include "ao_kalman.c" +#include "ao_sqrt.c"  #include "ao_sample.c"  #include "ao_flight.c" @@ -248,6 +264,10 @@ static int	landed_set;  static double	landed_time;  static double	landed_height; +#if HAS_MPU6000 +static struct ao_mpu6000_sample	ao_ground_mpu6000; +#endif +  void  ao_test_exit(void)  { @@ -285,6 +305,20 @@ ao_test_exit(void)  	exit(0);  } +#if HAS_MPU6000 +static double +ao_mpu6000_accel(int16_t sensor) +{ +	return sensor / 32767.0 * MPU6000_ACCEL_FULLSCALE * GRAVITY; +} + +static double +ao_mpu6000_gyro(int32_t sensor) +{ +	return sensor / 32767.0 * MPU6000_GYRO_FULLSCALE; +} +#endif +  void  ao_insert(void)  { @@ -293,9 +327,20 @@ ao_insert(void)  	ao_data_ring[ao_data_head] = ao_data_static;  	ao_data_head = ao_data_ring_next(ao_data_head);  	if (ao_flight_state != ao_flight_startup) { -		double	height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height; -		double  accel = ((ao_flight_ground_accel - ao_data_static.adc.accel) * GRAVITY * 2.0) / +#if HAS_ACCEL +		double  accel = ((ao_flight_ground_accel - ao_data_accel_cook(&ao_data_static)) * GRAVITY * 2.0) /  			(ao_config.accel_minus_g - ao_config.accel_plus_g); +#else +		double	accel = 0.0; +#endif +#if TELEMEGA +		double	height; + +		ao_ms5607_convert(&ao_data_static.ms5607_raw, &ao_data_static.ms5607_cooked); +		height = ao_pa_to_altitude(ao_data_static.ms5607_cooked.pres) - ao_ground_height; +#else +		double	height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height; +#endif  		if (!tick_offset)  			tick_offset = -ao_data_static.tick; @@ -327,10 +372,26 @@ ao_insert(void)  		}  		if (!ao_summary) { -			printf("%7.2f height %8.2f accel %8.3f state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n", +			printf("%7.2f height %8.2f accel %8.3f " +#if TELEMEGA +			       "roll %8.3f angle %8.3f qangle %8.3f " +			       "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f " +#endif +			       "state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n",  			       time,  			       height,  			       accel, +#if TELEMEGA +			       ao_mpu6000_gyro(ao_sample_roll_angle) / 100.0, +			       ao_mpu6000_gyro(ao_sample_angle) / 100.0, +			       ao_sample_qangle, +			       ao_mpu6000_accel(ao_data_static.mpu6000.accel_x), +			       ao_mpu6000_accel(ao_data_static.mpu6000.accel_y), +			       ao_mpu6000_accel(ao_data_static.mpu6000.accel_z), +			       ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x), +			       ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y), +			       ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z), +#endif  			       ao_state_names[ao_flight_state],  			       ao_k_height / 65536.0,  			       ao_k_speed / 65536.0 / 16.0, @@ -469,7 +530,6 @@ union ao_telemetry_all {  uint16_t  uint16(uint8_t *bytes, int off)  { -	off++;  	return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);  } @@ -479,6 +539,223 @@ int16(uint8_t *bytes, int off)  	return (int16_t) uint16(bytes, off);  } +uint32_t +uint32(uint8_t *bytes, int off) +{ +	return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) | +		(((uint32_t) bytes[off+2]) << 16) | +		(((uint32_t) bytes[off+3]) << 24); +} + +int32_t +int32(uint8_t *bytes, int off) +{ +	return (int32_t) uint32(bytes, off); +} + +static int log_format; + +#if TELEMEGA + +static double +ao_vec_norm(double x, double y, double z) +{ +	return x*x + y*y + z*z; +} + +static void +ao_vec_normalize(double *x, double *y, double *z) +{ +	double	scale = 1/sqrt(ao_vec_norm(*x, *y, *z)); + +	*x *= scale; +	*y *= scale; +	*z *= scale; +} + +struct ao_quat { +	double	q0, q1, q2, q3; +}; + +static void +ao_quat_mul(struct ao_quat *r, struct ao_quat *a, struct ao_quat *b) +{ +	r->q0 = a->q0 * b->q0 - a->q1 * b->q1 - a->q2 * b->q2 - a->q3 * b->q3; +	r->q1 = a->q0 * b->q1 + a->q1 * b->q0 + a->q2 * b->q3 - a->q3 * b->q2; +	r->q2 = a->q0 * b->q2 - a->q1 * b->q3 + a->q2 * b->q0 + a->q3 * b->q1; +	r->q3 = a->q0 * b->q3 + a->q1 * b->q2 - a->q2 * b->q1 + a->q3 * b->q0; +} + +#if 0 +static void +ao_quat_scale(struct ao_quat *r, struct ao_quat *a, double s) +{ +	r->q0 = a->q0 * s; +	r->q1 = a->q1 * s; +	r->q2 = a->q2 * s; +	r->q3 = a->q3 * s; +} +#endif + +static void +ao_quat_conj(struct ao_quat *r, struct ao_quat *a) +{ +	r->q0 =  a->q0; +	r->q1 = -a->q1; +	r->q2 = -a->q2; +	r->q3 = -a->q3; +} + +static void +ao_quat_rot(struct ao_quat *r, struct ao_quat *a, struct ao_quat *q) +{ +	struct ao_quat	t; +	struct ao_quat	c; +	ao_quat_mul(&t, q, a); +	ao_quat_conj(&c, q); +	ao_quat_mul(r, &t, &c); +} + +static void +ao_quat_from_angle(struct ao_quat *r, +		   double x_rad, +		   double y_rad, +		   double z_rad) +{ +	double angle = sqrt (x_rad * x_rad + y_rad * y_rad + z_rad * z_rad); +	double s = sin(angle/2); +	double c = cos(angle/2); + +	r->q0 = c; +	r->q1 = x_rad * s / angle; +	r->q2 = y_rad * s / angle; +	r->q3 = z_rad * s / angle; +} + +static void +ao_quat_from_vector(struct ao_quat *r, double x, double y, double z) +{ +	ao_vec_normalize(&x, &y, &z); +	double	x_rad = atan2(z, y); +	double	y_rad = atan2(x, z); +	double	z_rad = atan2(y, x); + +	ao_quat_from_angle(r, x_rad, y_rad, z_rad); +} + +static double +ao_quat_norm(struct ao_quat *a) +{ +	return (a->q0 * a->q0 + +		a->q1 * a->q1 + +		a->q2 * a->q2 + +		a->q3 * a->q3); +} + +static void +ao_quat_normalize(struct ao_quat *a) +{ +	double	norm = ao_quat_norm(a); + +	if (norm) { +		double m = 1/sqrt(norm); + +		a->q0 *= m; +		a->q1 *= m; +		a->q2 *= m; +		a->q3 *= m; +	} +} + +static struct ao_quat	ao_up, ao_current; +static struct ao_quat	ao_orient; +static int		ao_orient_tick; + +void +set_orientation(double x, double y, double z, int tick) +{ +	struct ao_quat	t; + +	printf ("set_orientation %g %g %g\n", x, y, z); +	ao_quat_from_vector(&ao_orient, x, y, z); +	ao_up.q1 = ao_up.q2 = 0; +	ao_up.q0 = ao_up.q3 = sqrt(2)/2; +	ao_orient_tick = tick; + +	ao_orient.q0 = 1; +	ao_orient.q1 = 0; +	ao_orient.q2 = 0; +	ao_orient.q3 = 0; + +	printf ("orient (%g) %g %g %g up (%g) %g %g %g\n", +		ao_orient.q0, +		ao_orient.q1, +		ao_orient.q2, +		ao_orient.q3, +		ao_up.q0, +		ao_up.q1, +		ao_up.q2, +		ao_up.q3); + +	ao_quat_rot(&t, &ao_up, &ao_orient); +	printf ("pad orient (%g) %g %g %g\n", +		t.q0, +		t.q1, +		t.q2, +		t.q3); + +} + +void +update_orientation (double rate_x, double rate_y, double rate_z, int tick) +{ +	struct ao_quat	q_dot; +	double		lambda; +	double		dt = (tick - ao_orient_tick) / 100.0; + +	ao_orient_tick = tick; +  +//	lambda = 1 - ao_quat_norm(&ao_orient); +	lambda = 0; + +	q_dot.q0 = -0.5 * (ao_orient.q1 * rate_x + ao_orient.q2 * rate_y + ao_orient.q3 * rate_z) + lambda * ao_orient.q0; +	q_dot.q1 =  0.5 * (ao_orient.q0 * rate_x + ao_orient.q2 * rate_z - ao_orient.q3 * rate_y) + lambda * ao_orient.q1; +	q_dot.q2 =  0.5 * (ao_orient.q0 * rate_y + ao_orient.q3 * rate_x - ao_orient.q1 * rate_z) + lambda * ao_orient.q2; +	q_dot.q3 =  0.5 * (ao_orient.q0 * rate_z + ao_orient.q1 * rate_y - ao_orient.q2 * rate_x) + lambda * ao_orient.q3; + +#if 0 +	printf ("update_orientation %g %g %g (%g s)\n", rate_x, rate_y, rate_z, dt); +	printf ("q_dot (%g) %g %g %g\n", +		q_dot.q0, +		q_dot.q1, +		q_dot.q2, +		q_dot.q3); +#endif + +	ao_orient.q0 += q_dot.q0 * dt; +	ao_orient.q1 += q_dot.q1 * dt; +	ao_orient.q2 += q_dot.q2 * dt; +	ao_orient.q3 += q_dot.q3 * dt; + +	ao_quat_normalize(&ao_orient); + +	ao_quat_rot(&ao_current, &ao_up, &ao_orient); + +	ao_sample_qangle = 180 / M_PI * acos(ao_current.q3 * sqrt(2)); +#if 0 +	printf ("orient (%g) %g %g %g current (%g) %g %g %g\n", +		ao_orient.q0, +		ao_orient.q1, +		ao_orient.q2, +		ao_orient.q3, +		ao_current.q0, +		ao_current.q1, +		ao_current.q2, +		ao_current.q3); +#endif +} +#endif +  void  ao_sleep(void *wchan)  { @@ -497,7 +774,11 @@ ao_sleep(void *wchan)  		for (;;) {  			if (ao_records_read > 2 && ao_flight_state == ao_flight_startup)  			{ +#if TELEMEGA +				ao_data_static.mpu6000 = ao_ground_mpu6000; +#else  				ao_data_static.adc.accel = ao_flight_ground_accel; +#endif  				ao_insert();  				return;  			} @@ -519,13 +800,102 @@ ao_sleep(void *wchan)  				if (words[nword] == NULL)  					break;  			} -			if (nword == 4) { +#if TELEMEGA +			if (log_format == AO_LOG_FORMAT_TELEMEGA && nword == 30 && strlen(words[0]) == 1) { +				int	i; +				struct ao_ms5607_value	value; + +				type = words[0][0]; +				tick = strtoul(words[1], NULL, 16); +//				printf ("%c %04x", type, tick); +				for (i = 2; i < nword; i++) { +					bytes[i - 2] = strtoul(words[i], NULL, 16); +//					printf(" %02x", bytes[i-2]); +				} +//				printf ("\n"); +				switch (type) { +				case 'F': +					ao_flight_ground_accel = int16(bytes, 2); +					ao_flight_started = 1; +					ao_ground_pres = int32(bytes, 4); +					ao_ground_height = ao_pa_to_altitude(ao_ground_pres); +					break; +				case 'A': +					ao_data_static.tick = tick; +					ao_data_static.ms5607_raw.pres = int32(bytes, 0); +					ao_data_static.ms5607_raw.temp = int32(bytes, 4); +					ao_ms5607_convert(&ao_data_static.ms5607_raw, &value); +					ao_data_static.mpu6000.accel_x = int16(bytes, 8); +					ao_data_static.mpu6000.accel_y = -int16(bytes, 10); +					ao_data_static.mpu6000.accel_z = int16(bytes, 12); +					ao_data_static.mpu6000.gyro_x = int16(bytes, 14); +					ao_data_static.mpu6000.gyro_y = -int16(bytes, 16); +					ao_data_static.mpu6000.gyro_z = int16(bytes, 18); +#if HAS_MMA655X +					ao_data_static.mma655x = int16(bytes, 26); +#endif +					if (ao_records_read == 0) +						ao_ground_mpu6000 = ao_data_static.mpu6000; +					else if (ao_records_read < 10) { +#define f(f) ao_ground_mpu6000.f = ao_ground_mpu6000.f + ((ao_data_static.mpu6000.f - ao_ground_mpu6000.f) >> 2) +						f(accel_x); +						f(accel_y); +						f(accel_z); +						f(gyro_x); +						f(gyro_y); +						f(gyro_z); + +						double		accel_x = ao_mpu6000_accel(ao_ground_mpu6000.accel_x); +						double		accel_y = ao_mpu6000_accel(ao_ground_mpu6000.accel_y); +						double		accel_z = ao_mpu6000_accel(ao_ground_mpu6000.accel_z); + +						/* X and Y are in the ground plane, arbitraryily picked as MPU X and Z axes +						 * Z is normal to the ground, the MPU y axis +						 */ +						set_orientation(accel_x, accel_z, accel_y, tick); +					} else { +						double		rate_x = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x); +						double		rate_y = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y); +						double		rate_z = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z); + +						update_orientation(rate_x * M_PI / 180, rate_z * M_PI / 180, rate_y * M_PI / 180, tick); +					} +					ao_records_read++; +					ao_insert(); +					return; +				} +				continue; +			} else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { +				if (strcmp(words[1], "reserved:") == 0) +					ms5607_prom.reserved = strtoul(words[2], NULL, 10); +				else if (strcmp(words[1], "sens:") == 0) +					ms5607_prom.sens = strtoul(words[2], NULL, 10); +				else if (strcmp(words[1], "off:") == 0) +					ms5607_prom.off = strtoul(words[2], NULL, 10); +				else if (strcmp(words[1], "tcs:") == 0) +					ms5607_prom.tcs = strtoul(words[2], NULL, 10); +				else if (strcmp(words[1], "tco:") == 0) +					ms5607_prom.tco = strtoul(words[2], NULL, 10); +				else if (strcmp(words[1], "tref:") == 0) +					ms5607_prom.tref = strtoul(words[2], NULL, 10); +				else if (strcmp(words[1], "tempsens:") == 0) +					ms5607_prom.tempsens = strtoul(words[2], NULL, 10); +				else if (strcmp(words[1], "crc:") == 0) +					ms5607_prom.crc = strtoul(words[2], NULL, 10); +				continue; +			} +#else +			if (nword == 4 && log_format != AO_LOG_FORMAT_TELEMEGA) {  				type = words[0][0];  				tick = strtoul(words[1], NULL, 16);  				a = strtoul(words[2], NULL, 16);  				b = strtoul(words[3], NULL, 16);  				if (type == 'P')  					type = 'A'; +			} +#endif +			else if (nword == 2 && strcmp(words[0], "log-format") == 0) { +				log_format = strtoul(words[1], NULL, 10);  			} else if (nword >= 6 && strcmp(words[0], "Accel") == 0) {  				ao_config.accel_plus_g = atoi(words[3]);  				ao_config.accel_minus_g = atoi(words[5]); @@ -608,22 +978,22 @@ ao_sleep(void *wchan)  					}  				} else if (len == 99) {  					ao_flight_started = 1; -					tick = uint16(bytes, 21); -					ao_flight_ground_accel = int16(bytes, 7); -					ao_config.accel_plus_g = int16(bytes, 17); -					ao_config.accel_minus_g = int16(bytes, 19); +					tick = uint16(bytes+1, 21); +					ao_flight_ground_accel = int16(bytes+1, 7); +					ao_config.accel_plus_g = int16(bytes+1, 17); +					ao_config.accel_minus_g = int16(bytes+1, 19);  					type = 'A'; -					a = int16(bytes, 23); -					b = int16(bytes, 25); +					a = int16(bytes+1, 23); +					b = int16(bytes+1, 25);  				} else if (len == 98) {  					ao_flight_started = 1; -					tick = uint16(bytes, 20); -					ao_flight_ground_accel = int16(bytes, 6); -					ao_config.accel_plus_g = int16(bytes, 16); -					ao_config.accel_minus_g = int16(bytes, 18); +					tick = uint16(bytes+1, 20); +					ao_flight_ground_accel = int16(bytes+1, 6); +					ao_config.accel_plus_g = int16(bytes+1, 16); +					ao_config.accel_minus_g = int16(bytes+1, 18);  					type = 'A'; -					a = int16(bytes, 22); -					b = int16(bytes, 24); +					a = int16(bytes+1, 22); +					b = int16(bytes+1, 24);  				} else {  					printf("unknown len %d\n", len);  					continue; @@ -632,6 +1002,10 @@ ao_sleep(void *wchan)  			if (type != 'F' && !ao_flight_started)  				continue; +#if TELEMEGA +			(void) a; +			(void) b; +#else  			switch (type) {  			case 'F':  				ao_flight_ground_accel = a; @@ -667,6 +1041,7 @@ ao_sleep(void *wchan)  			case 'H':  				break;  			} +#endif  		}  	} diff --git a/src/test/ao_gps_test.c b/src/test/ao_gps_test.c index d75a12ec..3844a326 100644 --- a/src/test/ao_gps_test.c +++ b/src/test/ao_gps_test.c @@ -88,6 +88,7 @@ ao_mutex_put(uint8_t *mutex)  static int  ao_gps_fd; +#if 0  static void  ao_dbg_char(char c)  { @@ -103,6 +104,7 @@ ao_dbg_char(char c)  	}  	write(1, line, strlen(line));  } +#endif  #define QUEUE_LEN	4096 @@ -391,6 +393,7 @@ ao_serial1_putchar(char c)  #define AO_SERIAL_SPEED_4800	0  #define AO_SERIAL_SPEED_57600	1 +#define AO_SERIAL_SPEED_115200	2  static void  ao_serial1_set_speed(uint8_t speed) @@ -407,6 +410,9 @@ ao_serial1_set_speed(uint8_t speed)  	case AO_SERIAL_SPEED_57600:  		cfsetspeed(&termios, B57600);  		break; +	case AO_SERIAL_SPEED_115200: +		cfsetspeed(&termios, B115200); +		break;  	}  	tcsetattr(fd, TCSAFLUSH, &termios);  	tcflush(fd, TCIFLUSH); @@ -420,7 +426,6 @@ ao_serial1_set_speed(uint8_t speed)  void  ao_dump_state(void *wchan)  { -	double	lat, lon;  	int	i;  	if (wchan == &ao_gps_data)  		ao_gps_print(&ao_gps_data); @@ -510,4 +515,5 @@ main (int argc, char **argv)  	}  	ao_gps_setup();  	ao_gps(); +	return 0;  } diff --git a/src/test/ao_gps_test_skytraq.c b/src/test/ao_gps_test_skytraq.c index 846daa94..81008b39 100644 --- a/src/test/ao_gps_test_skytraq.c +++ b/src/test/ao_gps_test_skytraq.c @@ -397,6 +397,7 @@ ao_serial1_putchar(char c)  #define AO_SERIAL_SPEED_4800	0  #define AO_SERIAL_SPEED_9600	1  #define AO_SERIAL_SPEED_57600	2 +#define AO_SERIAL_SPEED_115200	3  static void  ao_serial1_set_speed(uint8_t speed) @@ -411,11 +412,14 @@ ao_serial1_set_speed(uint8_t speed)  		cfsetspeed(&termios, B4800);  		break;  	case AO_SERIAL_SPEED_9600: -		cfsetspeed(&termios, B38400); +		cfsetspeed(&termios, B9600);  		break;  	case AO_SERIAL_SPEED_57600:  		cfsetspeed(&termios, B57600);  		break; +	case AO_SERIAL_SPEED_115200: +		cfsetspeed(&termios, B115200); +		break;  	}  	tcsetattr(fd, TCSAFLUSH, &termios);  	tcflush(fd, TCIFLUSH); @@ -423,6 +427,10 @@ ao_serial1_set_speed(uint8_t speed)  #define ao_time() 0 +uint8_t	ao_task_minimize_latency; + +#define ao_usb_getchar()	0 +  #include "ao_gps_print.c"  #include "ao_gps_skytraq.c" diff --git a/src/test/ao_gps_test_ublox.c b/src/test/ao_gps_test_ublox.c new file mode 100644 index 00000000..80671735 --- /dev/null +++ b/src/test/ao_gps_test_ublox.c @@ -0,0 +1,409 @@ +/* + * Copyright © 2009 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. + */ + +#define AO_GPS_TEST +#include "ao_host.h" +#include <termios.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#define AO_GPS_NUM_SAT_MASK	(0xf << 0) +#define AO_GPS_NUM_SAT_SHIFT	(0) + +#define AO_GPS_VALID		(1 << 4) +#define AO_GPS_RUNNING		(1 << 5) +#define AO_GPS_DATE_VALID	(1 << 6) +#define AO_GPS_COURSE_VALID	(1 << 7) + +struct ao_telemetry_location { +	uint8_t			year; +	uint8_t			month; +	uint8_t			day; +	uint8_t			hour; +	uint8_t			minute; +	uint8_t			second; +	uint8_t			flags; +	int32_t			latitude;	/* degrees * 10⁷ */ +	int32_t			longitude;	/* degrees * 10⁷ */ +	int16_t			altitude;	/* m */ +	uint16_t		ground_speed;	/* cm/s */ +	uint8_t			course;		/* degrees / 2 */ +	uint8_t			pdop;		/* * 5 */ +	uint8_t			hdop;		/* * 5 */ +	uint8_t			vdop;		/* * 5 */ +	int16_t			climb_rate;	/* cm/s */ +	uint16_t		h_error;	/* m */ +	uint16_t		v_error;	/* m */ +}; + +#define UBLOX_SAT_STATE_ACQUIRED		(1 << 0) +#define UBLOX_SAT_STATE_CARRIER_PHASE_VALID	(1 << 1) +#define UBLOX_SAT_BIT_SYNC_COMPLETE		(1 << 2) +#define UBLOX_SAT_SUBFRAME_SYNC_COMPLETE	(1 << 3) +#define UBLOX_SAT_CARRIER_PULLIN_COMPLETE	(1 << 4) +#define UBLOX_SAT_CODE_LOCKED			(1 << 5) +#define UBLOX_SAT_ACQUISITION_FAILED		(1 << 6) +#define UBLOX_SAT_EPHEMERIS_AVAILABLE		(1 << 7) + +struct ao_telemetry_satellite_info { +	uint8_t		svid; +	uint8_t		c_n_1; +}; + +#define AO_TELEMETRY_SATELLITE_MAX_SAT	12 + +struct ao_telemetry_satellite { +	uint8_t					channels; +	struct ao_telemetry_satellite_info	sats[AO_TELEMETRY_SATELLITE_MAX_SAT]; +}; + +#define ao_gps_orig ao_telemetry_location +#define ao_gps_tracking_orig ao_telemetry_satellite +#define ao_gps_sat_orig ao_telemetry_satellite_info + +void +ao_mutex_get(uint8_t *mutex) +{ +} + +void +ao_mutex_put(uint8_t *mutex) +{ +} + +static int ao_gps_fd; +static FILE *ao_gps_file; + +#if 0 +static void +ao_dbg_char(char c) +{ +	char	line[128]; +	line[0] = '\0'; +	if (c < ' ') { +		if (c == '\n') +			sprintf (line, "\n"); +		else +			sprintf (line, "\\%02x", ((int) c) & 0xff); +	} else { +		sprintf (line, "%c", c); +	} +	write(1, line, strlen(line)); +} +#endif + +#include <sys/time.h> + +int +get_millis(void) +{ +	struct timeval	tv; +	gettimeofday(&tv, NULL); +	return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static uint8_t	in_message[4096]; +static int	in_len; +static uint16_t	recv_len; + +static void check_ublox_message(char *which, uint8_t *msg); + +char +ao_serial1_getchar(void) +{ +	char	c; +	uint8_t	uc; +	int	i; + +	i = getc(ao_gps_file); +	if (i == EOF) { +		perror("getchar"); +		exit(1); +	} +	c = i; +	uc = (uint8_t) c; +	if (in_len || uc == 0xb5) { +		in_message[in_len++] = c; +		if (in_len == 6) { +			recv_len = in_message[4] | (in_message[5] << 8); +		} else if (in_len > 6 && in_len == recv_len + 8) { +			check_ublox_message("recv", in_message + 2); +			in_len = 0; +		} +		 +	} +	return c; +} + +#define MESSAGE_LEN	4096 + +static uint8_t	message[MESSAGE_LEN]; +static int	message_len; +static uint16_t	send_len; + +void +ao_serial1_putchar(char c) +{ +	int	i; +	uint8_t	uc = (uint8_t) c; + +	if (message_len || uc == 0xb5) { +		if (message_len < MESSAGE_LEN) +			message[message_len++] = uc; +		if (message_len == 6) { +			send_len = message[4] | (message[5] << 8); +		} else if (message_len > 6 && message_len == send_len + 8) { +			check_ublox_message("send", message + 2); +			message_len = 0; +		} +	} + +	for (;;) { +		i = write(ao_gps_fd, &c, 1); +		if (i == 1) +			break; +		if (i < 0 && (errno == EINTR || errno == EAGAIN)) +			continue; +		perror("putchar"); +		exit(1); +	} +} + +#define AO_SERIAL_SPEED_4800	0 +#define AO_SERIAL_SPEED_9600	1 +#define AO_SERIAL_SPEED_57600	2 +#define AO_SERIAL_SPEED_115200	3 + +static void +ao_serial1_set_speed(uint8_t speed) +{ +	int	fd = ao_gps_fd; +	struct termios	termios; + +	printf ("\t\tset speed %d\n", speed); +	tcdrain(fd); +	tcgetattr(fd, &termios); +	switch (speed) { +	case AO_SERIAL_SPEED_4800: +		cfsetspeed(&termios, B4800); +		break; +	case AO_SERIAL_SPEED_9600: +		cfsetspeed(&termios, B9600); +		break; +	case AO_SERIAL_SPEED_57600: +		cfsetspeed(&termios, B57600); +		break; +	case AO_SERIAL_SPEED_115200: +		cfsetspeed(&termios, B115200); +		break; +	} +	tcsetattr(fd, TCSAFLUSH, &termios); +	tcflush(fd, TCIFLUSH); +} + +#define ao_time() 0 + +uint8_t	ao_task_minimize_latency; + +#define ao_usb_getchar()	0 + +#include "ao_gps_print.c" +#include "ao_gps_ublox.c" + +static void +check_ublox_message(char *which, uint8_t *msg) +{ +	uint8_t	class = msg[0]; +	uint8_t	id = msg[1]; +	uint16_t len = msg[2] | (msg[3] << 8); +	uint16_t i; +	struct ao_ublox_cksum	cksum_msg = { .a = msg[4 + len], +					      .b = msg[4 + len + 1] }; +	struct ao_ublox_cksum	cksum= { 0, 0 }; + +	for (i = 0; i < 4 + len; i++) { +		add_cksum(&cksum, msg[i]); +	} +	if (cksum.a != cksum_msg.a || cksum.b != cksum_msg.b) { +		printf ("\t%s: cksum mismatch %02x,%02x != %02x,%02x\n", +			which, +			cksum_msg.a & 0xff, +			cksum_msg.b & 0xff, +			cksum.a & 0xff, +			cksum.b & 0xff); +		return; +	} +	switch (class) { +	case UBLOX_NAV: +		switch (id) { +		case UBLOX_NAV_DOP: ; +			struct ublox_nav_dop	*nav_dop = (void *) msg; +			printf ("\tnav-dop    iTOW %9u gDOP %5u dDOP %5u tDOP %5u vDOP %5u hDOP %5u nDOP %5u eDOP %5u\n", +				nav_dop->itow, +				nav_dop->gdop, +				nav_dop->ddop, +				nav_dop->tdop, +				nav_dop->vdop, +				nav_dop->hdop, +				nav_dop->ndop, +				nav_dop->edop); +			return; +		case UBLOX_NAV_POSLLH: ; +			struct ublox_nav_posllh	*nav_posllh = (void *) msg; +			printf ("\tnav-posllh iTOW %9u lon %12.7f lat %12.7f height %10.3f hMSL %10.3f hAcc %10.3f vAcc %10.3f\n", +				nav_posllh->itow, +				nav_posllh->lon / 1e7, +				nav_posllh->lat / 1e7, +				nav_posllh->height / 1e3, +				nav_posllh->hmsl / 1e3, +				nav_posllh->hacc / 1e3, +				nav_posllh->vacc / 1e3); +			return; +		case UBLOX_NAV_SOL: ; +			struct ublox_nav_sol	*nav_sol = (struct ublox_nav_sol *) msg; +			printf ("\tnav-sol    iTOW %9u fTOW %9d week %5d gpsFix %2d flags %02x\n", +				nav_sol->itow, nav_sol->ftow, nav_sol->week, +				nav_sol->gpsfix, nav_sol->flags); +			return; +		case UBLOX_NAV_SVINFO: ; +			struct ublox_nav_svinfo	*nav_svinfo = (struct ublox_nav_svinfo *) msg; +			printf ("\tnav-svinfo iTOW %9u numCH %3d globalFlags %02x\n", +				nav_svinfo->itow, nav_svinfo->numch, nav_svinfo->globalflags); +			int i; +			for (i = 0; i < nav_svinfo->numch; i++) { +				struct ublox_nav_svinfo_block *nav_svinfo_block = (void *) (msg + 12 + 12 * i); +				printf ("\t\tchn %3u svid %3u flags %02x quality %3u cno %3u elev %3d azim %6d prRes %9d\n", +					nav_svinfo_block->chn, +					nav_svinfo_block->svid, +					nav_svinfo_block->flags, +					nav_svinfo_block->quality, +					nav_svinfo_block->cno, +					nav_svinfo_block->elev, +					nav_svinfo_block->azim, +					nav_svinfo_block->prres); +			} +			return; +		case UBLOX_NAV_VELNED: ; +			struct ublox_nav_velned *nav_velned = (void *) msg; +			printf ("\tnav-velned iTOW %9u velN %10.2f velE %10.2f velD %10.2f speed %10.2f gSpeed %10.2f heading %10.5f sAcc %10.2f cAcc %10.5f\n", +				nav_velned->itow, +				nav_velned->veln / 1e2, +				nav_velned->vele / 1e2, +				nav_velned->veld / 1e2, +				nav_velned->speed / 1e2, +				nav_velned->gspeed / 1e2, +				nav_velned->heading / 1e5, +				nav_velned->sacc / 1e5, +				nav_velned->cacc / 1e6); +			return; +		case UBLOX_NAV_TIMEUTC:; +			struct ublox_nav_timeutc *nav_timeutc = (void *) msg; +			printf ("\tnav-timeutc iTOW %9u tAcc %5u nano %5d %4u-%2d-%2d %2d:%02d:%02d flags %02x\n", +				nav_timeutc->itow, +				nav_timeutc->tacc, +				nav_timeutc->nano, +				nav_timeutc->year, +				nav_timeutc->month, +				nav_timeutc->day, +				nav_timeutc->hour, +				nav_timeutc->min, +				nav_timeutc->sec, +				nav_timeutc->valid); +			return; +		} +		break; +	} +#if 1 +	printf ("\t%s: class %02x id %02x len %d:", which, class & 0xff, id & 0xff, len & 0xffff); +	for (i = 0; i < len; i++) +		printf (" %02x", msg[4 + i]); +	printf (" cksum %02x %02x", cksum_msg.a & 0xff, cksum_msg.b & 0xff); +#endif +	printf ("\n"); +} + +void +ao_dump_state(void *wchan) +{ +	if (wchan == &ao_gps_data) +		ao_gps_print(&ao_gps_data); +	else +		ao_gps_tracking_print(&ao_gps_tracking_data); +	putchar('\n'); +	return; +} + +int +ao_gps_open(const char *tty) +{ +	struct termios	termios; +	int fd; + +	fd = open (tty, O_RDWR); +	if (fd < 0) +		return -1; + +	tcgetattr(fd, &termios); +	cfmakeraw(&termios); +	cfsetspeed(&termios, B4800); +	tcsetattr(fd, TCSAFLUSH, &termios); + +	tcdrain(fd); +	tcflush(fd, TCIFLUSH); +	return fd; +} + +#include <getopt.h> + +static const struct option options[] = { +	{ .name = "tty", .has_arg = 1, .val = 'T' }, +	{ 0, 0, 0, 0}, +}; + +static void usage(char *program) +{ +	fprintf(stderr, "usage: %s [--tty <tty-name>]\n", program); +	exit(1); +} + +int +main (int argc, char **argv) +{ +	char	*tty = "/dev/ttyUSB0"; +	int	c; + +	while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) { +		switch (c) { +		case 'T': +			tty = optarg; +			break; +		default: +			usage(argv[0]); +			break; +		} +	} +	ao_gps_fd = ao_gps_open(tty); +	if (ao_gps_fd < 0) { +		perror (tty); +		exit (1); +	} +	ao_gps_file = fdopen(ao_gps_fd, "r"); +	ao_gps(); +	return 0; +} diff --git a/src/test/ao_micropeak_test.c b/src/test/ao_micropeak_test.c new file mode 100644 index 00000000..5961bd93 --- /dev/null +++ b/src/test/ao_micropeak_test.c @@ -0,0 +1,220 @@ +/* + * Copyright © 2009 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. + */ + +#define _GNU_SOURCE + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <math.h> + +FILE *emulator_in; +char *emulator_app; +char *emulator_name; +char *emulator_info; +uint8_t ao_flight_debug; + +#define AO_FLIGHT_TEST + +typedef int32_t alt_t; + +#define AO_MS_TO_TICKS(ms)	((ms) / 10) + +#define AO_LED_REPORT 0 + +static void ao_led_on(uint8_t led) { +} + +static void ao_led_off(uint8_t led) { +} + +static void ao_delay_until(uint16_t target) { +} + +static uint16_t ao_time(void) { +	return 0; +} + +#include "ao_microflight.c" +#include "ao_microkalman.c" +#include "ao_convert_pa.c" + +uint16_t	now; +uint8_t		running; + +void ao_log_micro_data() { +	running = 1; +} + +void +ao_micro_report(void) +{ +	if (running) { +		alt_t	ground = ao_pa_to_altitude(pa_ground); +		printf ("%6.3f %10d %10d %10d %10d %10d\n", now / 100.0, +			ao_pa_to_altitude(pa) - ground, +			ao_pa_to_altitude(ao_pa) - ground, +			ao_pa_to_altitude(pa_min) - ground, +			ao_pa_speed, ao_pa_accel); +	} +} + +void +ao_micro_finish(void) +{ +	ao_micro_report(); +} + +void +ao_pa_get(void) +{ +	char	line[4096]; +	char	*toks[128]; +	char	*saveptr; +	int	t, ntok; +	static int	time_id; +	static int	pa_id; +	double		time; +	double		pressure; +	static double	last_time; +	static double	last_pressure; +	static int	been_here; +	static int	start_samples; +	static int	is_mp; +	static int	use_saved; + +	if (been_here && start_samples < 100) { +		start_samples++; +		return; +	} +	ao_micro_report(); +	if (use_saved) { +		pa = last_pressure; +		now = last_time; +		use_saved = 0; +//		printf ("use saved %d %d\n", now, pa); +		return; +	} +	for (;;) { +		if (!fgets(line, sizeof (line), emulator_in)) +			exit(0); +		for (t = 0; t < 128; t++) { +			toks[t] = strtok_r(t ? NULL : line, ", ", &saveptr); +			if (!toks[t]) +				break; +		} +		ntok = t; +		if (toks[0][0] == '#') { +			if (strcmp(toks[0],"#version") == 0) { +				for (t = 1; t < ntok; t++) { +					if (!strcmp(toks[t], "time")) +						time_id = t; +					if (!strcmp(toks[t],"pressure")) +						pa_id = t; +				} +			} +			continue; +		} else if (!strcmp(toks[0], "Time")) { +			time_id = 0; +			pa_id = 1; +			is_mp = 1; +			continue; +		} +		time = strtod(toks[time_id],NULL); +		pressure = strtod(toks[pa_id],NULL); +		time *= 100; +		if (been_here && time - last_time < 0.096 * 100) +			continue; +		if (is_mp && been_here) { +			double	avg_pressure = (pressure + last_pressure) / 2.0; +			double	avg_time = (time + last_time) / 2.0; + +			now = avg_time; +			pa = avg_pressure; +//			printf ("new %d %d\n", now, pa); +			use_saved = 1; +		} else { +			now = floor (time + 0.5); +			pa = pressure; +		} +		last_pressure = pressure; +		last_time = time; +		been_here = 1; +		break; +	} +} + +void +ao_dump_state(void) +{ +} + +static const struct option options[] = { +	{ .name = "summary", .has_arg = 0, .val = 's' }, +	{ .name = "debug", .has_arg = 0, .val = 'd' }, +	{ .name = "info", .has_arg = 1, .val = 'i' }, +	{ 0, 0, 0, 0}, +}; + +void run_flight_fixed(char *name, FILE *f, int summary, char *info) +{ +	emulator_name = name; +	emulator_in = f; +	emulator_info = info; +	ao_microflight(); +	ao_micro_finish(); +} + +int +main (int argc, char **argv) +{ +	int	summary = 0; +	int	c; +	int	i; +	char	*info = NULL; + +	emulator_app="baro"; +	while ((c = getopt_long(argc, argv, "sdi:", options, NULL)) != -1) { +		switch (c) { +		case 's': +			summary = 1; +			break; +		case 'd': +			ao_flight_debug = 1; +			break; +		case 'i': +			info = optarg; +			break; +		} +	} + +	if (optind == argc) +		run_flight_fixed("<stdin>", stdin, summary, info); +	else +		for (i = optind; i < argc; i++) { +			FILE	*f = fopen(argv[i], "r"); +			if (!f) { +				perror(argv[i]); +				continue; +			} +			run_flight_fixed(argv[i], f, summary, info); +			fclose(f); +		} +	exit(0); +} diff --git a/src/test/plotmicro b/src/test/plotmicro new file mode 100755 index 00000000..bb8f4d1d --- /dev/null +++ b/src/test/plotmicro @@ -0,0 +1,16 @@ +#!/bin/sh +for i in "$@"; do +gnuplot -p << EOF & +set title "$i" +set ylabel "height (m)" +set y2label "accel (m/s²)" +set xlabel "time (s)" +set xtics border out nomirror +set ytics border out nomirror +set y2tics border out nomirror +plot "$i" using 1:2 with lines lt 2 axes x1y1 title "raw height",\ +     "$i" using 1:3 with lines lt 4 axes x1y1 title "kalman height",\ +     "$i" using 1:4 with lines lt 1 axes x1y1 title "max height",\ +     "$i" using 1:6 with lines lt 3 axes x1y2 title "pa accel" +EOF +done diff --git a/src/test/plotmm b/src/test/plotmm new file mode 100755 index 00000000..5f5bd2ca --- /dev/null +++ b/src/test/plotmm @@ -0,0 +1,11 @@ +gnuplot -persist << EOF +set ylabel "altitude (m)" +set y2label "angle (d)" +set xlabel "time (s)" +set xtics border out nomirror +set ytics border out nomirror +set y2tics border out nomirror +plot "$1" using 1:3 with lines axes x1y1 title "raw height",\ +"$1" using 1:9 with lines axes x1y2 title "angle",\ +"$1" using 1:11 with lines axes x1y2 title "qangle" +EOF diff --git a/src/test/run-mm b/src/test/run-mm new file mode 100755 index 00000000..6f3d97a2 --- /dev/null +++ b/src/test/run-mm @@ -0,0 +1,41 @@ +#!/bin/sh + +DIR=~/misc/rockets/flights + +for i in "$@"; do +case "$i" in +    */*) +    file="$i" +    ;; +    *) +    file="$DIR/$i" +    ;; +esac +./ao_flight_test_mm "$file" > run-out.mm + +#./ao_flight_test_accel "$file" > run-out.accel +#"run-out.accel" using 1:9 with lines lt 4 axes x1y1 title "accel height",\ +#"run-out.accel" using 1:11 with lines lt 4 axes x1y2 title "accel speed",\ +#"run-out.accel" using 1:13 with lines lt 4 axes x1y2 title "accel accel",\ +#"run-out.accel" using 1:15 with lines lt 4 axes x1y1 title "accel drogue",\ +#"run-out.accel" using 1:17 with lines lt 4 axes x1y1 title "accel main",\ +# + +gnuplot << EOF +set ylabel "altitude (m)" +set y2label "velocity (m/s), acceleration(m/s²)" +set xlabel "time (s)" +set xtics border out nomirror +set ytics border out nomirror +set y2tics border out nomirror +set title "$i" +plot "run-out.mm" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ +"run-out.mm" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\ +"run-out.mm" using 1:21 with lines lt 2 axes x1y1 title "mm height",\ +"run-out.mm" using 1:23 with lines lt 2 axes x1y2 title "mm speed",\ +"run-out.mm" using 1:25 with lines lt 2 axes x1y2 title "mm accel",\ +"run-out.mm" using 1:29 with lines lt 2 axes x1y1 title "mm drogue",\ +"run-out.mm" using 1:31 with lines lt 2 axes x1y1 title "mm main" +pause mouse close +EOF +done
\ No newline at end of file  | 
