From 84c93bb2fc4558a5e4654794ba90e730a84eaf67 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 20 Feb 2010 20:22:16 -0800 Subject: Change altos build process to support per-product compile-time changes This creates per-product subdirectories and recompiles everything for each product, allowing per-product compile-time changes for things like peripheral pin assignments and attached serial devices. Signed-off-by: Keith Packard --- src/test/Makefile | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/Makefile (limited to 'src/test') diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 00000000..f6e9b9f5 --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,24 @@ +vpath % .. + +PROGS=ao_flight_test ao_gps_test ao_gps_test_skytraq ao_convert_test + +CFLAGS=-I.. -I. + +all: $(PROGS) + +clean: + rm -f $(PROGS) + +install: + +ao_flight_test: ao_flight_test.c ao_flight_test.c ao_host.h + cc -g -o $@ $< + +ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h + cc -g -o $@ $< + +ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_host.h + cc -g -o $@ $< + +ao_convert_test: ao_convert_test.c ao_convert.c altitude.h + cc -g -o $@ $< -- cgit v1.2.3 From 004c2a9b7a4b44ef71ca60482573e8e9d8c6ce93 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 20 Feb 2010 20:36:08 -0800 Subject: Update .gitignore files --- .gitignore | 7 ++----- debian/.gitignore | 6 ++++++ src/teledongle-v0.1/.gitignore | 2 ++ src/teledongle-v0.2/.gitignore | 2 ++ src/telemetrum-v0.1-sirf/.gitignore | 2 ++ src/telemetrum-v0.1-sky/.gitignore | 2 ++ src/telemetrum-v0.2/.gitignore | 2 ++ src/test/.gitignore | 4 ++++ src/tidongle/.gitignore | 2 ++ 9 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 debian/.gitignore create mode 100644 src/teledongle-v0.1/.gitignore create mode 100644 src/teledongle-v0.2/.gitignore create mode 100644 src/telemetrum-v0.1-sirf/.gitignore create mode 100644 src/telemetrum-v0.1-sky/.gitignore create mode 100644 src/telemetrum-v0.2/.gitignore create mode 100644 src/test/.gitignore create mode 100644 src/tidongle/.gitignore (limited to 'src/test') diff --git a/.gitignore b/.gitignore index a6f94439..eafee20f 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,8 @@ config.h.in config.h.in~ config.log config.status +build-stamp +configure-stamp configure depcomp install-sh @@ -47,8 +49,3 @@ Makefile.in missing stamp-h1 tags -teledongle -telemetrum-sirf -telemetrum-sky -teleterra -tidongle diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 00000000..850d7c20 --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,6 @@ +altos.debhelper.log +altos.postinst.debhelper +altos.postrm.debhelper +altos.substvars +altos +files diff --git a/src/teledongle-v0.1/.gitignore b/src/teledongle-v0.1/.gitignore new file mode 100644 index 00000000..96c802bd --- /dev/null +++ b/src/teledongle-v0.1/.gitignore @@ -0,0 +1,2 @@ +teledongle-v0.1 +ao_product.h diff --git a/src/teledongle-v0.2/.gitignore b/src/teledongle-v0.2/.gitignore new file mode 100644 index 00000000..af79a766 --- /dev/null +++ b/src/teledongle-v0.2/.gitignore @@ -0,0 +1,2 @@ +teledongle-v0.2 +ao_product.h diff --git a/src/telemetrum-v0.1-sirf/.gitignore b/src/telemetrum-v0.1-sirf/.gitignore new file mode 100644 index 00000000..6d584f36 --- /dev/null +++ b/src/telemetrum-v0.1-sirf/.gitignore @@ -0,0 +1,2 @@ +telemetrum-v0.1-sirf +ao_product.h diff --git a/src/telemetrum-v0.1-sky/.gitignore b/src/telemetrum-v0.1-sky/.gitignore new file mode 100644 index 00000000..5a9fafb5 --- /dev/null +++ b/src/telemetrum-v0.1-sky/.gitignore @@ -0,0 +1,2 @@ +telemetrum-v0.1-sky +ao_product.h diff --git a/src/telemetrum-v0.2/.gitignore b/src/telemetrum-v0.2/.gitignore new file mode 100644 index 00000000..76228093 --- /dev/null +++ b/src/telemetrum-v0.2/.gitignore @@ -0,0 +1,2 @@ +telemetrum-v0.2 +ao_product.h diff --git a/src/test/.gitignore b/src/test/.gitignore new file mode 100644 index 00000000..54b00096 --- /dev/null +++ b/src/test/.gitignore @@ -0,0 +1,4 @@ +ao_flight_test +ao_gps_test +ao_gps_test_skytraq +ao_convert_test diff --git a/src/tidongle/.gitignore b/src/tidongle/.gitignore new file mode 100644 index 00000000..3323f640 --- /dev/null +++ b/src/tidongle/.gitignore @@ -0,0 +1,2 @@ +tidongle +ao_product.h -- cgit v1.2.3 From d3bc27fabb6159ce58b14d0f7929b0f46f67c378 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Feb 2011 09:54:01 -0800 Subject: altos/test: Add dependencies in the Makefile for ao_flight_test Yes, it would be nice to automate dependency generation here, but I can't be bothered. Signed-off-by: Keith Packard --- src/test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/test') diff --git a/src/test/Makefile b/src/test/Makefile index f6e9b9f5..cd9cafc8 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -11,7 +11,7 @@ clean: install: -ao_flight_test: ao_flight_test.c ao_flight_test.c ao_host.h +ao_flight_test: ao_flight_test.c ao_flight_test.c ao_host.h ao_flight.c altitude.h cc -g -o $@ $< ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h -- cgit v1.2.3 From 1e56ed44e562f808addfd76bfb352f981db94094 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Mar 2011 21:59:08 -0800 Subject: altos/test: Add baro-only flight test program This builds the flight code in baro-only mode for testing. Signed-off-by: Keith Packard --- src/ao_flight_test.c | 10 +++++++++- src/test/Makefile | 7 +++++-- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src/test') diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 70888d34..a635803f 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -72,6 +72,7 @@ uint8_t ao_adc_head; #define ao_telemetry_set_interval(x) #define ao_rdf_set(rdf) #define ao_packet_slave_start() +#define ao_packet_slave_stop() enum ao_igniter { ao_igniter_drogue = 0, @@ -138,8 +139,8 @@ struct ao_config ao_config; #define HAS_GPS 1 #ifndef HAS_ACCEL #define HAS_ACCEL 1 -#endif #define HAS_ACCEL_REF 0 +#endif #include "ao_flight.c" @@ -268,12 +269,19 @@ ao_dump_state(void) { if (ao_flight_state == ao_flight_startup) return; +#if HAS_ACCEL printf ("\t\t\t\t\t%s accel %g vel %g alt %d main %d\n", ao_state_names[ao_flight_state], (ao_ground_accel - ao_flight_accel) / COUNTS_PER_G * GRAVITY, (double) ao_flight_vel / 100 / COUNTS_PER_G * GRAVITY, ao_pres_to_altitude(ao_flight_pres) - ao_pres_to_altitude(ao_ground_pres), ao_pres_to_altitude(ao_main_pres) - ao_pres_to_altitude(ao_ground_pres)); +#else + printf ("\t\t\t\t\t%s alt %d main %d\n", + ao_state_names[ao_flight_state], + ao_pres_to_altitude(ao_flight_pres) - ao_pres_to_altitude(ao_ground_pres), + ao_pres_to_altitude(ao_main_pres) - ao_pres_to_altitude(ao_ground_pres)); +#endif if (ao_flight_state == ao_flight_landed) exit(0); } diff --git a/src/test/Makefile b/src/test/Makefile index cd9cafc8..853713fa 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,6 @@ vpath % .. -PROGS=ao_flight_test ao_gps_test ao_gps_test_skytraq ao_convert_test +PROGS=ao_flight_test ao_flight_test_baro ao_gps_test ao_gps_test_skytraq ao_convert_test CFLAGS=-I.. -I. @@ -11,9 +11,12 @@ clean: install: -ao_flight_test: ao_flight_test.c ao_flight_test.c ao_host.h ao_flight.c altitude.h +ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c altitude.h cc -g -o $@ $< +ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c altitude.h + cc -g -o $@ -DHAS_ACCEL=0 ../ao_flight_test.c + ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h cc -g -o $@ $< -- cgit v1.2.3 From 8b546b474b7b6c5b4169b4c1ca09c6f17ebb3ae5 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Fri, 11 Mar 2011 21:41:01 +1000 Subject: ignore new flight test file --- src/test/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test') diff --git a/src/test/.gitignore b/src/test/.gitignore index 54b00096..0a43de8a 100644 --- a/src/test/.gitignore +++ b/src/test/.gitignore @@ -1,4 +1,5 @@ ao_flight_test +ao_flight_test_baro ao_gps_test ao_gps_test_skytraq ao_convert_test -- cgit v1.2.3 From c985bb6a19c710409629f3c095332ba7afcf5248 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Mar 2011 20:36:59 -0700 Subject: altos/test: Add scripts to run lots of flights through the code This runs a long list of flights (there's a user-specific path pointing at the flights) and squawks if the baro and dual flight computers don't match. Signed-off-by: Keith Packard --- src/test/run-tests | 22 ++++++++++++++++ src/test/test-flights | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100755 src/test/run-tests create mode 100644 src/test/test-flights (limited to 'src/test') diff --git a/src/test/run-tests b/src/test/run-tests new file mode 100755 index 00000000..ec279776 --- /dev/null +++ b/src/test/run-tests @@ -0,0 +1,22 @@ +#!/bin/sh + +DIR=~/src/cc1111/flights + +while read flight; do + baro=`./ao_flight_test_baro -s $DIR/$flight | + awk '/drogue/ { printf "%s ", $4 } + /main/ { printf "%s\n", $4 }'` + full=`./ao_flight_test -s $DIR/$flight | + awk '/drogue/ { printf "%s ", $4 } + /main/ { printf "%s\n", $4 }'` + echo $flight $baro $full +done < test-flights | +awk '{ name = $1; + drogue_error = $2 - $4; + if (drogue_error < 0) drogue_error = -drogue_error; + main_error = $3 - $5; + if (main_error < 0) main_error = -main_error; + if (drogue_error > 4 || main_error > 4) + printf ("%s: baro drogue %f main %f. full drogue %f main %f\n", + name, $2, $3, $4, $5); + }' diff --git a/src/test/test-flights b/src/test/test-flights new file mode 100644 index 00000000..a9a2ecca --- /dev/null +++ b/src/test/test-flights @@ -0,0 +1,72 @@ +2009-06-03-serial-003-flight-002.eeprom +2009-06-05-serial-004-flight-008.eeprom +2009-06-06-serial-004-flight-009.eeprom +2009-06-14-serial-004-flight-010.eeprom +2009-06-20-serial-003-flight-003.eeprom +2009-07-04-serial-001-flight-006.eeprom +2009-07-18-serial-001-flight-007.eeprom +2009-08-22-serial-001-flight-001.eeprom +2009-08-22-serial-010-flight-001.eeprom +2009-09-05-serial-008-flight-002.eeprom +2009-09-05-serial-010-flight-002.eeprom +2009-09-05-serial-011-flight-001.eeprom +2009-09-11-serial-008-flight-003.eeprom +2009-09-12-serial-002-flight-002.eeprom +2009-09-12-serial-008-flight-005.eeprom +2009-09-12-serial-008-flight-007.eeprom +2009-09-19-serial-011-flight-002.eeprom +2009-10-03-serial-008-flight-009.eeprom +2009-10-03-serial-008-flight-010.eeprom +2009-10-03-serial-009-flight-001.eeprom +2009-10-03-serial-011-flight-003.eeprom +2009-10-17-serial-009-flight-002.eeprom +2009-11-14-serial-003-flight-005.eeprom +2009-11-14-serial-003-flight-006.eeprom +2009-11-21-serial-013-flight-001.eeprom +2009-11-21-serial-013-flight-002.eeprom +2010-02-13-serial-051-flight-002.eeprom +2010-02-13-serial-052-flight-002.eeprom +2010-02-28-serial-052-flight-003.eeprom +2010-02-28-serial-052-flight-004.eeprom +2010-03-06-serial-010-flight-004.eeprom +2010-03-06-serial-013-flight-003.eeprom +2010-03-06-serial-051-flight-003.eeprom +2010-03-06-serial-053-flight-004.eeprom +2010-05-08-serial-229-flight-002.eeprom +2010-05-28-serial-215-flight-002.eeprom +2010-05-28-serial-224-flight-001.eeprom +2010-05-29-serial-052-flight-005.eeprom +2010-05-30-serial-010-flight-005.eeprom +2010-05-30-serial-051-flight-004.eeprom +2010-05-30-serial-224-flight-003.eeprom +2010-05-30-serial-226-flight-001.eeprom +2010-05-31-serial-010-flight-006.eeprom +2010-05-31-serial-216-flight-001.eeprom +2010-05-31-serial-219-flight-001.eeprom +2010-05-31-serial-227-flight-003.eeprom +2010-06-05-serial-220-flight-001.eeprom +2010-06-26-serial-209-flight-003.eeprom +2010-06-26-serial-215-flight-004.eeprom +2010-06-26-serial-220-flight-002.eeprom +2010-06-26-serial-226-flight-002.eeprom +2010-06-27-serial-221-flight-002.eeprom +2010-07-17-serial-230-flight-001.eeprom +2010-07-18-serial-219-flight-002.eeprom +2010-08-07-serial-216-flight-003.eeprom +2010-08-07-serial-220-flight-003.eeprom +2010-08-12-serial-236-flight-001.eeprom +2010-08-21-serial-010-flight-007.eeprom +2010-08-21-serial-224-flight-004.eeprom +2010-08-21-serial-224-flight-005.eeprom +2010-08-21-serial-233-flight-002.eeprom +2010-09-03-serial-051-flight-005.eeprom +2010-09-03-serial-215-flight-005.eeprom +2010-09-24-serial-236-flight-006.eeprom +2010-09-25-serial-223-flight-001.eeprom +2010-10-17-serial-215-flight-006.eeprom +2010-10-23-serial-236-flight-008.eeprom +2011-01-30-serial-056-flight-001.eeprom +2011-01-30-serial-250-flight-002.eeprom +2011-02-19-serial-215-flight-007.eeprom +2011-02-19-serial-216-flight-006.eeprom +2011-02-19-serial-286-flight-001.eeprom -- cgit v1.2.3 From 7b009b2efe3af8722c358c304c2243652594e0d5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 22 Mar 2011 05:42:51 +0900 Subject: altos: Switch telemetrum over to kalman filter This changes the full telemetry stream to include kalman data instead of the old ad-hoc flight data. It's compatible in that the packet sizes are the same so teledongle can receive either and figure out which it has received. A few plotting and testing tools are added to make validating the new code easier. Signed-off-by: Keith Packard --- src/ao.h | 36 ++-- src/ao_flash.c | 8 +- src/ao_flight.c | 495 +++++++++++++++++++++--------------------------- src/ao_flight_test.c | 82 ++++---- src/ao_log_tiny.c | 2 +- src/ao_monitor.c | 34 ++-- src/ao_pins.h | 5 - src/ao_report.c | 2 +- src/ao_telemetry.c | 7 +- src/ao_telemetry_tiny.c | 6 +- src/test/.gitignore | 1 + src/test/Makefile | 13 +- src/test/plottest | 16 ++ src/test/run-one | 32 ++++ src/test/test-flights | 1 - 15 files changed, 367 insertions(+), 373 deletions(-) create mode 100755 src/test/plottest create mode 100755 src/test/run-one (limited to 'src/test') diff --git a/src/ao.h b/src/ao.h index 527390b0..b88bef1f 100644 --- a/src/ao.h +++ b/src/ao.h @@ -34,7 +34,7 @@ /* Stack runs from above the allocated __data space to 0xfe, which avoids * writing to 0xff as that triggers the stack overflow indicator */ -#define AO_STACK_START 0x80 +#define AO_STACK_START 0x90 #define AO_STACK_END 0xfe #define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) @@ -470,7 +470,7 @@ extern __xdata uint16_t ao_storage_unit; /* Initialize above values. Can only be called once the OS is running */ void -ao_storage_setup(void); +ao_storage_setup(void) __reentrant; /* Write data. Returns 0 on failure, 1 on success */ uint8_t @@ -698,21 +698,19 @@ enum ao_flight_state { extern __data uint8_t ao_flight_adc; extern __pdata enum ao_flight_state ao_flight_state; extern __pdata uint16_t ao_flight_tick; -extern __pdata int16_t ao_flight_accel; -extern __pdata int16_t ao_flight_pres; -extern __pdata int32_t ao_flight_vel; -extern __pdata int16_t ao_ground_pres; +extern __xdata int16_t ao_ground_pres; extern __pdata int16_t ao_ground_accel; -extern __pdata int16_t ao_min_pres; extern __pdata uint16_t ao_launch_time; extern __xdata uint8_t ao_flight_force_idle; -#ifdef USE_KALMAN extern __pdata int16_t ao_ground_height; -extern __pdata int32_t ao_k_max_height; -extern __pdata int32_t ao_k_height; -extern __pdata int32_t ao_k_speed; -extern __pdata int32_t ao_k_accel; -#endif +extern __pdata int16_t ao_max_height; +extern __pdata int16_t ao_height; /* meters */ +extern __pdata int16_t ao_speed; /* m/s * 16 */ +extern __pdata int16_t ao_accel; /* m/s² * 16 */ + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) /* Flight thread */ void @@ -912,10 +910,16 @@ struct ao_telemetry { uint16_t serial; uint16_t flight; uint8_t flight_state; - int16_t flight_accel; + int16_t accel; int16_t ground_accel; - int32_t flight_vel; - int16_t flight_pres; + union { + struct { + int16_t speed; + int16_t unused; + } k; + int32_t flight_vel; + } u; + int16_t height; int16_t ground_pres; int16_t accel_plus_g; int16_t accel_minus_g; diff --git a/src/ao_flash.c b/src/ao_flash.c index 3a264ceb..d323926f 100644 --- a/src/ao_flash.c +++ b/src/ao_flash.c @@ -93,12 +93,12 @@ static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE; static __pdata uint8_t ao_flash_block_dirty; static __pdata uint8_t ao_flash_write_pending; static __pdata uint8_t ao_flash_setup_done; -static __data uint8_t ao_flash_block_shift; -static __data uint16_t ao_flash_block_size; -static __data uint16_t ao_flash_block_mask; +static __pdata uint8_t ao_flash_block_shift; +static __pdata uint16_t ao_flash_block_size; +static __pdata uint16_t ao_flash_block_mask; void -ao_storage_setup(void) +ao_storage_setup(void) __reentrant { uint8_t status; diff --git a/src/ao_flight.c b/src/ao_flight.c index 493913b2..c65670f0 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -31,22 +31,14 @@ #error Please define HAS_USB #endif -#ifndef USE_KALMAN -#error Please define USE_KALMAN -#endif - /* Main flight thread. */ __pdata enum ao_flight_state ao_flight_state; /* current flight state */ __pdata uint16_t ao_flight_tick; /* time of last data */ __pdata uint16_t ao_flight_prev_tick; /* time of previous data */ -__pdata int16_t ao_flight_pres; /* filtered pressure */ -__pdata int16_t ao_ground_pres; /* startup pressure */ -__pdata int16_t ao_min_pres; /* minimum recorded pressure */ +__xdata int16_t ao_ground_pres; /* startup pressure */ __pdata uint16_t ao_launch_tick; /* time of launch detect */ -__pdata int16_t ao_main_pres; /* pressure to eject main */ #if HAS_ACCEL -__pdata int16_t ao_flight_accel; /* filtered acceleration */ __pdata int16_t ao_ground_accel; /* startup acceleration */ #endif @@ -55,16 +47,8 @@ __pdata int16_t ao_ground_accel; /* startup acceleration */ * resting */ __pdata uint16_t ao_interval_end; -__pdata int16_t ao_interval_cur_min_pres; -__pdata int16_t ao_interval_cur_max_pres; -__pdata int16_t ao_interval_min_pres; -__pdata int16_t ao_interval_max_pres; -#if HAS_ACCEL -__pdata int16_t ao_interval_cur_min_accel; -__pdata int16_t ao_interval_cur_max_accel; -__pdata int16_t ao_interval_min_accel; -__pdata int16_t ao_interval_max_accel; -#endif +__pdata int16_t ao_interval_min_height; +__pdata int16_t ao_interval_max_height; __data uint8_t ao_flight_adc; __pdata int16_t ao_raw_pres; @@ -96,15 +80,8 @@ __pdata int16_t ao_accel_2g; */ #define GRAVITY 9.80665 -/* convert m/s to velocity count */ -#define VEL_MPS_TO_COUNT(mps) (((int32_t) (((mps) / GRAVITY) * (AO_HERTZ/2))) * (int32_t) ao_accel_2g) #define ACCEL_NOSE_UP (ao_accel_2g >> 2) -#define ACCEL_BOOST ao_accel_2g -#define ACCEL_COAST (ao_accel_2g >> 3) -#define ACCEL_INT_LAND (ao_accel_2g >> 3) -#define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200) -#define ACCEL_VEL_BOOST VEL_MPS_TO_COUNT(5) #endif @@ -127,91 +104,185 @@ __pdata int16_t ao_accel_2g; * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa */ -#define BARO_kPa 268 -#define BARO_LAUNCH (BARO_kPa / 5) /* .2kPa, or about 20m */ -#define BARO_APOGEE (BARO_kPa / 10) /* .1kPa, or about 10m */ -#define BARO_COAST (BARO_kPa * 5) /* 5kpa, or about 500m */ -#define BARO_MAIN (BARO_kPa) /* 1kPa, or about 100m */ -#define BARO_INT_LAND (BARO_kPa / 20) /* .05kPa, or about 5m */ -#define BARO_LAND (BARO_kPa * 10) /* 10kPa or about 1000m */ - /* We also have a clock, which can be used to sanity check things in * case of other failures */ #define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) -#if HAS_ACCEL -/* This value is scaled in a weird way. It's a running total of accelerometer - * readings minus the ground accelerometer reading. That means it measures - * velocity, and quite accurately too. As it gets updated 100 times a second, - * it's scaled by 100 - */ -__pdata int32_t ao_flight_vel; -__pdata int32_t ao_min_vel; -__pdata int32_t ao_old_vel; -__pdata int16_t ao_old_vel_tick; -__xdata int32_t ao_raw_accel_sum; -#endif - -#if USE_KALMAN -__pdata int16_t ao_ground_height; -__pdata int32_t ao_k_max_height; -__pdata int32_t ao_k_height; -__pdata int32_t ao_k_speed; -__pdata int32_t ao_k_accel; - #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) #define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) - #define from_fix(x) ((x) >> 16) -#define AO_K0_100 to_fix16(0.05680323) -#define AO_K1_100 to_fix16(0.16608182) -#define AO_K2_100 to_fix16(0.24279580) +#include "ao_kalman.h" + +__pdata int16_t ao_ground_height; +__pdata int16_t ao_height; +__pdata int16_t ao_speed; +__pdata int16_t ao_accel; +__pdata int16_t ao_max_height; + +static __pdata int32_t ao_k_height; +static __pdata int32_t ao_k_speed; +static __pdata int32_t ao_k_accel; #define AO_K_STEP_100 to_fix16(0.01) #define AO_K_STEP_2_2_100 to_fix16(0.00005) -#define AO_K0_10 to_fix16(0.23772023) -#define AO_K1_10 to_fix16(0.32214149) -#define AO_K2_10 to_fix16(0.21827159) - #define AO_K_STEP_10 to_fix16(0.1) #define AO_K_STEP_2_2_10 to_fix16(0.005) +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 8000 + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 300 + +static void +ao_kalman_predict(void) +{ +#ifdef AO_FLIGHT_TEST + if (ao_flight_tick - ao_flight_prev_tick > 5) { + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + + (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; + + return; + } +#endif + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + + (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; +} + +static __pdata int16_t ao_error_h; +static __pdata int16_t ao_raw_alt; +static __pdata int16_t ao_raw_height; +static __pdata int16_t ao_error_h_sq_avg; + static void -ao_kalman_baro(void) +ao_kalman_err_height(void) { - int16_t err = ((ao_pres_to_altitude(ao_raw_pres) - ao_ground_height)) - - (int16_t) (ao_k_height >> 16); + int16_t e; + ao_error_h = ao_raw_height - (int16_t) (ao_k_height >> 16); + + e = ao_error_h; + if (e < 0) + e = -e; + if (e > 127) + e = 127; + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; + ao_error_h_sq_avg += (e * e) >> 4; +} +static void +ao_kalman_correct_baro(void) +{ + ao_kalman_err_height(); #ifdef AO_FLIGHT_TEST if (ao_flight_tick - ao_flight_prev_tick > 5) { - ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_10 + - (ao_k_accel >> 16) * AO_K_STEP_2_2_10); - ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_10; - - /* correct */ - ao_k_height += (int32_t) AO_K0_10 * err; - ao_k_speed += (int32_t) AO_K1_10 * err; - ao_k_accel += (int32_t) AO_K2_10 * err; + ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; return; } #endif - ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_100 + - (ao_k_accel >> 16) * AO_K_STEP_2_2_100); - ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_100; - - /* correct */ - ao_k_height += (int32_t) AO_K0_100 * err; - ao_k_speed += (int32_t) AO_K1_100 * err; - ao_k_accel += (int32_t) AO_K2_100 * err; + ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; } + +#if HAS_ACCEL +static __pdata int16_t ao_error_a; +static __pdata int32_t ao_accel_scale; + +static void +ao_kalman_err_accel(void) +{ + int32_t accel; + + accel = (ao_ground_accel - ao_raw_accel) * ao_accel_scale; + + /* Can't use ao_accel here as it is the pre-prediction value still */ + ao_error_a = (accel - ao_k_accel) >> 16; +} + +static void +ao_kalman_correct_both(void) +{ + ao_kalman_err_height(); + ao_kalman_err_accel(); + +#if 0 + /* + * Check to see if things are crazy here -- + * if the computed height is far above the + * measured height, we assume that the flight + * trajectory is not vertical, and so ignore + * the accelerometer for the remainder of the + * flight. + */ + if (ao_error_h_sq_avg > 10) + { + ao_kalman_correct_baro(); + return; + } +#endif + +#ifdef AO_FLIGHT_TEST + if (ao_flight_tick - ao_flight_prev_tick > 5) { + ao_k_height += + (int32_t) AO_BOTH_K00_10 * ao_error_h + + (int32_t) (AO_BOTH_K01_10 >> 4) * ao_error_a; + ao_k_speed += + ((int32_t) AO_BOTH_K10_10 << 4) * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a; + ao_k_accel += + ((int32_t) AO_BOTH_K20_10 << 4) * ao_error_h + + (int32_t) AO_BOTH_K21_10 * ao_error_a; + return; + } +#endif + ao_k_height += + (int32_t) AO_BOTH_K00_100 * ao_error_h + + (int32_t) AO_BOTH_K01_100 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_100 * ao_error_h + + (int32_t) AO_BOTH_K21_100 * ao_error_a; +} + +static void +ao_kalman_correct_accel(void) +{ + ao_kalman_err_accel(); + +#ifdef AO_FLIGHT_TEST + if (ao_flight_tick - ao_flight_prev_tick > 5) { + ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; + return; + } #endif + ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; +} +#endif /* HAS_ACCEL */ __xdata int32_t ao_raw_pres_sum; +#ifdef HAS_ACCEL +__xdata int32_t ao_raw_accel_sum; +#endif + /* Landing is detected by getting constant readings from both pressure and accelerometer * for a fairly long time (AO_INTERVAL_TICKS) */ @@ -235,10 +306,6 @@ ao_flight(void) ao_wakeup(DATA_TO_XDATA(&ao_flight_adc)); ao_sleep(DATA_TO_XDATA(&ao_adc_head)); while (ao_flight_adc != ao_adc_head) { -#if HAS_ACCEL - __pdata uint8_t ticks; - __pdata int16_t ao_vel_change; -#endif __xdata struct ao_adc *ao_adc; ao_flight_prev_tick = ao_flight_tick; @@ -246,9 +313,8 @@ ao_flight(void) ao_adc = &ao_adc_ring[ao_flight_adc]; ao_flight_tick = ao_adc->tick; ao_raw_pres = ao_adc->pres; - ao_flight_pres -= ao_flight_pres >> 4; - ao_flight_pres += ao_raw_pres >> 4; - + ao_raw_alt = ao_pres_to_altitude(ao_raw_pres); + ao_raw_height = ao_raw_alt - ao_ground_height; #if HAS_ACCEL ao_raw_accel = ao_adc->accel; #if HAS_ACCEL_REF @@ -335,45 +401,31 @@ ao_flight(void) ao_raw_accel = (uint16_t) ((((uint32_t) ao_raw_accel << 16) / (ao_accel_ref[ao_flight_adc] << 1))) >> 1; ao_adc->accel = ao_raw_accel; #endif - - ao_flight_accel -= ao_flight_accel >> 4; - ao_flight_accel += ao_raw_accel >> 4; - /* Update velocity - * - * The accelerometer is mounted so that - * acceleration yields negative values - * while deceleration yields positive values, - * so subtract instead of add. - */ - ticks = ao_flight_tick - ao_flight_prev_tick; - ao_vel_change = ao_ground_accel - (((ao_raw_accel + 1) >> 1) + ((ao_raw_accel_prev + 1) >> 1)); - ao_raw_accel_prev = ao_raw_accel; - - /* one is a common interval */ - if (ticks == 1) - ao_flight_vel += (int32_t) ao_vel_change; - else - ao_flight_vel += (int32_t) ao_vel_change * (int32_t) ticks; #endif -#if USE_KALMAN - if (ao_flight_state > ao_flight_idle) - ao_kalman_baro(); -#endif - ao_flight_adc = ao_adc_ring_next(ao_flight_adc); - } - - if (ao_flight_pres < ao_min_pres) - ao_min_pres = ao_flight_pres; + if (ao_flight_state > ao_flight_idle) { + ao_kalman_predict(); #if HAS_ACCEL - if (ao_flight_vel >= 0) { - if (ao_flight_vel < ao_min_vel) - ao_min_vel = ao_flight_vel; - } else { - if (-ao_flight_vel < ao_min_vel) - ao_min_vel = -ao_flight_vel; + if (ao_flight_state <= ao_flight_coast) { +#ifndef FORCE_ACCEL + if (/*ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED) &&*/ + ao_raw_alt < AO_MAX_BARO_HEIGHT) + ao_kalman_correct_both(); + else +#endif + ao_kalman_correct_accel(); + } else +#endif + if (ao_raw_alt < AO_MAX_BARO_HEIGHT || ao_flight_state >= ao_flight_drogue) + ao_kalman_correct_baro(); + ao_height = from_fix(ao_k_height); + ao_speed = from_fix(ao_k_speed); + ao_accel = from_fix(ao_k_accel); + if (ao_height > ao_max_height) + ao_max_height = ao_height; + } + ao_flight_adc = ao_adc_ring_next(ao_flight_adc); } -#endif switch (ao_flight_state) { case ao_flight_startup: @@ -391,35 +443,25 @@ ao_flight(void) ++nsamples; continue; } + ao_config_get(); #if HAS_ACCEL ao_ground_accel = ao_raw_accel_sum >> 9; + ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; + ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; #endif ao_ground_pres = ao_raw_pres_sum >> 9; - ao_min_pres = ao_ground_pres; - ao_config_get(); -#if USE_KALMAN ao_ground_height = ao_pres_to_altitude(ao_ground_pres); -#endif - ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy); -#if HAS_ACCEL - ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; - ao_flight_vel = 0; - ao_min_vel = 0; - ao_old_vel = ao_flight_vel; - ao_old_vel_tick = ao_flight_tick; -#endif /* Check to see what mode we should go to. * - Invalid mode if accel cal appears to be out * - pad mode if we're upright, * - idle mode otherwise */ - ao_config_get(); #if HAS_ACCEL if (ao_config.accel_plus_g == 0 || ao_config.accel_minus_g == 0 || - ao_flight_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || - ao_flight_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) + ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || + ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) { /* Detected an accel value outside -1.5g to 1.5g * (or uncalibrated values), so we go into invalid mode @@ -430,7 +472,7 @@ ao_flight(void) #endif if (!ao_flight_force_idle #if HAS_ACCEL - && ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP + && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP #endif ) { @@ -465,57 +507,27 @@ ao_flight(void) break; case ao_flight_pad: -#if HAS_ACCEL - /* Trim velocity - * - * Once a second, remove any velocity from - * a second ago - */ - if ((int16_t) (ao_flight_tick - ao_old_vel_tick) >= AO_SEC_TO_TICKS(1)) { - ao_old_vel_tick = ao_flight_tick; - ao_flight_vel -= ao_old_vel; - ao_old_vel = ao_flight_vel; - } -#endif /* pad to boost: * - * accelerometer: > 2g AND velocity > 5m/s - * OR * barometer: > 20m vertical motion + * OR + * accelerometer: > 2g AND velocity > 5m/s * * The accelerometer should always detect motion before * the barometer, but we use both to make sure this - * transition is detected + * transition is detected. If the device + * doesn't have an accelerometer, then ignore the + * speed and acceleration as they are quite noisy + * on the pad. */ -#if USE_KALMAN + if (ao_height > AO_M_TO_HEIGHT(20) #if HAS_ACCEL - /* - * With an accelerometer, either to detect launch - */ - if ((ao_k_accel > to_fix32(20) && - ao_k_speed > to_fix32(5)) || - ao_k_height > to_fix32(20)) -#else - /* - * Without an accelerometer, the barometer is far too - * noisy to rely on speed or acceleration data - */ - if (ao_k_height > to_fix32(20)) -#endif -#else - if ( -#if HAS_ACCEL - (ao_flight_accel < ao_ground_accel - ACCEL_BOOST && - ao_flight_vel > ACCEL_VEL_BOOST) || -#endif - ao_flight_pres < ao_ground_pres - BARO_LAUNCH) + || (ao_accel > AO_MSS_TO_ACCEL(20) && + ao_speed > AO_MS_TO_SPEED(5)) #endif + ) { -#if HAS_ACCEL || USE_KALMAN ao_flight_state = ao_flight_boost; -#else - ao_flight_state = ao_flight_coast; -#endif ao_launch_tick = ao_flight_tick; /* start logging data */ @@ -537,7 +549,6 @@ ao_flight(void) break; } break; -#if HAS_ACCEL || USE_KALMAN case ao_flight_boost: /* boost to fast: @@ -550,13 +561,8 @@ ao_flight(void) * deceleration, or by waiting until the maximum burn duration * (15 seconds) has past. */ -#if USE_KALMAN - if ((ao_k_accel < to_fix32(-10) && ao_k_height > to_fix32(100)) || - (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) -#else - if (ao_flight_accel > ao_ground_accel + ACCEL_COAST || + if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX) -#endif { ao_flight_state = ao_flight_fast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); @@ -564,62 +570,28 @@ ao_flight(void) } break; case ao_flight_fast: - - /* fast to coast: - * - * accelerometer: integrated velocity < 200 m/s - * OR - * barometer: fall at least 500m from max altitude - * - * This extra state is required to avoid mis-detecting - * apogee due to mach transitions. - * - * XXX this is essentially a single-detector test - * as the 500m altitude change would likely result - * in a loss of the rocket. More data on precisely - * how big a pressure change the mach transition - * generates would be useful here. + /* + * This is essentially the same as coast, + * but the barometer is being ignored as + * it may be unreliable. */ -#if USE_KALMAN - if (ao_k_speed < to_fix32(200) || - ao_k_height < ao_k_max_height - to_fix32(500)) -#else - if (ao_flight_vel < ACCEL_VEL_MACH || - ao_flight_pres > ao_min_pres + BARO_COAST) -#endif - { -#if HAS_ACCEL - /* set min velocity to current velocity for - * apogee detect - */ - ao_min_vel = abs(ao_flight_vel); -#endif + if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) { ao_flight_state = ao_flight_coast; ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + break; } break; -#endif /* HAS_ACCEL */ case ao_flight_coast: -#if USE_KALMAN /* apogee detect: coast to drogue deploy: * * speed: < 0 - */ - if (ao_k_speed < 0) -#else - /* apogee detect: coast to drogue deploy: - * - * barometer: fall at least 10m * - * It would be nice to use the accelerometer - * to detect apogee as well, but tests have - * shown that flights far from vertical would - * grossly mis-detect apogee. So, for now, - * we'll trust to a single sensor for this test + * Also make sure the model altitude is tracking + * the measured altitude reasonably closely; otherwise + * we're probably transsonic. */ - if (ao_flight_pres > ao_min_pres + BARO_APOGEE) -#endif + if (ao_speed < 0 && (ao_raw_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)) { /* ignite the drogue charge */ ao_ignite(ao_igniter_drogue); @@ -627,32 +599,15 @@ ao_flight(void) /* slow down the telemetry system */ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); -#if !USE_KALMAN - /* slow down the ADC sample rate */ - ao_timer_set_adc_interval(10); -#endif - /* - * Start recording min/max accel and pres for a while + * Start recording min/max height * to figure out when the rocket has landed */ - /* Set the 'last' limits to max range to prevent - * early resting detection - */ -#if HAS_ACCEL - ao_interval_min_accel = 0; - ao_interval_max_accel = 0x7fff; -#endif - ao_interval_min_pres = 0; - ao_interval_max_pres = 0x7fff; /* initialize interval values */ ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; - ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; -#if HAS_ACCEL - ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel; -#endif + ao_interval_min_height = ao_interval_max_height = ao_height; /* and enter drogue state */ ao_flight_state = ao_flight_drogue; @@ -674,11 +629,7 @@ ao_flight(void) * at that point. Perhaps also use the drogue sense lines * to notice continutity? */ -#if USE_KALMAN - if (from_fix(ao_k_height) < ao_config.main_deploy) -#else - if (ao_flight_pres >= ao_main_pres) -#endif + if (ao_height <= ao_config.main_deploy) { ao_ignite(ao_igniter_main); ao_flight_state = ao_flight_main; @@ -690,39 +641,17 @@ ao_flight(void) /* drogue/main to land: * - * accelerometer: value stable - * AND * barometer: altitude stable and within 1000m of the launch altitude */ - if (ao_flight_pres < ao_interval_cur_min_pres) - ao_interval_cur_min_pres = ao_flight_pres; - if (ao_flight_pres > ao_interval_cur_max_pres) - ao_interval_cur_max_pres = ao_flight_pres; -#if HAS_ACCEL - if (ao_flight_accel < ao_interval_cur_min_accel) - ao_interval_cur_min_accel = ao_flight_accel; - if (ao_flight_accel > ao_interval_cur_max_accel) - ao_interval_cur_max_accel = ao_flight_accel; -#endif + if (ao_height < ao_interval_min_height) + ao_interval_min_height = ao_height; + if (ao_height > ao_interval_max_height) + ao_interval_max_height = ao_height; if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) { - ao_interval_max_pres = ao_interval_cur_max_pres; - ao_interval_min_pres = ao_interval_cur_min_pres; - ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres; -#if HAS_ACCEL - ao_interval_max_accel = ao_interval_cur_max_accel; - ao_interval_min_accel = ao_interval_cur_min_accel; - ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel; -#endif - ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; - - if ( -#if HAS_ACCEL - (uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND && -#endif - ao_flight_pres > ao_ground_pres - BARO_LAND && - (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND) + if (ao_height < AO_M_TO_HEIGHT(1000) && + ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) { ao_flight_state = ao_flight_landed; @@ -733,6 +662,8 @@ ao_flight(void) ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } + ao_interval_min_height = ao_interval_max_height = ao_height; + ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS; } break; case ao_flight_landed: diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 16167644..e7bfbdd2 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -29,6 +29,10 @@ #define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) #define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + /* * One set of samples read from the A/D converter */ @@ -143,15 +147,26 @@ struct ao_config ao_config; #ifndef HAS_ACCEL #define HAS_ACCEL 1 #define HAS_ACCEL_REF 0 -#define USE_KALMAN 0 -#else -#define USE_KALMAN 1 #endif #include "ao_flight.c" #define to_double(f) ((f) / 65536.0) +#define GRAVITY 9.80665 +extern int16_t ao_ground_accel, ao_raw_accel; +extern int16_t ao_accel_2g; + +int32_t drogue_height; +int32_t main_height; + +int tick_offset; +uint16_t prev_tick; +static int ao_records_read = 0; +static int ao_eof_read = 0; +static int ao_flight_ground_accel; +static int ao_flight_started = 0; + void ao_insert(void) { @@ -159,33 +174,39 @@ ao_insert(void) ao_adc_head = ao_adc_ring_next(ao_adc_head); if (ao_summary) return; - if (ao_flight_state != ao_flight_startup) { -#if USE_KALMAN - printf("time %7.2f accel %d pres %d k_height %8.2f k_speed %8.5f k_accel %8.5f\n", - (double) ao_adc_static.tick / 100, - ao_adc_static.accel, - ao_adc_static.pres, - to_double(ao_k_height), - to_double(ao_k_speed), - to_double(ao_k_accel)); -#else - printf("time %g accel %d pres %d\n", - (double) ao_adc_static.tick / 100, - ao_adc_static.accel, - ao_adc_static.pres); -#endif + if (ao_flight_state == ao_flight_startup) + return; + { + double height = ao_pres_to_altitude(ao_raw_pres) - ao_ground_height; + double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / + (ao_config.accel_minus_g - ao_config.accel_plus_g); + + if (!tick_offset) + tick_offset = ao_adc_static.tick; + if (!drogue_height && ao_flight_state >= ao_flight_drogue) + drogue_height = ao_k_height; + if (!main_height && ao_flight_state >= ao_flight_main) + main_height = ao_k_height; + if ((prev_tick - ao_adc_static.tick) > 0) + tick_offset += 65536; + prev_tick = ao_adc_static.tick; + printf("%7.2f height %g accel %g state %s k_height %g k_speed %g k_accel %g drogue %g main %g error %d\n", + (double) (ao_adc_static.tick + tick_offset) / 100, + height, + accel, + ao_state_names[ao_flight_state], + ao_k_height / 65536.0, + ao_k_speed / 65536.0 / 16.0, + ao_k_accel / 65536.0 / 16.0, + drogue_height / 65536.0, + main_height / 65536.0, + ao_error_h_sq_avg); } } -static int ao_records_read = 0; -static int ao_eof_read = 0; -static int ao_flight_ground_accel; -static int ao_flight_started = 0; - void ao_sleep(void *wchan) { - ao_dump_state(); if (wchan == &ao_adc_head) { char type; uint16_t tick; @@ -291,19 +312,6 @@ ao_dump_state(void) return; if (ao_summary) return; -#if HAS_ACCEL - printf ("\t\t\t\t\t%s accel %g vel %g alt %d main %d\n", - ao_state_names[ao_flight_state], - (ao_ground_accel - ao_flight_accel) / COUNTS_PER_G * GRAVITY, - (double) ao_flight_vel / 100 / COUNTS_PER_G * GRAVITY, - ao_pres_to_altitude(ao_flight_pres) - ao_pres_to_altitude(ao_ground_pres), - ao_pres_to_altitude(ao_main_pres) - ao_pres_to_altitude(ao_ground_pres)); -#else - printf ("\t\t\t\t\t%s alt %d main %d\n", - ao_state_names[ao_flight_state], - ao_pres_to_altitude(ao_flight_pres) - ao_pres_to_altitude(ao_ground_pres), - ao_pres_to_altitude(ao_main_pres) - ao_pres_to_altitude(ao_ground_pres)); -#endif if (ao_flight_state == ao_flight_landed) exit(0); } diff --git a/src/ao_log_tiny.c b/src/ao_log_tiny.c index fad2a242..f0c0662a 100644 --- a/src/ao_log_tiny.c +++ b/src/ao_log_tiny.c @@ -69,7 +69,7 @@ ao_log(void) if (ao_log_tiny_state == ao_flight_landed) ao_log_stop(); } - ao_log_tiny_data(ao_k_height >> 16); + ao_log_tiny_data(ao_height); time += ao_log_tiny_interval; delay = time - ao_time(); if (delay > 0) diff --git a/src/ao_monitor.c b/src/ao_monitor.c index d6fd8305..8f290071 100644 --- a/src/ao_monitor.c +++ b/src/ao_monitor.c @@ -92,23 +92,23 @@ ao_monitor(void) recv.telemetry.accel_plus_g, recv.telemetry.accel_minus_g); -#if 0 - /* Kalman state values */ - printf(AO_TELEM_KALMAN_HEIGHT " %d " - AO_TELEM_KALMAN_SPEED " %d " - AO_TELEM_KALMAN_ACCEL " %d ", - recv.telemetry.height, - recv.telemetry.speed, - recv.telemetry.accel); -#else - /* Ad-hoc flight values */ - printf(AO_TELEM_ADHOC_ACCEL " %d " - AO_TELEM_ADHOC_SPEED " %ld " - AO_TELEM_ADHOC_BARO " %d ", - recv.telemetry.flight_accel, - recv.telemetry.flight_vel, - recv.telemetry.flight_pres); -#endif + if (recv.telemetry.u.k.unused == 0x8000) { + /* Kalman state values */ + printf(AO_TELEM_KALMAN_HEIGHT " %d " + AO_TELEM_KALMAN_SPEED " %d " + AO_TELEM_KALMAN_ACCEL " %d ", + recv.telemetry.height, + recv.telemetry.u.k.speed, + recv.telemetry.accel); + } else { + /* Ad-hoc flight values */ + printf(AO_TELEM_ADHOC_ACCEL " %d " + AO_TELEM_ADHOC_SPEED " %ld " + AO_TELEM_ADHOC_BARO " %d ", + recv.telemetry.accel, + recv.telemetry.u.flight_vel, + recv.telemetry.height); + } ao_gps_print(&recv.telemetry.gps); ao_gps_tracking_print(&recv.telemetry.gps_tracking); putchar('\n'); diff --git a/src/ao_pins.h b/src/ao_pins.h index c602268b..a4a93aab 100644 --- a/src/ao_pins.h +++ b/src/ao_pins.h @@ -28,7 +28,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 0 #define HAS_DBG 1 - #define USE_KALMAN 0 #define DBG_ON_P1 1 #define DBG_ON_P0 0 #define IGNITE_ON_P2 1 @@ -53,7 +52,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 0 #define HAS_DBG 1 - #define USE_KALMAN 0 #define DBG_ON_P1 1 #define DBG_ON_P0 0 #define IGNITE_ON_P2 1 @@ -103,7 +101,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 1 #define HAS_DBG 0 - #define USE_KALMAN 1 #define IGNITE_ON_P2 0 #define IGNITE_ON_P0 1 #define PACKET_HAS_MASTER 0 @@ -126,7 +123,6 @@ #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 1 #define HAS_DBG 0 - #define USE_KALMAN 1 #define IGNITE_ON_P2 0 #define IGNITE_ON_P0 1 #define PACKET_HAS_MASTER 0 @@ -147,7 +143,6 @@ #define HAS_SERIAL_1 1 #define HAS_ADC 1 #define HAS_DBG 0 - #define USE_KALMAN 0 #define HAS_EEPROM 1 #define USE_INTERNAL_FLASH 0 #define DBG_ON_P1 0 diff --git a/src/ao_report.c b/src/ao_report.c index 3223390f..4f7fd657 100644 --- a/src/ao_report.c +++ b/src/ao_report.c @@ -87,7 +87,7 @@ ao_report_digit(uint8_t digit) __reentrant static void ao_report_altitude(void) { - __xdata int16_t agl = ao_pres_to_altitude(ao_min_pres) - ao_pres_to_altitude(ao_ground_pres); + __xdata int16_t agl = ao_max_height; __xdata uint8_t digits[10]; __xdata uint8_t ndigits, i; diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c index 6556ce32..9a86882f 100644 --- a/src/ao_telemetry.c +++ b/src/ao_telemetry.c @@ -45,12 +45,13 @@ ao_telemetry(void) time = ao_rdf_time = ao_time(); while (ao_telemetry_interval) { telemetry.flight_state = ao_flight_state; + telemetry.height = ao_height; + telemetry.u.k.speed = ao_speed; + telemetry.accel = ao_accel; + telemetry.u.k.unused = 0x8000; #if HAS_ACCEL - telemetry.flight_accel = ao_flight_accel; telemetry.ground_accel = ao_ground_accel; - telemetry.flight_vel = ao_flight_vel; #endif - telemetry.flight_pres = ao_flight_pres; telemetry.ground_pres = ao_ground_pres; #if HAS_ADC ao_adc_get(&telemetry.adc); diff --git a/src/ao_telemetry_tiny.c b/src/ao_telemetry_tiny.c index 83ba7fc0..6f2ddda1 100644 --- a/src/ao_telemetry_tiny.c +++ b/src/ao_telemetry_tiny.c @@ -43,9 +43,9 @@ ao_telemetry_tiny(void) time = ao_rdf_time = ao_time(); while (ao_telemetry_tiny_interval) { telemetry_tiny.flight_state = ao_flight_state; - telemetry_tiny.height = ao_k_height >> 16; - telemetry_tiny.speed = ao_k_speed >> 12; - telemetry_tiny.accel = ao_k_accel >> 12; + telemetry_tiny.height = ao_height; + telemetry_tiny.speed = ao_speed; + telemetry_tiny.accel = ao_accel; telemetry_tiny.ground_pres = ao_ground_pres; ao_adc_get(&telemetry_tiny.adc); ao_radio_send(&telemetry_tiny, sizeof (telemetry_tiny)); diff --git a/src/test/.gitignore b/src/test/.gitignore index 0a43de8a..33c7ef35 100644 --- a/src/test/.gitignore +++ b/src/test/.gitignore @@ -1,5 +1,6 @@ ao_flight_test ao_flight_test_baro +ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test diff --git a/src/test/Makefile b/src/test/Makefile index 853713fa..433f749b 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,7 @@ vpath % .. +vpath % ../kalman -PROGS=ao_flight_test ao_flight_test_baro ao_gps_test ao_gps_test_skytraq ao_convert_test +PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test CFLAGS=-I.. -I. @@ -11,12 +12,15 @@ clean: install: -ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c altitude.h +ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c altitude.h ao_kalman.h cc -g -o $@ $< -ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c altitude.h +ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c altitude.h ao_kalman.h cc -g -o $@ -DHAS_ACCEL=0 ../ao_flight_test.c +ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c altitude.h ao_kalman.h + cc -g -o $@ -DFORCE_ACCEL=1 ../ao_flight_test.c + ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h cc -g -o $@ $< @@ -25,3 +29,6 @@ ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_ho ao_convert_test: ao_convert_test.c ao_convert.c altitude.h cc -g -o $@ $< + +../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c + sh $< > $@ diff --git a/src/test/plottest b/src/test/plottest new file mode 100755 index 00000000..76af5ee7 --- /dev/null +++ b/src/test/plottest @@ -0,0 +1,16 @@ +gnuplot -persist << 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 +plot "$1" using 1:3 with lines axes x1y1 title "raw height",\ +"$1" using 1:5 with lines axes x1y2 title "raw accel",\ +"$1" using 1:9 with lines axes x1y1 title "height",\ +"$1" using 1:11 with lines axes x1y2 title "speed",\ +"$1" using 1:13 with lines axes x1y2 title "accel",\ +"$1" using 1:15 with lines axes x1y1 title "drogue",\ +"$1" using 1:17 with lines axes x1y1 title "main",\ +"$1" using 1:19 with lines axes x1y1 title "error" +EOF diff --git a/src/test/run-one b/src/test/run-one new file mode 100755 index 00000000..f9d21576 --- /dev/null +++ b/src/test/run-one @@ -0,0 +1,32 @@ +#!/bin/sh + +./ao_flight_test "$1" > run-out.full +./ao_flight_test_baro "$1" > run-out.baro +./ao_flight_test_accel "$1" > run-out.accel + +gnuplot -persist << 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 "$1" +plot "run-out.full" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ +"run-out.full" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\ +"run-out.full" using 1:9 with lines lt 2 axes x1y1 title "full height",\ +"run-out.full" using 1:11 with lines lt 2 axes x1y2 title "full speed",\ +"run-out.full" using 1:13 with lines lt 2 axes x1y2 title "full accel",\ +"run-out.full" using 1:15 with lines lt 2 axes x1y1 title "full drogue",\ +"run-out.full" using 1:17 with lines lt 2 axes x1y1 title "full main", \ +"run-out.baro" using 1:9 with lines lt 3 axes x1y1 title "baro height",\ +"run-out.baro" using 1:11 with lines lt 3 axes x1y2 title "baro speed",\ +"run-out.baro" using 1:13 with lines lt 3 axes x1y2 title "baro accel",\ +"run-out.baro" using 1:15 with lines lt 3 axes x1y1 title "baro drogue",\ +"run-out.baro" using 1:17 with lines lt 3 axes x1y1 title "baro main",\ +"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" +EOF diff --git a/src/test/test-flights b/src/test/test-flights index a9a2ecca..afdaba5a 100644 --- a/src/test/test-flights +++ b/src/test/test-flights @@ -7,7 +7,6 @@ 2009-07-18-serial-001-flight-007.eeprom 2009-08-22-serial-001-flight-001.eeprom 2009-08-22-serial-010-flight-001.eeprom -2009-09-05-serial-008-flight-002.eeprom 2009-09-05-serial-010-flight-002.eeprom 2009-09-05-serial-011-flight-001.eeprom 2009-09-11-serial-008-flight-003.eeprom -- cgit v1.2.3 From 7d7b476564a16eda81ab3406f70a21995e1b464e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 22 Mar 2011 21:51:52 +0900 Subject: altos: Fix up flight code testing This automates flight code testing by reporting mis-detected apogee or main events. Signed-off-by: Keith Packard --- src/ao_flight_test.c | 138 ++++++++++++++++++++++++++++++++++++-------------- src/test/run-one | 26 ++++++---- src/test/run-tests | 34 ++++++------- src/test/test-flights | 1 - 4 files changed, 131 insertions(+), 68 deletions(-) (limited to 'src/test') diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index e7bfbdd2..51a5965c 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -22,6 +22,7 @@ #include #include #include +#include #define AO_HERTZ 100 @@ -87,11 +88,27 @@ enum ao_igniter { struct ao_adc ao_adc_static; +int drogue_height; +double drogue_time; +int main_height; +double main_time; + +int tick_offset; + +static int32_t ao_k_height; + void ao_ignite(enum ao_igniter igniter) { - printf ("ignite %s at %7.2f\n", igniter == ao_igniter_drogue ? "drogue" : "main", - (double) ao_adc_static.tick / 100.0); + double time = (double) (ao_adc_static.tick + tick_offset) / 100; + + if (igniter == ao_igniter_drogue) { + drogue_time = time; + drogue_height = ao_k_height >> 16; + } else { + main_time = time; + main_height = ao_k_height >> 16; + } } struct ao_task { @@ -108,7 +125,12 @@ struct ao_task { #define AO_FLIGHT_TEST +int ao_flight_debug; + FILE *emulator_in; +char *emulator_app; +char *emulator_name; +double emulator_error_max = 10; void ao_dump_state(void); @@ -157,51 +179,84 @@ struct ao_config ao_config; extern int16_t ao_ground_accel, ao_raw_accel; extern int16_t ao_accel_2g; -int32_t drogue_height; -int32_t main_height; - -int tick_offset; uint16_t prev_tick; static int ao_records_read = 0; static int ao_eof_read = 0; static int ao_flight_ground_accel; static int ao_flight_started = 0; +static int ao_test_max_height; +static double ao_test_max_height_time; +static int ao_test_main_height; +static double ao_test_main_height_time; void ao_insert(void) { + double time; + ao_adc_ring[ao_adc_head] = ao_adc_static; ao_adc_head = ao_adc_ring_next(ao_adc_head); - if (ao_summary) - return; - if (ao_flight_state == ao_flight_startup) - return; - { + if (ao_flight_state != ao_flight_startup) { double height = ao_pres_to_altitude(ao_raw_pres) - ao_ground_height; double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / (ao_config.accel_minus_g - ao_config.accel_plus_g); if (!tick_offset) - tick_offset = ao_adc_static.tick; - if (!drogue_height && ao_flight_state >= ao_flight_drogue) - drogue_height = ao_k_height; - if (!main_height && ao_flight_state >= ao_flight_main) - main_height = ao_k_height; - if ((prev_tick - ao_adc_static.tick) > 0) + tick_offset = -ao_adc_static.tick; + if ((prev_tick - ao_adc_static.tick) > 0x400) tick_offset += 65536; prev_tick = ao_adc_static.tick; - printf("%7.2f height %g accel %g state %s k_height %g k_speed %g k_accel %g drogue %g main %g error %d\n", - (double) (ao_adc_static.tick + tick_offset) / 100, - height, - accel, - ao_state_names[ao_flight_state], - ao_k_height / 65536.0, - ao_k_speed / 65536.0 / 16.0, - ao_k_accel / 65536.0 / 16.0, - drogue_height / 65536.0, - main_height / 65536.0, - ao_error_h_sq_avg); + time = (double) (ao_adc_static.tick + tick_offset) / 100; + if (!ao_summary) { + printf("%7.2f height %g accel %g state %s k_height %g k_speed %g k_accel %g drogue %d main %d error %d\n", + time, + height, + accel, + ao_state_names[ao_flight_state], + ao_k_height / 65536.0, + ao_k_speed / 65536.0 / 16.0, + ao_k_accel / 65536.0 / 16.0, + drogue_height, + main_height, + ao_error_h_sq_avg); + } + + if (ao_test_max_height < height) { + ao_test_max_height = height; + ao_test_max_height_time = time; + } + if (height > ao_config.main_deploy) { + ao_test_main_height_time = time; + ao_test_main_height = height; + } + } +} + +void +ao_test_exit(void) +{ + double drogue_error; + double main_error; + + if (!ao_test_main_height_time) { + ao_test_main_height_time = ao_test_max_height_time; + ao_test_main_height = ao_test_max_height; + } + drogue_error = fabs(ao_test_max_height_time - drogue_time); + main_error = fabs(ao_test_main_height_time - main_time); + if (drogue_error > emulator_error_max || main_error > emulator_error_max) { + printf ("%s %s\n", + emulator_app, emulator_name); + printf ("\tApogee error %g\n", drogue_error); + printf ("\tMain error %g\n", main_error); + printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f\n", + ao_test_max_height, ao_test_max_height_time, + ao_test_main_height, ao_test_main_height_time); + printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f\n", + drogue_height, drogue_time, main_height, main_time); + exit (1); } + exit(0); } void @@ -228,8 +283,9 @@ ao_sleep(void *wchan) if (!fgets(line, sizeof (line), emulator_in)) { if (++ao_eof_read >= 1000) { - printf ("no more data, exiting simulation\n"); - exit(0); + if (!ao_summary) + printf ("no more data, exiting simulation\n"); + ao_test_exit(); } ao_adc_static.tick += 10; ao_insert(); @@ -247,10 +303,10 @@ ao_sleep(void *wchan) tick = strtoul(words[1], NULL, 16); a = strtoul(words[2], NULL, 16); b = strtoul(words[3], NULL, 16); - } else if (nword >= 6 && strcmp(words[0], "Accel")) { + } 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]); - } else if (nword >= 4 && strcmp(words[0], "Main")) { + } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { ao_config.main_deploy = atoi(words[2]); } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { tick = atoi(words[10]); @@ -308,21 +364,17 @@ ao_sleep(void *wchan) void ao_dump_state(void) { - if (ao_flight_state == ao_flight_startup) - return; - if (ao_summary) - return; - if (ao_flight_state == ao_flight_landed) - exit(0); } static const struct option options[] = { { .name = "summary", .has_arg = 0, .val = 's' }, + { .name = "debug", .has_arg = 0, .val = 'd' }, { 0, 0, 0, 0}, }; void run_flight_fixed(char *name, FILE *f, int summary) { + emulator_name = name; emulator_in = f; ao_summary = summary; ao_flight_init(); @@ -336,11 +388,19 @@ main (int argc, char **argv) int c; int i; - while ((c = getopt_long(argc, argv, "s", options, NULL)) != -1) { +#if HAS_ACCEL + emulator_app="full"; +#else + emulator_app="baro"; +#endif + while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) { switch (c) { case 's': summary = 1; break; + case 'd': + ao_flight_debug = 1; + break; } } diff --git a/src/test/run-one b/src/test/run-one index f9d21576..d661abec 100755 --- a/src/test/run-one +++ b/src/test/run-one @@ -1,17 +1,24 @@ #!/bin/sh -./ao_flight_test "$1" > run-out.full -./ao_flight_test_baro "$1" > run-out.baro -./ao_flight_test_accel "$1" > run-out.accel +for i in "$@"; do +./ao_flight_test "$i" > run-out.full +./ao_flight_test_baro "$i" > run-out.baro +#./ao_flight_test_accel "$i" > run-out.accel -gnuplot -persist << EOF +#"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 "$1" +set title "$i" plot "run-out.full" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ "run-out.full" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\ "run-out.full" using 1:9 with lines lt 2 axes x1y1 title "full height",\ @@ -23,10 +30,7 @@ plot "run-out.full" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height", "run-out.baro" using 1:11 with lines lt 3 axes x1y2 title "baro speed",\ "run-out.baro" using 1:13 with lines lt 3 axes x1y2 title "baro accel",\ "run-out.baro" using 1:15 with lines lt 3 axes x1y1 title "baro drogue",\ -"run-out.baro" using 1:17 with lines lt 3 axes x1y1 title "baro main",\ -"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" +"run-out.baro" using 1:17 with lines lt 3 axes x1y1 title "baro main" +pause mouse close EOF +done \ No newline at end of file diff --git a/src/test/run-tests b/src/test/run-tests index ec279776..11b4c95c 100755 --- a/src/test/run-tests +++ b/src/test/run-tests @@ -2,21 +2,21 @@ DIR=~/src/cc1111/flights +bad_baro=0 +bad_full=0 while read flight; do - baro=`./ao_flight_test_baro -s $DIR/$flight | - awk '/drogue/ { printf "%s ", $4 } - /main/ { printf "%s\n", $4 }'` - full=`./ao_flight_test -s $DIR/$flight | - awk '/drogue/ { printf "%s ", $4 } - /main/ { printf "%s\n", $4 }'` - echo $flight $baro $full -done < test-flights | -awk '{ name = $1; - drogue_error = $2 - $4; - if (drogue_error < 0) drogue_error = -drogue_error; - main_error = $3 - $5; - if (main_error < 0) main_error = -main_error; - if (drogue_error > 4 || main_error > 4) - printf ("%s: baro drogue %f main %f. full drogue %f main %f\n", - name, $2, $3, $4, $5); - }' + if ./ao_flight_test_baro -s $DIR/$flight; then + : + else + ((bad_baro++)) + fi + if ./ao_flight_test -s $DIR/$flight; then + : + else + ((bad_full++)) + fi +done < test-flights +echo baro errors $bad_baro +echo full errors $bad_full +((bad = bad_baro + bad_full)) +exit $bad \ No newline at end of file diff --git a/src/test/test-flights b/src/test/test-flights index afdaba5a..0b90d9e0 100644 --- a/src/test/test-flights +++ b/src/test/test-flights @@ -63,7 +63,6 @@ 2010-09-24-serial-236-flight-006.eeprom 2010-09-25-serial-223-flight-001.eeprom 2010-10-17-serial-215-flight-006.eeprom -2010-10-23-serial-236-flight-008.eeprom 2011-01-30-serial-056-flight-001.eeprom 2011-01-30-serial-250-flight-002.eeprom 2011-02-19-serial-215-flight-007.eeprom -- cgit v1.2.3 From 43a94380032300a2e33e1faa1efe93e858e0a2cf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 23 Mar 2011 10:37:39 +0900 Subject: altos: Exit flight test at landing. Allow description in test flight list Signed-off-by: Keith Packard --- src/ao_flight_test.c | 77 +++++++++++++++++++++++++++------------------------- src/test/run-one | 3 +- src/test/run-tests | 2 +- 3 files changed, 43 insertions(+), 39 deletions(-) (limited to 'src/test') diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 51a5965c..91aa0f73 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -130,7 +130,7 @@ int ao_flight_debug; FILE *emulator_in; char *emulator_app; char *emulator_name; -double emulator_error_max = 10; +double emulator_error_max = 4; void ao_dump_state(void); @@ -189,6 +189,33 @@ static double ao_test_max_height_time; static int ao_test_main_height; static double ao_test_main_height_time; +void +ao_test_exit(void) +{ + double drogue_error; + double main_error; + + if (!ao_test_main_height_time) { + ao_test_main_height_time = ao_test_max_height_time; + ao_test_main_height = ao_test_max_height; + } + drogue_error = fabs(ao_test_max_height_time - drogue_time); + main_error = fabs(ao_test_main_height_time - main_time); + if (drogue_error > emulator_error_max || main_error > emulator_error_max) { + printf ("%s %s\n", + emulator_app, emulator_name); + printf ("\tApogee error %g\n", drogue_error); + printf ("\tMain error %g\n", main_error); + printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f\n", + ao_test_max_height, ao_test_max_height_time, + ao_test_main_height, ao_test_main_height_time); + printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f\n", + drogue_height, drogue_time, main_height, main_time); + exit (1); + } + exit(0); +} + void ao_insert(void) { @@ -207,6 +234,16 @@ ao_insert(void) tick_offset += 65536; prev_tick = ao_adc_static.tick; time = (double) (ao_adc_static.tick + tick_offset) / 100; + + if (ao_test_max_height < height) { + ao_test_max_height = height; + ao_test_max_height_time = time; + } + if (height > ao_config.main_deploy) { + ao_test_main_height_time = time; + ao_test_main_height = height; + } + if (!ao_summary) { printf("%7.2f height %g accel %g state %s k_height %g k_speed %g k_accel %g drogue %d main %d error %d\n", time, @@ -219,44 +256,10 @@ ao_insert(void) drogue_height, main_height, ao_error_h_sq_avg); + if (ao_flight_state == ao_flight_landed) + ao_test_exit(); } - - if (ao_test_max_height < height) { - ao_test_max_height = height; - ao_test_max_height_time = time; - } - if (height > ao_config.main_deploy) { - ao_test_main_height_time = time; - ao_test_main_height = height; - } - } -} - -void -ao_test_exit(void) -{ - double drogue_error; - double main_error; - - if (!ao_test_main_height_time) { - ao_test_main_height_time = ao_test_max_height_time; - ao_test_main_height = ao_test_max_height; - } - drogue_error = fabs(ao_test_max_height_time - drogue_time); - main_error = fabs(ao_test_main_height_time - main_time); - if (drogue_error > emulator_error_max || main_error > emulator_error_max) { - printf ("%s %s\n", - emulator_app, emulator_name); - printf ("\tApogee error %g\n", drogue_error); - printf ("\tMain error %g\n", main_error); - printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f\n", - ao_test_max_height, ao_test_max_height_time, - ao_test_main_height, ao_test_main_height_time); - printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f\n", - drogue_height, drogue_time, main_height, main_time); - exit (1); } - exit(0); } void diff --git a/src/test/run-one b/src/test/run-one index d661abec..7d0f95ae 100755 --- a/src/test/run-one +++ b/src/test/run-one @@ -3,13 +3,14 @@ for i in "$@"; do ./ao_flight_test "$i" > run-out.full ./ao_flight_test_baro "$i" > run-out.baro -#./ao_flight_test_accel "$i" > run-out.accel +#./ao_flight_test_accel "$i" > 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)" diff --git a/src/test/run-tests b/src/test/run-tests index 11b4c95c..3e0cad3c 100755 --- a/src/test/run-tests +++ b/src/test/run-tests @@ -4,7 +4,7 @@ DIR=~/src/cc1111/flights bad_baro=0 bad_full=0 -while read flight; do +while read flight description; do if ./ao_flight_test_baro -s $DIR/$flight; then : else -- cgit v1.2.3 From 1e976a105423f2da1842f70da531c9051ba88a7f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 23 Mar 2011 10:42:31 +0900 Subject: Add description to test flights --- src/test/test-flights | 140 +++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 70 deletions(-) (limited to 'src/test') diff --git a/src/test/test-flights b/src/test/test-flights index 0b90d9e0..f6b3b992 100644 --- a/src/test/test-flights +++ b/src/test/test-flights @@ -1,70 +1,70 @@ -2009-06-03-serial-003-flight-002.eeprom -2009-06-05-serial-004-flight-008.eeprom -2009-06-06-serial-004-flight-009.eeprom -2009-06-14-serial-004-flight-010.eeprom -2009-06-20-serial-003-flight-003.eeprom -2009-07-04-serial-001-flight-006.eeprom -2009-07-18-serial-001-flight-007.eeprom -2009-08-22-serial-001-flight-001.eeprom -2009-08-22-serial-010-flight-001.eeprom -2009-09-05-serial-010-flight-002.eeprom -2009-09-05-serial-011-flight-001.eeprom -2009-09-11-serial-008-flight-003.eeprom -2009-09-12-serial-002-flight-002.eeprom -2009-09-12-serial-008-flight-005.eeprom -2009-09-12-serial-008-flight-007.eeprom -2009-09-19-serial-011-flight-002.eeprom -2009-10-03-serial-008-flight-009.eeprom -2009-10-03-serial-008-flight-010.eeprom -2009-10-03-serial-009-flight-001.eeprom -2009-10-03-serial-011-flight-003.eeprom -2009-10-17-serial-009-flight-002.eeprom -2009-11-14-serial-003-flight-005.eeprom -2009-11-14-serial-003-flight-006.eeprom -2009-11-21-serial-013-flight-001.eeprom -2009-11-21-serial-013-flight-002.eeprom -2010-02-13-serial-051-flight-002.eeprom -2010-02-13-serial-052-flight-002.eeprom -2010-02-28-serial-052-flight-003.eeprom -2010-02-28-serial-052-flight-004.eeprom -2010-03-06-serial-010-flight-004.eeprom -2010-03-06-serial-013-flight-003.eeprom -2010-03-06-serial-051-flight-003.eeprom -2010-03-06-serial-053-flight-004.eeprom -2010-05-08-serial-229-flight-002.eeprom -2010-05-28-serial-215-flight-002.eeprom -2010-05-28-serial-224-flight-001.eeprom -2010-05-29-serial-052-flight-005.eeprom -2010-05-30-serial-010-flight-005.eeprom -2010-05-30-serial-051-flight-004.eeprom -2010-05-30-serial-224-flight-003.eeprom -2010-05-30-serial-226-flight-001.eeprom -2010-05-31-serial-010-flight-006.eeprom -2010-05-31-serial-216-flight-001.eeprom -2010-05-31-serial-219-flight-001.eeprom -2010-05-31-serial-227-flight-003.eeprom -2010-06-05-serial-220-flight-001.eeprom -2010-06-26-serial-209-flight-003.eeprom -2010-06-26-serial-215-flight-004.eeprom -2010-06-26-serial-220-flight-002.eeprom -2010-06-26-serial-226-flight-002.eeprom -2010-06-27-serial-221-flight-002.eeprom -2010-07-17-serial-230-flight-001.eeprom -2010-07-18-serial-219-flight-002.eeprom -2010-08-07-serial-216-flight-003.eeprom -2010-08-07-serial-220-flight-003.eeprom -2010-08-12-serial-236-flight-001.eeprom -2010-08-21-serial-010-flight-007.eeprom -2010-08-21-serial-224-flight-004.eeprom -2010-08-21-serial-224-flight-005.eeprom -2010-08-21-serial-233-flight-002.eeprom -2010-09-03-serial-051-flight-005.eeprom -2010-09-03-serial-215-flight-005.eeprom -2010-09-24-serial-236-flight-006.eeprom -2010-09-25-serial-223-flight-001.eeprom -2010-10-17-serial-215-flight-006.eeprom -2011-01-30-serial-056-flight-001.eeprom -2011-01-30-serial-250-flight-002.eeprom -2011-02-19-serial-215-flight-007.eeprom -2011-02-19-serial-216-flight-006.eeprom -2011-02-19-serial-286-flight-001.eeprom +2009-06-03-serial-003-flight-002.eeprom PSAS flight on research motor.Lots of ugly bumps. +2009-06-05-serial-004-flight-008.eeprom Add June 2009 Lil Nuke flight +2009-06-06-serial-004-flight-009.eeprom Another Lil nuke flight? 700m, subsonic. +2009-06-14-serial-004-flight-010.eeprom Lil nuke flies again. 450m, subsonic. +2009-06-20-serial-003-flight-003.eeprom Transonic flight. 2100m, single deploy. +2009-07-04-serial-001-flight-006.eeprom Subsonic, 1100m, noisy descent. +2009-07-18-serial-001-flight-007.eeprom Transonic, 1900m, noisy descent. +2009-08-22-serial-001-flight-001.eeprom Transonic 2200m. noisy descent +2009-08-22-serial-010-flight-001.eeprom Subsonic, laggy baro. 400m +2009-09-05-serial-010-flight-002.eeprom Subsonic, fairly quick baro. 600m +2009-09-05-serial-011-flight-001.eeprom Subsonic, 1800m. Early Ejection confuses apogee detect. +2009-09-11-serial-008-flight-003.eeprom Subsonic, 200m, early ejection. +2009-09-12-serial-002-flight-002.eeprom Subsonic. 1200m. Very nice baro velocity +2009-09-12-serial-008-flight-005.eeprom Low flight. 220m, 100m/s. +2009-09-12-serial-008-flight-007.eeprom Model flight. +2009-09-19-serial-011-flight-002.eeprom Subsonic, but noisy baro. +2009-10-03-serial-008-flight-009.eeprom Transonic baro bump. 1600m. +2009-10-03-serial-008-flight-010.eeprom Barely transonic, but other baro bumps. +2009-10-03-serial-009-flight-001.eeprom Add Ofest ToT flight (drag race with Candy Cane). subsonic, but a bit of baro noise. +2009-10-03-serial-011-flight-003.eeprom Add Ofest G-spot flight. transonic bump, ugly looking data. +2009-10-17-serial-009-flight-002.eeprom Clean looking subsonic flight, small baro slump at max-Q +2009-11-14-serial-003-flight-005.eeprom Model flight. +2009-11-14-serial-003-flight-006.eeprom Model flight. +2009-11-21-serial-013-flight-001.eeprom ToT AMW J450ST with Jason Chamberlin strontium nitrate igniter +2009-11-21-serial-013-flight-002.eeprom ToT - CTI 1009J420CL pro38 6xl +2010-02-13-serial-051-flight-002.eeprom G-Spot at Albuquerque Rocket Society launch site in Rio Rancho, NM Cesaroni 229H255WT-14A +2010-02-13-serial-052-flight-002.eeprom Add Grappler flight at OROC February model launch +2010-02-28-serial-052-flight-003.eeprom LDDD Tillamook airport, 2010-02-28, H252 +2010-02-28-serial-052-flight-004.eeprom LDDD Tillamook airport, 2010-02-28, I161 +2010-03-06-serial-010-flight-004.eeprom Robert's Lil Nuke at Hudson Ranch on a CTI 108G57CL Pro29 +2010-03-06-serial-013-flight-003.eeprom Trick-O-Treat at Hudson Ranch on a J595BS +2010-03-06-serial-051-flight-003.eeprom G-Spot at Hudson Ranch on an H180W +2010-03-06-serial-053-flight-004.eeprom Horizon Rebuilt at Hudson Ranch on a J530IM with MAWD as backup +2010-05-08-serial-229-flight-002.eeprom First customer flight on a sparky. +2010-05-28-serial-215-flight-002.eeprom Mike's L1 cert flight. Congrats! +2010-05-28-serial-224-flight-001.eeprom Bill Mott's amram +2010-05-29-serial-052-flight-005.eeprom LDDD on J335 at MHM +2010-05-30-serial-010-flight-005.eeprom Robert's Lil Nuke on a 84G88 Smoky Sam at Mile High Mayhem 2010 Version 0.1 TeleMetrum with 5010 GPS board. +2010-05-30-serial-051-flight-004.eeprom Bdale's G-Spot on a CTI 298H159 Green3 at Mile High Mayhem 2010 +2010-05-30-serial-224-flight-003.eeprom Bill Mott's L3 cert flight +2010-05-30-serial-226-flight-001.eeprom Robert's RG-2 on a 159G54RL at Mile High Mayhem. Very noise accel data, early apogee +2010-05-31-serial-010-flight-006.eeprom Robert's Lil Nuke with a v0.1 TeleMetrum and 5010 GPS board flying on a 159G118 Blue Streak on the last day of Mile High Mayhem 2010 +2010-05-31-serial-216-flight-001.eeprom Sharp Stick in the Sky on an "I something" EX motor from James Russell +2010-05-31-serial-219-flight-001.eeprom Candy Cane on CTI K300 at MHM. +2010-05-31-serial-227-flight-003.eeprom Mike's Rocket on J285 for successful L2 cert at MHM +2010-06-05-serial-220-flight-001.eeprom Mini-mmuchness on 159G54RL, Sunday at MHM 2010 +2010-06-26-serial-209-flight-003.eeprom Tripoli Colorado Spring Fling with COSROCS at the Buffalo Ranch +2010-06-26-serial-215-flight-004.eeprom Tripoli Colorado Spring Fling with COSROCS at the Buffalo Ranch +2010-06-26-serial-220-flight-002.eeprom Mini Mmuchness on CTI H120CL to 1975m, OROC June 2010 +2010-06-26-serial-226-flight-002.eeprom Tripoli Colorado Spring Fling with COSROCS at the Buffalo Ranch +2010-06-27-serial-221-flight-002.eeprom PSAS LV2c on N2000 at OROC june launch +2010-07-17-serial-230-flight-001.eeprom Mike Ward's Level 1 cert flight on H225 +2010-07-18-serial-219-flight-002.eeprom MMuchness on M1230 for successful L3 cert flight +2010-08-07-serial-216-flight-003.eeprom Sharp stick on I300T at Metra's august launch. Main out at apogee. +2010-08-07-serial-220-flight-003.eeprom Mini-mmuchness flight at Metra after debconf. Unstable on G80. ABNORMAL FLIGHT. +2010-08-12-serial-236-flight-001.eeprom Edgar's L1 flight, Madcow Momba on Aerotech H128 +2010-08-21-serial-010-flight-007.eeprom Robert's Lil Nuke, flying on a CTI Pro29 2-grain 110G250 Vmax. Just awesome! PFND. +2010-08-21-serial-224-flight-004.eeprom Anthony Towns' LDDD clone, successful L1 cert on a CTI Pro38 2-grain 266H125 classic. Airframe was set up for apogee-only with motor based ejection. The BP charge was larger than necessary, caused nose cone to snap back against aft airframe. Minor damage to leading edge of aft airframe, big chunk of the nose cone skin cracked away. Same problem Bdale saw on Sharp Stick's nosecone, also from Performance Rocketry, where there was apparently an air bubble below the gel coat. Determination was that damage was cosmetic and would not affect cert... confirmed by successful L2 later in the day! +2010-08-21-serial-224-flight-005.eeprom Anthony Towns' LDDD clone, successful L2 cert on a CTI Pro38 5-grain 58J357 blue streak. Perfect drogueless dual deploy! 0.8-0.9 grams aft charge and about 1.0 grams forward. Flew without ground testing charges due to time pressure before waiver closed for the day. About as close to the waiver as you'd ever want to be on a cert flight, again demonstrating that OpenRocket under-estimates apogee ... approximately 6800 ft predicted... +2010-08-21-serial-233-flight-002.eeprom Tim van Milligan's 5.5" L2 airframe, flying on a CTI Pro38 6-grain 774J410 red, TM indicated a problem with the apogee igniter continuity, noticed during countdown, turned out to be a loose wire! Perfect dual deploy flight once that was fixed. +2010-09-03-serial-051-flight-005.eeprom G-spot on an old Aerotech H125-20W single use 29mm motor. It appears the ejection at apogee actually happened much later, perhaps as much as 10 seconds late! +2010-09-03-serial-215-flight-005.eeprom Horizon Rebuild on a K490 Green3 reload. PFND. About 1.4 grams each end. +2010-09-24-serial-236-flight-006.eeprom LDDD on I236 in Sheridan on 2010-09-24 to 1216m +2010-09-25-serial-223-flight-001.eeprom Bdale's 10" Goblin, flying on a CTI Pro75 M1300 Imax dual thrust during Chili Blaster 2 at Hudson Ranch. First flight after rebuild to do dual deploy from one bay with ARRD and 15' surplus "+ sign" parachute. +2010-10-17-serial-215-flight-006.eeprom Horizon Rebuild on CTI J595BS at Tripoli Colorado launch site near Hartsel, CO +2011-01-30-serial-056-flight-001.eeprom Group project 5.5" Polecat Thumper airframe built in the Quay West Suites in Brisbane, Australia, during LCA 2011 by Bdale, Keith, Mike Beattie, and Anthony Towns. Flown at QRS club launch on an Aerotech J315R 54mm 2-grain motor. +2011-01-30-serial-250-flight-002.eeprom Group project 5.5" Polecat Thumper airframe built in the Quay West Suites in Brisbane, Australia, during LCA 2011 by Bdale, Keith, Mike Beattie, and Anthony Towns. Flown at QRS club launch on an Aerotech J315R 54mm 2-grain motor. +2011-02-19-serial-215-flight-007.eeprom Horizon Rebuild on a CTI Pro38 6xl J600R at Hudson Ranch 1.0 grams BP rear, 1.5 grams front Perfect drogueless dual deploy flight with no damage! +2011-02-19-serial-216-flight-006.eeprom Sharp Stick on a CTI Pro38 3-grain I345WT at Hudson Ranch Added more kevlar to the aft end, flew with 1.3 grams BP rear and 1.0 front. Perfect drogueless dual deploy flight, and no damage! +2011-02-19-serial-286-flight-001.eeprom Vertical Assault on a CTI Pro38 6xl J595BS at Hudson Ranch 1.5 grams BP rear, 1.8 grams BP front Perfect drogueless dual deploy flight, with no damage! -- cgit v1.2.3 From a9dae18a664f70b668159487015e61be7f776926 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 31 Mar 2011 20:51:15 -0700 Subject: altos: Reflect ao_flight split in ao_flight_test dependencies Need to rebuild ao_flight_test when any of the flight sources change Signed-off-by: Keith Packard --- src/test/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/test') diff --git a/src/test/Makefile b/src/test/Makefile index 433f749b..33203ffd 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -12,13 +12,13 @@ clean: install: -ao_flight_test: ao_flight_test.c ao_host.h ao_flight.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 ao_kalman.h cc -g -o $@ $< -ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.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 altitude.h ao_kalman.h cc -g -o $@ -DHAS_ACCEL=0 ../ao_flight_test.c -ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.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 altitude.h ao_kalman.h cc -g -o $@ -DFORCE_ACCEL=1 ../ao_flight_test.c ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h -- cgit v1.2.3 From 9513be7f9d3d0b0ec29f6487fa9dc8f1ac24d0de Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Aug 2011 20:43:44 -0700 Subject: altos: Restructure altos build to prepare for multi-arch support Split out sources into separate directories: core: architecture and product independent bits cc1111: cc1111-specific code drivers: architecture independent drivers product: product-specific sources and Makefile fragments util: scripts for building stuff This should have no effect on the built products, but testing is encouraged Signed-off-by: Keith Packard --- configure.ac | 2 +- src/25lc1024.h | 41 - src/Makefile | 25 +- src/Makefile.proto | 380 -------- src/_bp.c | 26 - src/altitude.h | 132 --- src/ao-make-product.5c | 103 -- src/ao.h | 1610 -------------------------------- src/ao_adc.c | 196 ---- src/ao_adc_fake.c | 27 - src/ao_beep.c | 52 -- src/ao_btm.c | 302 ------ src/ao_cmd.c | 320 ------- src/ao_companion.c | 132 --- src/ao_config.c | 542 ----------- src/ao_convert.c | 85 -- src/ao_convert_test.c | 75 -- src/ao_dbg.c | 364 -------- src/ao_dma.c | 131 --- src/ao_ee.c | 241 ----- src/ao_ee_fake.c | 37 - src/ao_flash.c | 318 ------- src/ao_flight.c | 315 ------- src/ao_flight_nano.c | 120 --- src/ao_flight_test.c | 716 -------------- src/ao_gps_print.c | 112 --- src/ao_gps_report.c | 99 -- src/ao_gps_sirf.c | 442 --------- src/ao_gps_skytraq.c | 490 ---------- src/ao_gps_test.c | 508 ---------- src/ao_gps_test_skytraq.c | 490 ---------- src/ao_host.h | 127 --- src/ao_ignite.c | 218 ----- src/ao_intflash.c | 209 ----- src/ao_kalman.c | 292 ------ src/ao_led.c | 61 -- src/ao_log.c | 284 ------ src/ao_log_big.c | 158 ---- src/ao_log_telem.c | 30 - src/ao_log_tiny.c | 161 ---- src/ao_m25.c | 380 -------- src/ao_main.c | 43 - src/ao_monitor.c | 277 ------ src/ao_mutex.c | 41 - src/ao_packet.c | 148 --- src/ao_packet_master.c | 144 --- src/ao_packet_slave.c | 64 -- src/ao_panic.c | 66 -- src/ao_pins.h | 408 -------- src/ao_product.c | 155 --- src/ao_radio.c | 475 ---------- src/ao_reboot.c | 28 - src/ao_report.c | 180 ---- src/ao_romconfig.c | 32 - src/ao_rssi.c | 53 -- src/ao_sample.c | 209 ----- src/ao_serial.c | 175 ---- src/ao_spi.c | 157 ---- src/ao_state.c | 23 - src/ao_stdio.c | 84 -- src/ao_storage.c | 184 ---- src/ao_task.c | 275 ------ src/ao_telebt.c | 50 - src/ao_teledongle.c | 40 - src/ao_telem.h | 172 ---- src/ao_telemetrum.c | 70 -- src/ao_telemetry.c | 270 ------ src/ao_telemini.c | 49 - src/ao_telenano.c | 43 - src/ao_teleterra.c | 38 - src/ao_test.c | 117 --- src/ao_tidongle.c | 42 - src/ao_timer.c | 111 --- src/ao_usb.c | 460 --------- src/ao_usb.h | 100 -- src/at45db161d.h | 45 - src/cc1111.h | 1306 -------------------------- src/cc1111/Makefile.cc1111 | 27 + src/cc1111/_bp.c | 26 + src/cc1111/ao_adc.c | 196 ++++ src/cc1111/ao_beep.c | 52 ++ src/cc1111/ao_dbg.c | 364 ++++++++ src/cc1111/ao_dma.c | 131 +++ src/cc1111/ao_ignite.c | 218 +++++ src/cc1111/ao_intflash.c | 209 +++++ src/cc1111/ao_led.c | 61 ++ src/cc1111/ao_packet.c | 148 +++ src/cc1111/ao_packet_master.c | 144 +++ src/cc1111/ao_packet_slave.c | 64 ++ src/cc1111/ao_radio.c | 475 ++++++++++ src/cc1111/ao_reboot.c | 28 + src/cc1111/ao_romconfig.c | 32 + src/cc1111/ao_serial.c | 175 ++++ src/cc1111/ao_spi.c | 157 ++++ src/cc1111/ao_timer.c | 111 +++ src/cc1111/ao_usb.c | 460 +++++++++ src/cc1111/ao_usb.h | 100 ++ src/cc1111/cc1111.h | 1306 ++++++++++++++++++++++++++ src/check-stack | 13 - src/core/altitude.h | 132 +++ src/core/ao.h | 1610 ++++++++++++++++++++++++++++++++ src/core/ao_cmd.c | 320 +++++++ src/core/ao_config.c | 542 +++++++++++ src/core/ao_convert.c | 85 ++ src/core/ao_convert_test.c | 75 ++ src/core/ao_ee_fake.c | 37 + src/core/ao_flight.c | 315 +++++++ src/core/ao_flight_nano.c | 120 +++ src/core/ao_gps_print.c | 112 +++ src/core/ao_gps_report.c | 99 ++ src/core/ao_host.h | 127 +++ src/core/ao_kalman.c | 292 ++++++ src/core/ao_log.c | 284 ++++++ src/core/ao_log_big.c | 158 ++++ src/core/ao_log_telem.c | 30 + src/core/ao_log_tiny.c | 161 ++++ src/core/ao_monitor.c | 277 ++++++ src/core/ao_mutex.c | 41 + src/core/ao_panic.c | 66 ++ src/core/ao_pins.h | 408 ++++++++ src/core/ao_product.c | 155 +++ src/core/ao_report.c | 180 ++++ src/core/ao_rssi.c | 53 ++ src/core/ao_sample.c | 209 +++++ src/core/ao_state.c | 23 + src/core/ao_stdio.c | 84 ++ src/core/ao_storage.c | 184 ++++ src/core/ao_task.c | 275 ++++++ src/core/ao_telem.h | 172 ++++ src/core/ao_telemetry.c | 270 ++++++ src/drivers/ao_25lc1024.c | 241 +++++ src/drivers/ao_25lc1024.h | 41 + src/drivers/ao_at45db161d.c | 318 +++++++ src/drivers/ao_at45db161d.h | 45 + src/drivers/ao_btm.c | 302 ++++++ src/drivers/ao_companion.c | 132 +++ src/drivers/ao_gps_sirf.c | 442 +++++++++ src/drivers/ao_gps_skytraq.c | 490 ++++++++++ src/drivers/ao_m25.c | 380 ++++++++ src/gps-cksum | 17 - src/make-altitude | 283 ------ src/make-kalman | 19 - src/product/Makefile.telebt | 97 ++ src/product/Makefile.teledongle | 96 ++ src/product/Makefile.telemetrum | 111 +++ src/product/Makefile.telemini | 100 ++ src/product/Makefile.telenano | 99 ++ src/product/ao_telebt.c | 50 + src/product/ao_teledongle.c | 40 + src/product/ao_telemetrum.c | 70 ++ src/product/ao_telemini.c | 49 + src/product/ao_telenano.c | 43 + src/product/ao_teleterra.c | 38 + src/product/ao_test.c | 117 +++ src/product/ao_tidongle.c | 42 + src/sirf-cksum | 44 - src/skytraq-cksum | 44 - src/telebt-v0.0/Makefile | 10 +- src/telebt-v0.0/Makefile.defs | 8 - src/telebt-v0.1/Makefile | 20 +- src/telebt-v0.1/Makefile.defs | 8 - src/teledongle-v0.1/Makefile | 9 +- src/teledongle-v0.1/Makefile.defs | 9 - src/teledongle-v0.2/Makefile | 9 +- src/teledongle-v0.2/Makefile.defs | 9 - src/telemetrum-v0.1-sirf/Makefile | 17 +- src/telemetrum-v0.1-sirf/Makefile.defs | 12 - src/telemetrum-v0.1-sky/Makefile | 17 +- src/telemetrum-v0.1-sky/Makefile.defs | 12 - src/telemetrum-v1.0/Makefile | 17 +- src/telemetrum-v1.0/Makefile.defs | 13 - src/telemetrum-v1.1/Makefile | 17 +- src/telemetrum-v1.1/Makefile.defs | 13 - src/telemini-v1.0/Makefile | 9 +- src/telemini-v1.0/Makefile.defs | 9 - src/telenano-v0.1/Makefile | 10 +- src/telenano-v0.1/Makefile.defs | 9 - src/test/Makefile | 20 +- src/test/ao_flight_test.c | 716 ++++++++++++++ src/test/ao_gps_test.c | 508 ++++++++++ src/test/ao_gps_test_skytraq.c | 490 ++++++++++ src/tidongle/Makefile | 93 +- src/tidongle/Makefile.defs | 9 - src/util/ao-make-product.5c | 103 ++ src/util/check-stack | 13 + src/util/gps-cksum | 17 + src/util/make-altitude | 283 ++++++ src/util/make-kalman | 19 + src/util/sirf-cksum | 44 + src/util/skytraq-cksum | 44 + 190 files changed, 17208 insertions(+), 17018 deletions(-) delete mode 100644 src/25lc1024.h delete mode 100644 src/Makefile.proto delete mode 100644 src/_bp.c delete mode 100644 src/altitude.h delete mode 100644 src/ao-make-product.5c delete mode 100644 src/ao.h delete mode 100644 src/ao_adc.c delete mode 100644 src/ao_adc_fake.c delete mode 100644 src/ao_beep.c delete mode 100644 src/ao_btm.c delete mode 100644 src/ao_cmd.c delete mode 100644 src/ao_companion.c delete mode 100644 src/ao_config.c delete mode 100644 src/ao_convert.c delete mode 100644 src/ao_convert_test.c delete mode 100644 src/ao_dbg.c delete mode 100644 src/ao_dma.c delete mode 100644 src/ao_ee.c delete mode 100644 src/ao_ee_fake.c delete mode 100644 src/ao_flash.c delete mode 100644 src/ao_flight.c delete mode 100644 src/ao_flight_nano.c delete mode 100644 src/ao_flight_test.c delete mode 100644 src/ao_gps_print.c delete mode 100644 src/ao_gps_report.c delete mode 100644 src/ao_gps_sirf.c delete mode 100644 src/ao_gps_skytraq.c delete mode 100644 src/ao_gps_test.c delete mode 100644 src/ao_gps_test_skytraq.c delete mode 100644 src/ao_host.h delete mode 100644 src/ao_ignite.c delete mode 100644 src/ao_intflash.c delete mode 100644 src/ao_kalman.c delete mode 100644 src/ao_led.c delete mode 100644 src/ao_log.c delete mode 100644 src/ao_log_big.c delete mode 100644 src/ao_log_telem.c delete mode 100644 src/ao_log_tiny.c delete mode 100644 src/ao_m25.c delete mode 100644 src/ao_main.c delete mode 100644 src/ao_monitor.c delete mode 100644 src/ao_mutex.c delete mode 100644 src/ao_packet.c delete mode 100644 src/ao_packet_master.c delete mode 100644 src/ao_packet_slave.c delete mode 100644 src/ao_panic.c delete mode 100644 src/ao_pins.h delete mode 100644 src/ao_product.c delete mode 100644 src/ao_radio.c delete mode 100644 src/ao_reboot.c delete mode 100644 src/ao_report.c delete mode 100644 src/ao_romconfig.c delete mode 100644 src/ao_rssi.c delete mode 100644 src/ao_sample.c delete mode 100644 src/ao_serial.c delete mode 100644 src/ao_spi.c delete mode 100644 src/ao_state.c delete mode 100644 src/ao_stdio.c delete mode 100644 src/ao_storage.c delete mode 100644 src/ao_task.c delete mode 100644 src/ao_telebt.c delete mode 100644 src/ao_teledongle.c delete mode 100644 src/ao_telem.h delete mode 100644 src/ao_telemetrum.c delete mode 100644 src/ao_telemetry.c delete mode 100644 src/ao_telemini.c delete mode 100644 src/ao_telenano.c delete mode 100644 src/ao_teleterra.c delete mode 100644 src/ao_test.c delete mode 100644 src/ao_tidongle.c delete mode 100644 src/ao_timer.c delete mode 100644 src/ao_usb.c delete mode 100644 src/ao_usb.h delete mode 100644 src/at45db161d.h delete mode 100644 src/cc1111.h create mode 100644 src/cc1111/Makefile.cc1111 create mode 100644 src/cc1111/_bp.c create mode 100644 src/cc1111/ao_adc.c create mode 100644 src/cc1111/ao_beep.c create mode 100644 src/cc1111/ao_dbg.c create mode 100644 src/cc1111/ao_dma.c create mode 100644 src/cc1111/ao_ignite.c create mode 100644 src/cc1111/ao_intflash.c create mode 100644 src/cc1111/ao_led.c create mode 100644 src/cc1111/ao_packet.c create mode 100644 src/cc1111/ao_packet_master.c create mode 100644 src/cc1111/ao_packet_slave.c create mode 100644 src/cc1111/ao_radio.c create mode 100644 src/cc1111/ao_reboot.c create mode 100644 src/cc1111/ao_romconfig.c create mode 100644 src/cc1111/ao_serial.c create mode 100644 src/cc1111/ao_spi.c create mode 100644 src/cc1111/ao_timer.c create mode 100644 src/cc1111/ao_usb.c create mode 100644 src/cc1111/ao_usb.h create mode 100644 src/cc1111/cc1111.h delete mode 100755 src/check-stack create mode 100644 src/core/altitude.h create mode 100644 src/core/ao.h create mode 100644 src/core/ao_cmd.c create mode 100644 src/core/ao_config.c create mode 100644 src/core/ao_convert.c create mode 100644 src/core/ao_convert_test.c create mode 100644 src/core/ao_ee_fake.c create mode 100644 src/core/ao_flight.c create mode 100644 src/core/ao_flight_nano.c create mode 100644 src/core/ao_gps_print.c create mode 100644 src/core/ao_gps_report.c create mode 100644 src/core/ao_host.h create mode 100644 src/core/ao_kalman.c create mode 100644 src/core/ao_log.c create mode 100644 src/core/ao_log_big.c create mode 100644 src/core/ao_log_telem.c create mode 100644 src/core/ao_log_tiny.c create mode 100644 src/core/ao_monitor.c create mode 100644 src/core/ao_mutex.c create mode 100644 src/core/ao_panic.c create mode 100644 src/core/ao_pins.h create mode 100644 src/core/ao_product.c create mode 100644 src/core/ao_report.c create mode 100644 src/core/ao_rssi.c create mode 100644 src/core/ao_sample.c create mode 100644 src/core/ao_state.c create mode 100644 src/core/ao_stdio.c create mode 100644 src/core/ao_storage.c create mode 100644 src/core/ao_task.c create mode 100644 src/core/ao_telem.h create mode 100644 src/core/ao_telemetry.c create mode 100644 src/drivers/ao_25lc1024.c create mode 100644 src/drivers/ao_25lc1024.h create mode 100644 src/drivers/ao_at45db161d.c create mode 100644 src/drivers/ao_at45db161d.h create mode 100644 src/drivers/ao_btm.c create mode 100644 src/drivers/ao_companion.c create mode 100644 src/drivers/ao_gps_sirf.c create mode 100644 src/drivers/ao_gps_skytraq.c create mode 100644 src/drivers/ao_m25.c delete mode 100755 src/gps-cksum delete mode 100644 src/make-altitude delete mode 100644 src/make-kalman create mode 100644 src/product/Makefile.telebt create mode 100644 src/product/Makefile.teledongle create mode 100644 src/product/Makefile.telemetrum create mode 100644 src/product/Makefile.telemini create mode 100644 src/product/Makefile.telenano create mode 100644 src/product/ao_telebt.c create mode 100644 src/product/ao_teledongle.c create mode 100644 src/product/ao_telemetrum.c create mode 100644 src/product/ao_telemini.c create mode 100644 src/product/ao_telenano.c create mode 100644 src/product/ao_teleterra.c create mode 100644 src/product/ao_test.c create mode 100644 src/product/ao_tidongle.c delete mode 100755 src/sirf-cksum delete mode 100644 src/skytraq-cksum delete mode 100644 src/telebt-v0.0/Makefile.defs delete mode 100644 src/telebt-v0.1/Makefile.defs delete mode 100644 src/teledongle-v0.1/Makefile.defs delete mode 100644 src/teledongle-v0.2/Makefile.defs delete mode 100644 src/telemetrum-v0.1-sirf/Makefile.defs delete mode 100644 src/telemetrum-v0.1-sky/Makefile.defs delete mode 100644 src/telemetrum-v1.0/Makefile.defs delete mode 100644 src/telemetrum-v1.1/Makefile.defs delete mode 100644 src/telemini-v1.0/Makefile.defs delete mode 100644 src/telenano-v0.1/Makefile.defs create mode 100644 src/test/ao_flight_test.c create mode 100644 src/test/ao_gps_test.c create mode 100644 src/test/ao_gps_test_skytraq.c delete mode 100644 src/tidongle/Makefile.defs create mode 100644 src/util/ao-make-product.5c create mode 100755 src/util/check-stack create mode 100755 src/util/gps-cksum create mode 100644 src/util/make-altitude create mode 100644 src/util/make-kalman create mode 100755 src/util/sirf-cksum create mode 100644 src/util/skytraq-cksum (limited to 'src/test') diff --git a/configure.ac b/configure.ac index f9002508..da9d9991 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ dnl Process this file with autoconf to create configure. AC_PREREQ(2.57) AC_INIT([altos], 1.0) -AC_CONFIG_SRCDIR([src/ao.h]) +AC_CONFIG_SRCDIR([src/core/ao.h]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_MAINTAINER_MODE diff --git a/src/25lc1024.h b/src/25lc1024.h deleted file mode 100644 index 44e52387..00000000 --- a/src/25lc1024.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -/* Defines for the 25LC1024 1Mbit SPI Bus Serial EEPROM */ - -#ifndef _25LC1024_H_ -#define _25LC1024_H_ - -#define EE_READ 0x03 -#define EE_WRITE 0x02 -#define EE_WREN 0x06 -#define EE_WRDI 0x04 -#define EE_RDSR 0x05 -#define EE_WRSR 0x01 -#define EE_PE 0x42 -#define EE_SE 0xd8 -#define EE_CE 0xc7 -#define EE_RDID 0xab -#define EE_DPD 0xb9 - -#define EE_STATUS_WIP (1 << 0) -#define EE_STATUS_WEL (1 << 1) -#define EE_STATUS_BP0 (1 << 2) -#define EE_STATUS_BP1 (1 << 3) -#define EE_STATUS_WPEN (1 << 7) - -#endif /* _25LC1024_H_ */ diff --git a/src/Makefile b/src/Makefile index 018f0c5c..4e40c2bf 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,13 @@ # AltOS build # # -CC=sdcc + +vpath make-altitude util +vpath make-kalman util +vpath kalman.5c kalman +vpath kalman_filter.5c kalman +vpath load_csv.5c kalman +vpath matrix.5c kalman include Version @@ -14,7 +20,7 @@ SUBDIRS=\ telemetrum-v0.1-sky telemetrum-v0.1-sirf \ tidongle test -all: all-recursive +all: all-local all-recursive RECURSIVE_TARGETS = all-recursive clean-recursive install-recursive @@ -27,8 +33,21 @@ $(RECURSIVE_TARGETS): distclean: clean -clean: clean-recursive +clean: clean-local clean-recursive install: install-recursive uninstall: + +all-recursive: all-local + +all-local: altitude.h ao_kalman.h + +altitude.h: make-altitude + nickle $< > $@ + +ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c + sh $< kalman > $@ + +clean-local: + rm -f altitude.h ao_kalman.h \ No newline at end of file diff --git a/src/Makefile.proto b/src/Makefile.proto deleted file mode 100644 index 8f98d354..00000000 --- a/src/Makefile.proto +++ /dev/null @@ -1,380 +0,0 @@ -# -# AltOS build -# -# -vpath %.c .. -vpath %.h .. -vpath make-altitude .. -vpath make-kalman .. -vpath kalman.5c ../kalman -vpath kalman_filter.5c ../kalman -vpath load_csv.5c ../kalman -vpath matrix.5c ../kalman -vpath ao-make-product.5c .. - -CC=sdcc - -ifndef VERSION -include ../Version -endif - -CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE) - -CODESIZE ?= 0x8000 - -LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size $(CODESIZE) \ - --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff - -INC = \ - ao.h \ - ao_pins.h \ - cc1111.h \ - altitude.h \ - ao_kalman.h \ - 25lc1024.h - -# -# Common AltOS sources -# -ALTOS_SRC = \ - ao_cmd.c \ - ao_dma.c \ - ao_mutex.c \ - ao_panic.c \ - ao_task.c \ - ao_timer.c \ - ao_romconfig.c \ - _bp.c - -# -# Shared AltOS drivers -# -ALTOS_DRIVER_SRC = \ - ao_config.c \ - ao_led.c \ - ao_radio.c \ - ao_stdio.c - -BEEP_DRIVER_SRC = \ - ao_beep.c - -USB_DRIVER_SRC = \ - ao_usb.c - -TELE_COMMON_SRC = \ - ao_packet.c - -# -# Receiver code -# -TELE_RECEIVER_SRC =\ - ao_monitor.c \ - ao_gps_print.c \ - ao_packet_master.c \ - ao_state.c \ - ao_rssi.c - -# -# Shared Tele drivers (on TeleMetrum, TeleTerra, TeleDongle) -# - -TELE_DRIVER_SRC = \ - ao_convert.c - -# -# Serial port driver -# -SERIAL_DRIVER_SRC = \ - ao_serial.c - -# -# Spi bus driver -# -SPI_DRIVER_SRC = \ - ao_spi.c - -# -# Debug dongle driver (only on TI) -# -DBG_SRC = \ - ao_dbg.c - -# -# Drivers only on TeleMetrum -# -TM_DRIVER_SRC = \ - ao_adc.c \ - ao_gps_report.c \ - ao_ignite.c \ - ao_packet_slave.c \ - $(BEEP_DRIVER_SRC) \ - $(USB_DRIVER_SRC) - -# -# 25LC1024 driver source -EE_DRIVER_SRC = \ - ao_storage.c \ - ao_ee.c - -# -# AT45DB161D driver source - -FLASH_DRIVER_SRC = \ - ao_storage.c \ - ao_flash.c - -# -# Numonyx M25P80 driver source -# - -M25_DRIVER_SRC = \ - ao_storage.c \ - ao_m25.c - -# -# SiRF driver source -# -SIRF_DRIVER_SRC = \ - ao_gps_sirf.c - -# -# Skytraq driver source -# -SKY_DRIVER_SRC = \ - ao_gps_skytraq.c - - -# -# BTM-182 driver source -# -BTM_DRIVER_SRC = \ - ao_btm.c - -# -# Companion port driver source -# -COMPANION_SRC = \ - ao_companion.c - -# -# Tasks run on TeleMetrum -# -TM_TASK_SRC = \ - ao_flight.c \ - ao_sample.c \ - ao_kalman.c \ - ao_log.c \ - ao_log_big.c \ - ao_report.c \ - ao_telemetry.c - -TM_MAIN_SRC = \ - ao_telemetrum.c - -# -# Base sources for TeleMetrum -# -TM_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(SERIAL_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(TM_DRIVER_SRC) \ - $(TM_TASK_SRC) \ - $(TM_MAIN_SRC) - -# -# Sources for TeleMini -TMINI_DRIVER_SRC = \ - ao_adc.c \ - ao_ignite.c \ - ao_config.c \ - ao_storage.c \ - ao_packet_slave.c \ - ao_intflash.c - -TMINI_TASK_SRC = \ - ao_flight.c \ - ao_sample.c \ - ao_kalman.c \ - ao_log.c \ - ao_log_tiny.c \ - ao_report.c \ - ao_telemetry.c - -TMINI_MAIN_SRC = \ - ao_telemini.c - -TMINI_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(TMINI_DRIVER_SRC) \ - $(TMINI_TASK_SRC) \ - $(TMINI_MAIN_SRC) - -# -# Sources for TeleNano -TNANO_DRIVER_SRC = \ - ao_adc.c \ - ao_config.c \ - ao_storage.c \ - ao_packet_slave.c \ - ao_intflash.c - -TNANO_TASK_SRC = \ - ao_flight_nano.c \ - ao_sample.c \ - ao_kalman.c \ - ao_log.c \ - ao_log_tiny.c \ - ao_report.c \ - ao_telemetry.c - -TNANO_MAIN_SRC = \ - ao_telenano.c - -TNANO_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(TNANO_DRIVER_SRC) \ - $(TNANO_TASK_SRC) \ - $(TNANO_MAIN_SRC) - -# -# Sources for TeleBluetooth -# - -TBT_MAIN_SRC = \ - ao_telebt.c - -TBT_BASE_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(SERIAL_DRIVER_SRC) \ - $(USB_DRIVER_SRC) \ - $(BTM_DRIVER_SRC) \ - $(DBG_SRC) \ - $(TBT_MAIN_SRC) - -TBT_V_0_1_SRC = \ - $(TBT_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(M25_DRIVER_SRC) \ - $(BEEP_DRIVER_SRC) \ - ao_log_telem.c - -# -# TI Dongle sources -# -TI_MAIN_SRC = \ - ao_tidongle.c - -# -# All sources for the TI debug dongle -# -TI_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(USB_DRIVER_SRC) \ - $(TI_MAIN_SRC) \ - $(DBG_SRC) - -TT_MAIN_SRC = \ - ao_teleterra.c -# -# All sources for TeleTerra -# -TT_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_DRIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(USB_DRIVER_SRC) \ - $(TT_MAIN_SRC) - - -# -# Sources for TeleDongle -# - -TD_MAIN_SRC = \ - ao_teledongle.c - -TD_SRC = \ - $(ALTOS_SRC) \ - $(ALTOS_DRIVER_SRC) \ - $(TELE_RECEIVER_SRC) \ - $(TELE_COMMON_SRC) \ - $(USB_DRIVER_SRC) \ - $(TD_MAIN_SRC) - -include Makefile.defs - -CFLAGS += $(PRODUCT_DEF) -I. - -NICKLE=nickle -CHECK_STACK=sh ../check-stack - -REL=$(SRC:.c=.rel) ao_product.rel -ADB=$(REL:.rel=.adb) -ASM=$(REL:.rel=.asm) -LNK=$(REL:.rel=.lnk) -LST=$(REL:.rel=.lst) -RST=$(REL:.rel=.rst) -SYM=$(REL:.rel=.sym) - -PCDB=$(PROG:.ihx=.cdb) -PLNK=$(PROG:.ihx=.lnk) -PMAP=$(PROG:.ihx=.map) -PMEM=$(PROG:.ihx=.mem) -PAOM=$(PROG:.ihx=) - -V=0 -# The user has explicitly enabled quiet compilation. -ifeq ($(V),0) -quiet = @printf " $1 $2 $@\n"; $($1) -endif -# Otherwise, print the full command line. -quiet ?= $($1) - -%.rel : %.c $(INC) - $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $< - -all: ../$(PROG) - -../$(PROG): $(REL) Makefile Makefile.defs ../Makefile.proto - $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. - $(call quiet,CHECK_STACK) ../ao.h $(PMEM) - -../altitude.h: make-altitude - nickle $< > $@ - -../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c - sh $< > $@ - -ao_product.h: ao-make-product.5c ../Version - $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ - -$(REL): ao_product.h - -distclean: clean - -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) - -install: - -uninstall: diff --git a/src/_bp.c b/src/_bp.c deleted file mode 100644 index 6bf135bc..00000000 --- a/src/_bp.c +++ /dev/null @@ -1,26 +0,0 @@ -/*------------------------------------------------------------------------- - - _bp.c :- just declares bp as a variable - - Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This library 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 Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this program; if not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - In other words, you are welcome to use, share and improve this program. - You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! --------------------------------------------------------------------------*/ - -__data unsigned char bp ; diff --git a/src/altitude.h b/src/altitude.h deleted file mode 100644 index a278bbc6..00000000 --- a/src/altitude.h +++ /dev/null @@ -1,132 +0,0 @@ -/*max error 3.197865153490684 at 0.782%. Average error 0.260150920474668*/ -#define NALT 129 -#define ALT_FRAC_BITS 8 - 15835, /* 10.56 kPa 0.000% */ - 15332, /* 11.42 kPa 0.781% */ - 14868, /* 12.29 kPa 1.563% */ - 14435, /* 13.16 kPa 2.344% */ - 14030, /* 14.02 kPa 3.125% */ - 13649, /* 14.90 kPa 3.906% */ - 13290, /* 15.76 kPa 4.688% */ - 12950, /* 16.63 kPa 5.469% */ - 12627, /* 17.50 kPa 6.250% */ - 12320, /* 18.37 kPa 7.031% */ - 12027, /* 19.24 kPa 7.813% */ - 11747, /* 20.10 kPa 8.594% */ - 11479, /* 20.97 kPa 9.375% */ - 11222, /* 21.84 kPa 10.156% */ - 10975, /* 22.71 kPa 10.938% */ - 10736, /* 23.58 kPa 11.719% */ - 10504, /* 24.44 kPa 12.500% */ - 10278, /* 25.31 kPa 13.281% */ - 10059, /* 26.18 kPa 14.063% */ - 9846, /* 27.05 kPa 14.844% */ - 9638, /* 27.91 kPa 15.625% */ - 9435, /* 28.78 kPa 16.406% */ - 9237, /* 29.65 kPa 17.188% */ - 9044, /* 30.52 kPa 17.969% */ - 8855, /* 31.39 kPa 18.750% */ - 8670, /* 32.26 kPa 19.531% */ - 8490, /* 33.13 kPa 20.313% */ - 8313, /* 33.99 kPa 21.094% */ - 8140, /* 34.86 kPa 21.875% */ - 7970, /* 35.73 kPa 22.656% */ - 7803, /* 36.60 kPa 23.438% */ - 7640, /* 37.47 kPa 24.219% */ - 7480, /* 38.33 kPa 25.000% */ - 7322, /* 39.20 kPa 25.781% */ - 7168, /* 40.07 kPa 26.563% */ - 7016, /* 40.94 kPa 27.344% */ - 6867, /* 41.80 kPa 28.125% */ - 6720, /* 42.67 kPa 28.906% */ - 6575, /* 43.54 kPa 29.688% */ - 6433, /* 44.41 kPa 30.469% */ - 6294, /* 45.28 kPa 31.250% */ - 6156, /* 46.15 kPa 32.031% */ - 6020, /* 47.01 kPa 32.813% */ - 5887, /* 47.88 kPa 33.594% */ - 5755, /* 48.75 kPa 34.375% */ - 5625, /* 49.62 kPa 35.156% */ - 5497, /* 50.49 kPa 35.938% */ - 5371, /* 51.35 kPa 36.719% */ - 5247, /* 52.22 kPa 37.500% */ - 5124, /* 53.09 kPa 38.281% */ - 5003, /* 53.96 kPa 39.063% */ - 4883, /* 54.83 kPa 39.844% */ - 4765, /* 55.69 kPa 40.625% */ - 4648, /* 56.56 kPa 41.406% */ - 4533, /* 57.43 kPa 42.188% */ - 4419, /* 58.30 kPa 42.969% */ - 4307, /* 59.17 kPa 43.750% */ - 4196, /* 60.03 kPa 44.531% */ - 4086, /* 60.90 kPa 45.313% */ - 3977, /* 61.77 kPa 46.094% */ - 3870, /* 62.63 kPa 46.875% */ - 3764, /* 63.51 kPa 47.656% */ - 3659, /* 64.38 kPa 48.438% */ - 3555, /* 65.24 kPa 49.219% */ - 3453, /* 66.11 kPa 50.000% */ - 3351, /* 66.98 kPa 50.781% */ - 3250, /* 67.85 kPa 51.563% */ - 3151, /* 68.72 kPa 52.344% */ - 3052, /* 69.58 kPa 53.125% */ - 2955, /* 70.45 kPa 53.906% */ - 2858, /* 71.32 kPa 54.688% */ - 2763, /* 72.19 kPa 55.469% */ - 2668, /* 73.06 kPa 56.250% */ - 2574, /* 73.92 kPa 57.031% */ - 2482, /* 74.79 kPa 57.813% */ - 2390, /* 75.66 kPa 58.594% */ - 2298, /* 76.52 kPa 59.375% */ - 2208, /* 77.40 kPa 60.156% */ - 2119, /* 78.26 kPa 60.938% */ - 2030, /* 79.13 kPa 61.719% */ - 1942, /* 80.00 kPa 62.500% */ - 1855, /* 80.87 kPa 63.281% */ - 1769, /* 81.74 kPa 64.063% */ - 1683, /* 82.60 kPa 64.844% */ - 1598, /* 83.47 kPa 65.625% */ - 1514, /* 84.34 kPa 66.406% */ - 1430, /* 85.21 kPa 67.188% */ - 1347, /* 86.08 kPa 67.969% */ - 1265, /* 86.94 kPa 68.750% */ - 1184, /* 87.81 kPa 69.531% */ - 1103, /* 88.68 kPa 70.313% */ - 1023, /* 89.55 kPa 71.094% */ - 943, /* 90.41 kPa 71.875% */ - 864, /* 91.28 kPa 72.656% */ - 786, /* 92.15 kPa 73.438% */ - 708, /* 93.02 kPa 74.219% */ - 631, /* 93.89 kPa 75.000% */ - 554, /* 94.76 kPa 75.781% */ - 478, /* 95.63 kPa 76.563% */ - 403, /* 96.49 kPa 77.344% */ - 328, /* 97.36 kPa 78.125% */ - 254, /* 98.23 kPa 78.906% */ - 180, /* 99.10 kPa 79.688% */ - 106, /* 99.97 kPa 80.469% */ - 34, /* 100.83 kPa 81.250% */ - -39, /* 101.70 kPa 82.031% */ - -111, /* 102.57 kPa 82.813% */ - -182, /* 103.44 kPa 83.594% */ - -253, /* 104.30 kPa 84.375% */ - -323, /* 105.17 kPa 85.156% */ - -393, /* 106.04 kPa 85.938% */ - -462, /* 106.91 kPa 86.719% */ - -531, /* 107.78 kPa 87.500% */ - -600, /* 108.65 kPa 88.281% */ - -668, /* 109.51 kPa 89.063% */ - -736, /* 110.38 kPa 89.844% */ - -803, /* 111.25 kPa 90.625% */ - -870, /* 112.12 kPa 91.406% */ - -936, /* 112.99 kPa 92.188% */ - -1002, /* 113.85 kPa 92.969% */ - -1068, /* 114.72 kPa 93.750% */ - -1133, /* 115.59 kPa 94.531% */ - -1198, /* 116.46 kPa 95.313% */ - -1262, /* 117.33 kPa 96.094% */ - -1326, /* 118.19 kPa 96.875% */ - -1389, /* 119.06 kPa 97.656% */ - -1453, /* 119.93 kPa 98.438% */ - -1516, /* 120.80 kPa 99.219% */ - -1578, /* 121.67 kPa 100.000% */ diff --git a/src/ao-make-product.5c b/src/ao-make-product.5c deleted file mode 100644 index 5f2eb8e8..00000000 --- a/src/ao-make-product.5c +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/sh - -autoimport ParseArgs; - -void -write_ucs2(string a, string description) -{ - int len = String::length(a); - - printf("/* %s */\n", description); - printf("#define AO_%s_LEN 0x%02x\n", description, len * 2 + 2); - printf("#define AO_%s_STRING \"%s\"\n", description, a); - printf("#define AO_%s_UCS2", description); - for (int i = 0; i < len; i++) { - int c = a[i]; - if (i > 0) - printf(","); - if (0x20 <= c && c < 128) - printf(" '%c', 0", c); - else - printf(" LE_WORD(0x%04x),", c); - } - printf("\n\n"); -} - -void -write_string(string a, string description) -{ - printf ("/* %s */\n", description); - printf ("#define AO_%s_STRING \"%s\"\n", description, a); -} - -void -write_int(int a, string description) -{ - printf ("/* %s */\n", description); - printf ("#define AO_%s_NUMBER %d\n\n", description, a); -} - -void -write_hex(int a, string description) -{ - printf ("/* %s */\n", description); - printf ("#define AO_%s_NUMBER 0x%04x\n\n", description, a); -} - -string manufacturer = "altusmetrum.org"; -string product = "TeleMetrum"; -string version = "0.0"; -int serial = 1; -int user_argind = 0; -int id_product = 0x000a; - -argdesc argd = { - .args = { - { - .var = { .arg_string = &manufacturer }, - .abbr = 'm', - .name = "manufacturer", - .expr_name = "manf", - .desc = "Manufacturer name." }, - { - .var = { .arg_string = &product }, - .abbr = 'p', - .name = "product", - .expr_name = "prod", - .desc = "Product name." }, - { - .var = { .arg_int = &id_product }, - .abbr = 'i', - .name = "id_product", - .expr_name = "id_p", - .desc = "Product ID." }, - { - .var = { .arg_int = &serial }, - .abbr = 's', - .name = "serial", - .expr_name = "number", - .desc = "Serial number." }, - { - .var = { .arg_string = &version }, - .abbr = 'v', - .name = "version", - .expr_name = "string", - .desc = "Program version." }, - }, - .prog_name = "usb descriptors", -}; - -void -main() -{ - string[dim(argv)-1] nargv = {[n] = argv[n+1]}; - parseargs(&argd, &nargv); - write_ucs2(manufacturer, "iManufacturer"); - write_ucs2(product, "iProduct"); - write_ucs2(sprintf("%06d", serial), "iSerial"); - write_int(serial, "iSerial"); - write_hex(id_product, "idProduct"); - write_string(version, "iVersion"); -} - -main(); diff --git a/src/ao.h b/src/ao.h deleted file mode 100644 index 8ac9ac3d..00000000 --- a/src/ao.h +++ /dev/null @@ -1,1610 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef _AO_H_ -#define _AO_H_ - -#include -#include -#include -#include -#include "cc1111.h" -#include "ao_pins.h" - -#define TRUE 1 -#define FALSE 0 - -/* Convert a __data pointer into an __xdata pointer */ -#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00)) - -/* Stack runs from above the allocated __data space to 0xfe, which avoids - * writing to 0xff as that triggers the stack overflow indicator - */ -#define AO_STACK_START 0x90 -#define AO_STACK_END 0xfe -#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) - -/* An AltOS task */ -struct ao_task { - __xdata void *wchan; /* current wait channel (NULL if running) */ - uint16_t alarm; /* abort ao_sleep time */ - uint8_t stack_count; /* amount of saved stack */ - uint8_t task_id; /* unique id */ - __code char *name; /* task name */ - uint8_t stack[AO_STACK_SIZE]; /* saved stack */ -}; - -extern __xdata struct ao_task *__data ao_cur_task; - -#define AO_NUM_TASKS 16 /* maximum number of tasks */ -#define AO_NO_TASK 0 /* no task id */ - -/* - ao_task.c - */ - -/* Suspend the current task until wchan is awoken. - * returns: - * 0 on normal wake - * 1 on alarm - */ -uint8_t -ao_sleep(__xdata void *wchan); - -/* Wake all tasks sleeping on wchan */ -void -ao_wakeup(__xdata void *wchan); - -/* set an alarm to go off in 'delay' ticks */ -void -ao_alarm(uint16_t delay); - -/* Yield the processor to another task */ -void -ao_yield(void) __naked; - -/* Add a task to the run queue */ -void -ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant; - -/* Terminate the current task */ -void -ao_exit(void); - -/* Dump task info to console */ -void -ao_task_info(void); - -/* Start the scheduler. This will not return */ -void -ao_start_scheduler(void); - -/* - * ao_panic.c - */ - -#define AO_PANIC_NO_TASK 1 /* AO_NUM_TASKS is not large enough */ -#define AO_PANIC_DMA 2 /* Attempt to start DMA while active */ -#define AO_PANIC_MUTEX 3 /* Mis-using mutex API */ -#define AO_PANIC_EE 4 /* Mis-using eeprom API */ -#define AO_PANIC_LOG 5 /* Failing to read/write log data */ -#define AO_PANIC_CMD 6 /* Too many command sets registered */ -#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */ -#define AO_PANIC_REBOOT 8 /* Reboot failed */ -#define AO_PANIC_FLASH 9 /* Invalid flash part (or wrong blocksize) */ -#define AO_PANIC_USB 10 /* Trying to send USB packet while busy */ -#define AO_PANIC_BT 11 /* Communications with bluetooth device failed */ - -/* Stop the operating system, beeping and blinking the reason */ -void -ao_panic(uint8_t reason); - -/* - * ao_timer.c - */ - -/* Our timer runs at 100Hz */ -#define AO_HERTZ 100 -#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ)) -#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ) - -/* Returns the current time in ticks */ -uint16_t -ao_time(void); - -/* Suspend the current task until ticks time has passed */ -void -ao_delay(uint16_t ticks); - -/* Set the ADC interval */ -void -ao_timer_set_adc_interval(uint8_t interval) __critical; - -/* Timer interrupt */ -void -ao_timer_isr(void) __interrupt 9; - -/* Initialize the timer */ -void -ao_timer_init(void); - -/* Initialize the hardware clock. Must be called first */ -void -ao_clock_init(void); - -/* - * One set of samples read from the A/D converter or telemetry - */ -struct ao_adc { - uint16_t tick; /* tick when the sample was read */ - int16_t accel; /* accelerometer */ - int16_t pres; /* pressure sensor */ - int16_t temp; /* temperature sensor */ - int16_t v_batt; /* battery voltage */ - int16_t sense_d; /* drogue continuity sense */ - int16_t sense_m; /* main continuity sense */ -}; - -#ifndef HAS_ADC -#error Please define HAS_ADC -#endif - -#if HAS_ADC - -#if HAS_ACCEL -#ifndef HAS_ACCEL_REF -#error Please define HAS_ACCEL_REF -#endif -#else -#define HAS_ACCEL_REF 0 -#endif - -/* - * ao_adc.c - */ - -#define AO_ADC_RING 32 -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) - - -/* - * A/D data is stored in a ring, with the next sample to be written - * at ao_adc_head - */ -extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -extern volatile __data uint8_t ao_adc_head; -#if HAS_ACCEL_REF -extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; -#endif - -/* Trigger a conversion sequence (called from the timer interrupt) */ -void -ao_adc_poll(void); - -/* Suspend the current task until another A/D sample is converted */ -void -ao_adc_sleep(void); - -/* Get a copy of the last complete A/D sample set */ -void -ao_adc_get(__xdata struct ao_adc *packet); - -/* The A/D interrupt handler */ - -void -ao_adc_isr(void) __interrupt 1; - -/* Initialize the A/D converter */ -void -ao_adc_init(void); - -#endif /* HAS_ADC */ - -/* - * ao_beep.c - */ - -/* - * Various pre-defined beep frequencies - * - * frequency = 1/2 (24e6/32) / beep - */ - -#define AO_BEEP_LOW 150 /* 2500Hz */ -#define AO_BEEP_MID 94 /* 3989Hz */ -#define AO_BEEP_HIGH 75 /* 5000Hz */ -#define AO_BEEP_OFF 0 /* off */ - -#define AO_BEEP_g 240 /* 1562.5Hz */ -#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */ -#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */ -#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */ -#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */ -#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */ -#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */ -#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */ -#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */ -#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */ -#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */ -#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */ -#define AO_BEEP_gg 120 /* 3125Hz */ -#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */ -#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */ -#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */ -#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */ -#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */ -#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */ -#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */ -#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */ -#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */ -#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */ -#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */ -#define AO_BEEP_ggg 60 /* 6250Hz */ - -/* Set the beeper to the specified tone */ -void -ao_beep(uint8_t beep); - -/* Turn on the beeper for the specified time */ -void -ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant; - -/* Initialize the beeper */ -void -ao_beep_init(void); - -/* - * ao_led.c - */ - -#define AO_LED_NONE 0 - -/* Turn on the specified LEDs */ -void -ao_led_on(uint8_t colors); - -/* Turn off the specified LEDs */ -void -ao_led_off(uint8_t colors); - -/* Set all of the LEDs to the specified state */ -void -ao_led_set(uint8_t colors); - -/* Toggle the specified LEDs */ -void -ao_led_toggle(uint8_t colors); - -/* Turn on the specified LEDs for the indicated interval */ -void -ao_led_for(uint8_t colors, uint16_t ticks) __reentrant; - -/* Initialize the LEDs */ -void -ao_led_init(uint8_t enable); - -/* - * ao_romconfig.c - */ - -#define AO_ROMCONFIG_VERSION 2 - -extern __code __at (0x00a0) uint16_t ao_romconfig_version; -extern __code __at (0x00a2) uint16_t ao_romconfig_check; -extern __code __at (0x00a4) uint16_t ao_serial_number; -extern __code __at (0x00a6) uint32_t ao_radio_cal; - -#ifndef HAS_USB -#error Please define HAS_USB -#endif - -#if HAS_USB -extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; -#endif - -/* - * ao_usb.c - */ - -/* Put one character to the USB output queue */ -void -ao_usb_putchar(char c); - -/* Get one character from the USB input queue */ -char -ao_usb_getchar(void); - -/* Poll for a charcter on the USB input queue. - * returns AO_READ_AGAIN if none are available - */ -char -ao_usb_pollchar(void); - -/* Flush the USB output queue */ -void -ao_usb_flush(void); - -#if HAS_USB -/* USB interrupt handler */ -void -ao_usb_isr(void) __interrupt 6; -#endif - -/* Enable the USB controller */ -void -ao_usb_enable(void); - -/* Disable the USB controller */ -void -ao_usb_disable(void); - -/* Initialize the USB system */ -void -ao_usb_init(void); - -/* - * ao_cmd.c - */ - -enum ao_cmd_status { - ao_cmd_success = 0, - ao_cmd_lex_error = 1, - ao_cmd_syntax_error = 2, -}; - -extern __pdata uint16_t ao_cmd_lex_i; -extern __pdata uint32_t ao_cmd_lex_u32; -extern __pdata char ao_cmd_lex_c; -extern __pdata enum ao_cmd_status ao_cmd_status; - -void -ao_cmd_lex(void); - -void -ao_cmd_put8(uint8_t v); - -void -ao_cmd_put16(uint16_t v); - -void -ao_cmd_white(void); - -void -ao_cmd_hex(void); - -void -ao_cmd_decimal(void); - -uint8_t -ao_match_word(__code char *word); - -struct ao_cmds { - void (*func)(void); - __code char *help; -}; - -void -ao_cmd_register(__code struct ao_cmds *cmds); - -void -ao_cmd_init(void); - -#if HAS_CMD_FILTER -/* - * Provided by an external module to filter raw command lines - */ -uint8_t -ao_cmd_filter(void); -#endif - -/* - * ao_dma.c - */ - -/* Allocate a DMA channel. the 'done' parameter will be set when the - * dma is finished and will be used to wakeup any waiters - */ - -uint8_t -ao_dma_alloc(__xdata uint8_t * done); - -/* Setup a DMA channel */ -void -ao_dma_set_transfer(uint8_t id, - void __xdata *srcaddr, - void __xdata *dstaddr, - uint16_t count, - uint8_t cfg0, - uint8_t cfg1); - -/* Start a DMA channel */ -void -ao_dma_start(uint8_t id); - -/* Manually trigger a DMA channel */ -void -ao_dma_trigger(uint8_t id); - -/* Abort a running DMA transfer */ -void -ao_dma_abort(uint8_t id); - -/* DMA interrupt routine */ -void -ao_dma_isr(void) __interrupt 8; - -/* - * ao_mutex.c - */ - -void -ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant; - -void -ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant; - -/* - * Storage interface, provided by one of the eeprom or flash - * drivers - */ - -/* Total bytes of available storage */ -extern __pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -extern __pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -extern __pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -extern __pdata uint16_t ao_storage_unit; - -#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE) - -/* Initialize above values. Can only be called once the OS is running */ -void -ao_storage_setup(void) __reentrant; - -/* Write data. Returns 0 on failure, 1 on success */ -uint8_t -ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Read data. Returns 0 on failure, 1 on success */ -uint8_t -ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Erase a block of storage. This always clears ao_storage_block bytes */ -uint8_t -ao_storage_erase(uint32_t pos) __reentrant; - -/* Flush any pending writes to stable storage */ -void -ao_storage_flush(void) __reentrant; - -/* Initialize the storage code */ -void -ao_storage_init(void); - -/* - * Low-level functions wrapped by ao_storage.c - */ - -/* Read data within a storage unit */ -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Write data within a storage unit */ -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Initialize low-level device bits */ -void -ao_storage_device_init(void); - -/* Print out information about flash chips */ -void -ao_storage_device_info(void) __reentrant; - -/* - * ao_log.c - */ - -/* We record flight numbers in the first record of - * the log. Tasks may wait for this to be initialized - * by sleeping on this variable. - */ -extern __xdata uint16_t ao_flight_number; - -extern __pdata uint32_t ao_log_current_pos; -extern __pdata uint32_t ao_log_end_pos; -extern __pdata uint32_t ao_log_start_pos; -extern __xdata uint8_t ao_log_running; -extern __pdata enum flight_state ao_log_state; - -/* required functions from the underlying log system */ - -#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ -#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ -#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ -#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ -#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ -#define AO_LOG_FORMAT_NONE 127 /* No log at all */ - -extern __code uint8_t ao_log_format; - -/* Return the flight number from the given log slot, 0 if none */ -uint16_t -ao_log_flight(uint8_t slot); - -/* Flush the log */ -void -ao_log_flush(void); - -/* Logging thread main routine */ -void -ao_log(void); - -/* functions provided in ao_log.c */ - -/* Figure out the current flight number */ -void -ao_log_scan(void) __reentrant; - -/* Return the position of the start of the given log slot */ -uint32_t -ao_log_pos(uint8_t slot); - -/* Start logging to eeprom */ -void -ao_log_start(void); - -/* Stop logging */ -void -ao_log_stop(void); - -/* Initialize the logging system */ -void -ao_log_init(void); - -/* Write out the current flight number to the erase log */ -void -ao_log_write_erase(uint8_t pos); - -/* Returns true if there are any logs stored in eeprom */ -uint8_t -ao_log_present(void); - -/* Returns true if there is no more storage space available */ -uint8_t -ao_log_full(void); - -/* - * ao_log_big.c - */ - -/* - * The data log is recorded in the eeprom as a sequence - * of data packets. - * - * Each packet starts with a 4-byte header that has the - * packet type, the packet checksum and the tick count. Then - * they all contain 2 16 bit values which hold packet-specific - * data. - * - * For each flight, the first packet - * is FLIGHT packet, indicating the serial number of the - * device and a unique number marking the number of flights - * recorded by this device. - * - * During flight, data from the accelerometer and barometer - * are recorded in SENSOR packets, using the raw 16-bit values - * read from the A/D converter. - * - * Also during flight, but at a lower rate, the deployment - * sensors are recorded in DEPLOY packets. The goal here is to - * detect failure in the deployment circuits. - * - * STATE packets hold state transitions as the flight computer - * transitions through different stages of the flight. - */ -#define AO_LOG_FLIGHT 'F' -#define AO_LOG_SENSOR 'A' -#define AO_LOG_TEMP_VOLT 'T' -#define AO_LOG_DEPLOY 'D' -#define AO_LOG_STATE 'S' -#define AO_LOG_GPS_TIME 'G' -#define AO_LOG_GPS_LAT 'N' -#define AO_LOG_GPS_LON 'W' -#define AO_LOG_GPS_ALT 'H' -#define AO_LOG_GPS_SAT 'V' -#define AO_LOG_GPS_DATE 'Y' - -#define AO_LOG_POS_NONE (~0UL) - -struct ao_log_record { - char type; - uint8_t csum; - uint16_t tick; - union { - struct { - int16_t ground_accel; - uint16_t flight; - } flight; - struct { - int16_t accel; - int16_t pres; - } sensor; - struct { - int16_t temp; - int16_t v_batt; - } temp_volt; - struct { - int16_t drogue; - int16_t main; - } deploy; - struct { - uint16_t state; - uint16_t reason; - } state; - struct { - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t flags; - } gps_time; - int32_t gps_latitude; - int32_t gps_longitude; - struct { - int16_t altitude; - uint16_t unused; - } gps_altitude; - struct { - uint16_t svid; - uint8_t unused; - uint8_t c_n; - } gps_sat; - struct { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t extra; - } gps_date; - struct { - uint16_t d0; - uint16_t d1; - } anon; - } u; -}; - -/* Write a record to the eeprom log */ -uint8_t -ao_log_data(__xdata struct ao_log_record *log) __reentrant; - -/* - * ao_flight.c - */ - -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 __pdata enum ao_flight_state ao_flight_state; - -extern __pdata uint16_t ao_launch_time; -extern __pdata uint8_t ao_flight_force_idle; - -/* Flight thread */ -void -ao_flight(void); - -/* Initialize flight thread */ -void -ao_flight_init(void); - -/* - * ao_flight_nano.c - */ - -void -ao_flight_nano_init(void); - -/* - * ao_sample.c - */ - -/* - * Barometer calibration - * - * We directly sample the barometer. The specs say: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * If we want to detect launch with the barometer, we need - * a large enough bump to not be fooled by noise. At typical - * launch elevations (0-2000m), a 200Pa pressure change cooresponds - * to about a 20m elevation change. This is 5.4mV, or about 3LSB. - * As all of our calculations are done in 16 bits, we'll actually see a change - * of 16 times this though - * - * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa - */ - -/* Accelerometer calibration - * - * We're sampling the accelerometer through a resistor divider which - * consists of 5k and 10k resistors. This multiplies the values by 2/3. - * That goes into the cc1111 A/D converter, which is running at 11 bits - * of precision with the bits in the MSB of the 16 bit value. Only positive - * values are used, so values should range from 0-32752 for 0-3.3V. The - * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what - * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, - * for a final computation of: - * - * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g - * - * Zero g was measured at 16000 (we would expect 16384). - * Note that this value is only require to tell if the - * rocket is standing upright. Once that is determined, - * the value of the accelerometer is averaged for 100 samples - * to find the resting accelerometer value, which is used - * for all further flight computations - */ - -#define GRAVITY 9.80665 - -/* - * Above this height, the baro sensor doesn't work - */ -#define AO_MAX_BARO_HEIGHT 12000 - -/* - * Above this speed, baro measurements are unreliable - */ -#define AO_MAX_BARO_SPEED 200 - -#define ACCEL_NOSE_UP (ao_accel_2g >> 2) - -/* - * Speed and acceleration are scaled by 16 to provide a bit more - * resolution while still having reasonable range. Note that this - * limits speed to 2047m/s (around mach 6) and acceleration to - * 2047m/s² (over 200g) - */ - -#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) -#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) -#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) - -extern __pdata uint16_t ao_sample_tick; /* time of last data */ -extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */ -extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */ -extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */ -extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ - -#if HAS_ACCEL -extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */ -#endif - -extern __pdata int16_t ao_ground_pres; /* startup pressure */ -extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ - -#if HAS_ACCEL -extern __pdata int16_t ao_ground_accel; /* startup acceleration */ -extern __pdata int16_t ao_accel_2g; /* factory accel calibration */ -extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ -#endif - -void ao_sample_init(void); - -/* returns FALSE in preflight mode, TRUE in flight mode */ -uint8_t ao_sample(void); - -/* - * ao_kalman.c - */ - -#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) -#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) -#define from_fix(x) ((x) >> 16) - -extern __pdata int16_t ao_height; /* meters */ -extern __pdata int16_t ao_speed; /* m/s * 16 */ -extern __pdata int16_t ao_accel; /* m/s² * 16 */ -extern __pdata int16_t ao_max_height; /* max of ao_height */ -extern __pdata int16_t ao_avg_height; /* running average of height */ - -extern __pdata int16_t ao_error_h; -extern __pdata int16_t ao_error_h_sq_avg; - -#if HAS_ACCEL -extern __pdata int16_t ao_error_a; -#endif - -void ao_kalman(void); - -/* - * ao_report.c - */ - -void -ao_report_init(void); - -/* - * ao_convert.c - * - * Given raw data, convert to SI units - */ - -/* pressure from the sensor to altitude in meters */ -int16_t -ao_pres_to_altitude(int16_t pres) __reentrant; - -int16_t -ao_altitude_to_pres(int16_t alt) __reentrant; - -int16_t -ao_temp_to_dC(int16_t temp) __reentrant; - -/* - * ao_dbg.c - * - * debug another telemetrum board - */ - -/* Send a byte to the dbg target */ -void -ao_dbg_send_byte(uint8_t byte); - -/* Receive a byte from the dbg target */ -uint8_t -ao_dbg_recv_byte(void); - -/* Start a bulk transfer to/from dbg target memory */ -void -ao_dbg_start_transfer(uint16_t addr); - -/* End a bulk transfer to/from dbg target memory */ -void -ao_dbg_end_transfer(void); - -/* Write a byte to dbg target memory */ -void -ao_dbg_write_byte(uint8_t byte); - -/* Read a byte from dbg target memory */ -uint8_t -ao_dbg_read_byte(void); - -/* Enable dbg mode, switching use of the pins */ -void -ao_dbg_debug_mode(void); - -/* Reset the dbg target */ -void -ao_dbg_reset(void); - -void -ao_dbg_init(void); - -/* - * ao_serial.c - */ - -#ifndef HAS_SERIAL_1 -#error Please define HAS_SERIAL_1 -#endif - -#if HAS_SERIAL_1 -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - -void -ao_serial_rx1_isr(void) __interrupt 3; - -void -ao_serial_tx1_isr(void) __interrupt 14; - -char -ao_serial_getchar(void) __critical; - -#if USE_SERIAL_STDIN -char -ao_serial_pollchar(void) __critical; - -void -ao_serial_set_stdin(uint8_t stdin); -#endif - -void -ao_serial_putchar(char c) __critical; - -void -ao_serial_drain(void) __critical; - -#define AO_SERIAL_SPEED_4800 0 -#define AO_SERIAL_SPEED_9600 1 -#define AO_SERIAL_SPEED_19200 2 -#define AO_SERIAL_SPEED_57600 3 - -void -ao_serial_set_speed(uint8_t speed); - -void -ao_serial_init(void); -#endif - -/* - * ao_spi.c - */ - -extern __xdata uint8_t ao_spi_mutex; - -#define ao_spi_get_mask(reg,mask) do {\ - ao_mutex_get(&ao_spi_mutex); \ - (reg) &= ~(mask); \ - } while (0) - -#define ao_spi_put_mask(reg,mask) do { \ - (reg) |= (mask); \ - ao_mutex_put(&ao_spi_mutex); \ - } while (0) - -#define ao_spi_get_bit(bit) do {\ - ao_mutex_get(&ao_spi_mutex); \ - (bit) = 0; \ - } while (0) - -#define ao_spi_put_bit(bit) do { \ - (bit) = 1; \ - ao_mutex_put(&ao_spi_mutex); \ - } while (0) - -/* - * The SPI mutex must be held to call either of these - * functions -- this mutex covers the entire SPI operation, - * from chip select low to chip select high - */ - -void -ao_spi_send(void __xdata *block, uint16_t len) __reentrant; - -void -ao_spi_recv(void __xdata *block, uint16_t len) __reentrant; - -void -ao_spi_init(void); - -/* - * ao_telemetry.c - */ -#define AO_MAX_CALLSIGN 8 -#define AO_MAX_VERSION 8 -#define AO_MAX_TELEMETRY 128 - -struct ao_telemetry_generic { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t payload[27]; /* 5 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 -#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 -#define AO_TELEMETRY_SENSOR_TELENANO 0x03 - -struct ao_telemetry_sensor { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t state; /* 5 flight state */ - int16_t accel; /* 6 accelerometer (TM only) */ - int16_t pres; /* 8 pressure sensor */ - int16_t temp; /* 10 temperature sensor */ - int16_t v_batt; /* 12 battery voltage */ - int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ - int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ - - int16_t acceleration; /* 18 m/s² * 16 */ - int16_t speed; /* 20 m/s * 16 */ - int16_t height; /* 22 m */ - - int16_t ground_pres; /* 24 average pres on pad */ - int16_t ground_accel; /* 26 average accel on pad */ - int16_t accel_plus_g; /* 28 accel calibration at +1g */ - int16_t accel_minus_g; /* 30 accel calibration at -1g */ - /* 32 */ -}; - -#define AO_TELEMETRY_CONFIGURATION 0x04 - -struct ao_telemetry_configuration { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t device; /* 5 device type */ - uint16_t flight; /* 6 flight number */ - uint8_t config_major; /* 8 Config major version */ - uint8_t config_minor; /* 9 Config minor version */ - uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ - uint16_t main_deploy; /* 12 Main deploy alt in meters */ - uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ - char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ - char version[AO_MAX_VERSION]; /* 24 Software version */ - /* 32 */ -}; - -#define AO_TELEMETRY_LOCATION 0x05 - -#define AO_GPS_MODE_NOT_VALID 'N' -#define AO_GPS_MODE_AUTONOMOUS 'A' -#define AO_GPS_MODE_DIFFERENTIAL 'D' -#define AO_GPS_MODE_ESTIMATED 'E' -#define AO_GPS_MODE_MANUAL 'M' -#define AO_GPS_MODE_SIMULATED 'S' - -struct ao_telemetry_location { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t flags; /* 5 Number of sats and other flags */ - int16_t altitude; /* 6 GPS reported altitude (m) */ - int32_t latitude; /* 8 latitude (degrees * 10⁷) */ - int32_t longitude; /* 12 longitude (degrees * 10⁷) */ - uint8_t year; /* 16 (- 2000) */ - uint8_t month; /* 17 (1-12) */ - uint8_t day; /* 18 (1-31) */ - uint8_t hour; /* 19 (0-23) */ - uint8_t minute; /* 20 (0-59) */ - uint8_t second; /* 21 (0-59) */ - uint8_t pdop; /* 22 (m * 5) */ - uint8_t hdop; /* 23 (m * 5) */ - uint8_t vdop; /* 24 (m * 5) */ - uint8_t mode; /* 25 */ - uint16_t ground_speed; /* 26 cm/s */ - int16_t climb_rate; /* 28 cm/s */ - uint8_t course; /* 30 degrees / 2 */ - uint8_t unused[1]; /* 31 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SATELLITE 0x06 - -struct ao_telemetry_satellite_info { - uint8_t svid; - uint8_t c_n_1; -}; - -struct ao_telemetry_satellite { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t channels; /* 5 number of reported sats */ - - struct ao_telemetry_satellite_info sats[12]; /* 6 */ - uint8_t unused[2]; /* 30 */ - /* 32 */ -}; - -#define AO_TELEMETRY_COMPANION 0x07 - -#define AO_COMPANION_MAX_CHANNELS 12 - -struct ao_telemetry_companion { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t board_id; /* 5 */ - - uint8_t update_period; /* 6 */ - uint8_t channels; /* 7 */ - uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */ - /* 32 */ -}; - -union ao_telemetry_all { - struct ao_telemetry_generic generic; - struct ao_telemetry_sensor sensor; - struct ao_telemetry_configuration configuration; - struct ao_telemetry_location location; - struct ao_telemetry_satellite satellite; - struct ao_telemetry_companion companion; -}; - -/* - * ao_gps.c - */ - -#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) - -extern __pdata uint16_t ao_gps_tick; -extern __xdata uint8_t ao_gps_mutex; -extern __xdata struct ao_telemetry_location ao_gps_data; -extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data; - -struct ao_gps_orig { - 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 hdop; /* * 5 */ - int16_t climb_rate; /* cm/s */ - uint16_t h_error; /* m */ - uint16_t v_error; /* m */ -}; - -struct ao_gps_sat_orig { - uint8_t svid; - uint8_t c_n_1; -}; - -#define AO_MAX_GPS_TRACKING 12 - -struct ao_gps_tracking_orig { - uint8_t channels; - struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; -}; - -void -ao_gps(void); - -void -ao_gps_print(__xdata struct ao_gps_orig *gps_data); - -void -ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data); - -void -ao_gps_init(void); - -/* - * ao_gps_report.c - */ - -void -ao_gps_report(void); - -void -ao_gps_report_init(void); - -/* - * ao_telemetry_orig.c - */ - -struct ao_telemetry_orig { - uint16_t serial; - uint16_t flight; - uint8_t flight_state; - int16_t accel; - int16_t ground_accel; - union { - struct { - int16_t speed; - int16_t unused; - } k; - int32_t flight_vel; - } u; - int16_t height; - int16_t ground_pres; - int16_t accel_plus_g; - int16_t accel_minus_g; - struct ao_adc adc; - struct ao_gps_orig gps; - char callsign[AO_MAX_CALLSIGN]; - struct ao_gps_tracking_orig gps_tracking; -}; - -struct ao_telemetry_tiny { - uint16_t serial; - uint16_t flight; - uint8_t flight_state; - int16_t height; /* AGL in meters */ - int16_t speed; /* in m/s * 16 */ - int16_t accel; /* in m/s² * 16 */ - int16_t ground_pres; /* sensor units */ - struct ao_adc adc; /* raw ADC readings */ - char callsign[AO_MAX_CALLSIGN]; -}; - -/* - * ao_radio_recv tacks on rssi and status bytes - */ - -struct ao_telemetry_raw_recv { - uint8_t packet[AO_MAX_TELEMETRY + 2]; -}; - -struct ao_telemetry_orig_recv { - struct ao_telemetry_orig telemetry_orig; - int8_t rssi; - uint8_t status; -}; - -struct ao_telemetry_tiny_recv { - struct ao_telemetry_tiny telemetry_tiny; - int8_t rssi; - uint8_t status; -}; - -/* Set delay between telemetry reports (0 to disable) */ - -#define AO_TELEMETRY_INTERVAL_PAD AO_MS_TO_TICKS(1000) -#define AO_TELEMETRY_INTERVAL_FLIGHT AO_MS_TO_TICKS(100) -#define AO_TELEMETRY_INTERVAL_RECOVER AO_MS_TO_TICKS(1000) - -void -ao_telemetry_set_interval(uint16_t interval); - -void -ao_rdf_set(uint8_t rdf); - -void -ao_telemetry_init(void); - -void -ao_telemetry_orig_init(void); - -void -ao_telemetry_tiny_init(void); - -/* - * ao_radio.c - */ - -extern __xdata uint8_t ao_radio_dma; -extern __xdata uint8_t ao_radio_dma_done; -extern __xdata uint8_t ao_radio_done; -extern __xdata uint8_t ao_radio_mutex; - -void -ao_radio_general_isr(void) __interrupt 16; - -void -ao_radio_get(uint8_t len); - -#define ao_radio_put() ao_mutex_put(&ao_radio_mutex) - -void -ao_radio_set_packet(void); - -void -ao_radio_send(__xdata void *data, uint8_t size) __reentrant; - -uint8_t -ao_radio_recv(__xdata void *data, uint8_t size) __reentrant; - -void -ao_radio_recv_abort(void); - -void -ao_radio_rdf(int ms); - -void -ao_radio_rdf_abort(void); - -void -ao_radio_idle(void); - -void -ao_radio_init(void); - -/* - * ao_monitor.c - */ - -extern const char const * const ao_state_names[]; - -void -ao_monitor(void); - -#define AO_MONITORING_OFF 0 -#define AO_MONITORING_ORIG 1 -#define AO_MONITORING_TINY 2 - -void -ao_set_monitor(uint8_t monitoring); - -void -ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant; - -/* - * ao_stdio.c - */ - -#define AO_READ_AGAIN ((char) -1) - -struct ao_stdio { - char (*pollchar)(void); - void (*putchar)(char c) __reentrant; - void (*flush)(void); - uint8_t echo; -}; - -extern __xdata struct ao_stdio ao_stdios[]; -extern __pdata int8_t ao_cur_stdio; -extern __pdata int8_t ao_num_stdios; - -void -flush(void); - -extern __xdata uint8_t ao_stdin_ready; - -uint8_t -ao_echo(void); - -int8_t -ao_add_stdio(char (*pollchar)(void), - void (*putchar)(char) __reentrant, - void (*flush)(void)) __reentrant; - -/* - * ao_ignite.c - */ - -enum ao_igniter { - ao_igniter_drogue = 0, - ao_igniter_main = 1 -}; - -void -ao_ignite(enum ao_igniter igniter); - -enum ao_igniter_status { - ao_igniter_unknown, /* unknown status (ambiguous voltage) */ - ao_igniter_ready, /* continuity detected */ - ao_igniter_active, /* igniter firing */ - ao_igniter_open, /* open circuit detected */ -}; - -enum ao_igniter_status -ao_igniter_status(enum ao_igniter igniter); - -void -ao_ignite_set_pins(void); - -void -ao_igniter_init(void); - -/* - * ao_config.c - */ - -#define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 8 - -struct ao_config { - uint8_t major; - uint8_t minor; - uint16_t main_deploy; - int16_t accel_plus_g; /* changed for minor version 2 */ - uint8_t radio_channel; - char callsign[AO_MAX_CALLSIGN + 1]; - uint8_t apogee_delay; /* minor version 1 */ - int16_t accel_minus_g; /* minor version 2 */ - uint32_t radio_cal; /* minor version 3 */ - uint32_t flight_log_max; /* minor version 4 */ - uint8_t ignite_mode; /* minor version 5 */ - uint8_t pad_orientation; /* minor version 6 */ - uint32_t radio_setting; /* minor version 7 */ - uint8_t radio_enable; /* minor version 8 */ -}; - -#define AO_IGNITE_MODE_DUAL 0 -#define AO_IGNITE_MODE_APOGEE 1 -#define AO_IGNITE_MODE_MAIN 2 - -#define AO_PAD_ORIENTATION_ANTENNA_UP 0 -#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 - -extern __xdata struct ao_config ao_config; - -#define AO_CONFIG_MAX_SIZE 128 - -void -ao_config_get(void); - -void -ao_config_put(void); - -void -ao_config_init(void); - -/* - * ao_rssi.c - */ - -void -ao_rssi_set(int rssi_value); - -void -ao_rssi_init(uint8_t rssi_led); - -/* - * ao_product.c - * - * values which need to be defined for - * each instance of a product - */ - -extern const char ao_version[]; -extern const char ao_manufacturer[]; -extern const char ao_product[]; - -/* - * Fifos - */ - -#define AO_FIFO_SIZE 32 - -struct ao_fifo { - uint8_t insert; - uint8_t remove; - char fifo[AO_FIFO_SIZE]; -}; - -#define ao_fifo_insert(f,c) do { \ - (f).fifo[(f).insert] = (c); \ - (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \ -} while(0) - -#define ao_fifo_remove(f,c) do {\ - c = (f).fifo[(f).remove]; \ - (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \ -} while(0) - -#define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove) -#define ao_fifo_empty(f) ((f).insert == (f).remove) - -/* - * ao_packet.c - * - * Packet-based command interface - */ - -#define AO_PACKET_MAX 64 -#define AO_PACKET_SYN (uint8_t) 0xff - -struct ao_packet { - uint8_t addr; - uint8_t len; - uint8_t seq; - uint8_t ack; - uint8_t d[AO_PACKET_MAX]; - uint8_t callsign[AO_MAX_CALLSIGN]; -}; - -struct ao_packet_recv { - struct ao_packet packet; - int8_t rssi; - uint8_t status; -}; - -extern __xdata struct ao_packet_recv ao_rx_packet; -extern __xdata struct ao_packet ao_tx_packet; -extern __xdata struct ao_task ao_packet_task; -extern __xdata uint8_t ao_packet_enable; -extern __xdata uint8_t ao_packet_master_sleeping; -extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; - -void -ao_packet_send(void); - -uint8_t -ao_packet_recv(void); - -void -ao_packet_flush(void); - -void -ao_packet_putchar(char c) __reentrant; - -char -ao_packet_pollchar(void) __critical; - -/* ao_packet_master.c */ - -void -ao_packet_master_init(void); - -/* ao_packet_slave.c */ - -void -ao_packet_slave_start(void); - -void -ao_packet_slave_stop(void); - -void -ao_packet_slave_init(uint8_t enable); - -/* ao_btm.c */ - -/* If bt_link is on P2, this interrupt is shared by USB, so the USB - * code calls this function. Otherwise, it's a regular ISR. - */ - -void -ao_btm_isr(void) -#if BT_LINK_ON_P1 - __interrupt 15 -#endif - ; - -void -ao_btm_init(void); - -/* ao_companion.c */ - -#define AO_COMPANION_SETUP 1 -#define AO_COMPANION_FETCH 2 -#define AO_COMPANION_NOTIFY 3 - -struct ao_companion_command { - uint8_t command; - uint8_t flight_state; - uint16_t tick; - uint16_t serial; - uint16_t flight; -}; - -struct ao_companion_setup { - uint16_t board_id; - uint16_t board_id_inverse; - uint8_t update_period; - uint8_t channels; -}; - -extern __pdata uint8_t ao_companion_running; -extern __xdata struct ao_companion_setup ao_companion_setup; -extern __xdata uint8_t ao_companion_mutex; -extern __xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; - -void -ao_companion_init(void); - -#endif /* _AO_H_ */ diff --git a/src/ao_adc.c b/src/ao_adc.c deleted file mode 100644 index 786dfd11..00000000 --- a/src/ao_adc.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "ao_pins.h" - -volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -#if HAS_ACCEL_REF -volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; -#endif -volatile __data uint8_t ao_adc_head; - -void -ao_adc_poll(void) -{ -#if HAS_ACCEL_REF - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; -#else -# ifdef TELENANO_V_0_1 - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; -# else - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0; -# endif -#endif -} - -void -ao_adc_get(__xdata struct ao_adc *packet) -{ - uint8_t i = ao_adc_ring_prev(ao_sample_adc); - memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); -} - -void -ao_adc_isr(void) __interrupt 1 -{ - uint8_t sequence; - uint8_t __xdata *a; - - sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT; -#if IGNITE_ON_P2 - /* TeleMetrum readings */ -#if HAS_ACCEL_REF - if (sequence == 2) { - a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]); - sequence = 0; - } else -#endif - { - if (sequence == ADCCON3_ECH_TEMP) - sequence = 2; - a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence); - sequence++; - } -#define GOT_ADC - a[0] = ADCL; - a[1] = ADCH; - if (sequence < 6) { -#if HAS_EXTERNAL_TEMP == 0 - /* start next channel conversion */ - /* v0.2 replaces external temp sensor with internal one */ - if (sequence == 2) - ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; - else -#endif - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; - } -#endif - -#if IGNITE_ON_P0 - /* TeleMini readings */ - a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].pres); -#ifdef TELEMINI_V_1_0 - switch (sequence) { - case 0: - /* pressure */ - a += 0; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; - break; - case 1: - /* drogue sense */ - a += 6; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; - break; - case 2: - /* main sense */ - a += 8; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; - break; - case 3: - /* battery */ - a += 4; - sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; - break; - case ADCCON3_ECH_TEMP: - a += 2; - sequence = 0; - break; - } -#define GOT_ADC -#endif -#ifdef TELENANO_V_0_1 - switch (sequence) { - case 1: - /* pressure */ - a += 0; - sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; - break; - case 3: - /* battery */ - a += 4; - sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; - break; - case ADCCON3_ECH_TEMP: - a += 2; - sequence = 0; - break; - } -#define GOT_ADC -#endif - a[0] = ADCL; - a[1] = ADCH; - if (sequence) { - /* Start next conversion */ - ADCCON3 = sequence; - } -#endif -#ifndef GOT_ADC -#error No known ADC configuration set -#endif - - else { - /* record this conversion series */ - ao_adc_ring[ao_adc_head].tick = ao_time(); - ao_adc_head = ao_adc_ring_next(ao_adc_head); - ao_wakeup(DATA_TO_XDATA(&ao_adc_head)); - } -} - -static void -ao_adc_dump(void) __reentrant -{ - static __xdata struct ao_adc packet; - ao_adc_get(&packet); - printf("tick: %5u accel: %5d pres: %5d temp: %5d batt: %5d drogue: %5d main: %5d\n", - packet.tick, packet.accel, packet.pres, packet.temp, - packet.v_batt, packet.sense_d, packet.sense_m); -} - -__code struct ao_cmds ao_adc_cmds[] = { - { ao_adc_dump, "a\0Current ADC" }, - { 0, NULL }, -}; - -void -ao_adc_init(void) -{ -#if IGNITE_ON_P2 - /* TeleMetrum configuration */ - ADCCFG = ((1 << 0) | /* acceleration */ - (1 << 1) | /* pressure */ -#if HAS_EXTERNAL_TEMP - (1 << 2) | /* v0.1 temperature */ -#endif - (1 << 3) | /* battery voltage */ - (1 << 4) | /* drogue sense */ - (1 << 5)); /* main sense */ -#endif - -#if IGNITE_ON_P0 - /* TeleMini configuration */ - ADCCFG = ((1 << 0) | /* pressure */ - (1 << 1) | /* drogue sense */ - (1 << 2) | /* main sense */ - (1 << 3)); /* battery voltage */ -#endif - - /* enable interrupts */ - ADCIF = 0; - IEN0 |= IEN0_ADCIE; - ao_cmd_register(&ao_adc_cmds[0]); -} diff --git a/src/ao_adc_fake.c b/src/ao_adc_fake.c deleted file mode 100644 index 6ca88d4e..00000000 --- a/src/ao_adc_fake.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -volatile __data uint8_t ao_adc_head; - -/* Stub for systems which have no ADC */ -void -ao_adc_poll(void) -{ -} diff --git a/src/ao_beep.c b/src/ao_beep.c deleted file mode 100644 index 3642f4c6..00000000 --- a/src/ao_beep.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -void -ao_beep(uint8_t beep) -{ - if (beep == 0) { - P2_0 = 0; - P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; - T4CTL = 0; - } else { - P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_PERIPHERAL; - T4CC0 = beep; - T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO | TxCTL_START; - } -} - -void -ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant -{ - ao_beep(beep); - ao_delay(ticks); - ao_beep(0); -} - -void -ao_beep_init(void) -{ - /* Our beeper is on P2_0, which is hooked to timer 4 using - * configuration alternative 2 - */ - P2_0 = 0; - P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; - PERCFG = (PERCFG & ~PERCFG_T4CFG_ALT_MASK) | PERCFG_T4CFG_ALT_2; - T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE; -} diff --git a/src/ao_btm.c b/src/ao_btm.c deleted file mode 100644 index 44155ec1..00000000 --- a/src/ao_btm.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -int8_t ao_btm_stdio; -__xdata uint8_t ao_btm_connected; - -#define AO_BTM_MAX_REPLY 16 -__xdata char ao_btm_reply[AO_BTM_MAX_REPLY]; - -extern volatile __xdata struct ao_fifo ao_usart1_rx_fifo; - -/* - * Read a line of data from the serial port, truncating - * it after a few characters. - */ - -uint8_t -ao_btm_get_line(void) -{ - uint8_t ao_btm_reply_len = 0; - char c; - - for (;;) { - - while ((c = ao_serial_pollchar()) != AO_READ_AGAIN) { - if (ao_btm_reply_len < sizeof (ao_btm_reply)) - ao_btm_reply[ao_btm_reply_len++] = c; - if (c == '\r' || c == '\n') - goto done; - } - for (c = 0; c < 10; c++) { - ao_delay(AO_MS_TO_TICKS(10)); - if (!ao_fifo_empty(ao_usart1_rx_fifo)) - break; - } - if (c == 10) - goto done; - } -done: - for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);) - ao_btm_reply[c++] = '\0'; - return ao_btm_reply_len; -} - -/* - * Drain the serial port completely - */ -void -ao_btm_drain() -{ - while (ao_btm_get_line()) - ; -} - -/* - * Set the stdio echo for the bluetooth link - */ -void -ao_btm_echo(uint8_t echo) -{ - ao_stdios[ao_btm_stdio].echo = echo; -} - -/* - * Delay between command charaters; the BT module - * can't keep up with 57600 baud - */ - -void -ao_btm_putchar(char c) -{ - ao_serial_putchar(c); - ao_delay(1); -} - -/* - * Wait for the bluetooth device to return - * status from the previously executed command - */ -uint8_t -ao_btm_wait_reply(void) -{ - for (;;) { - ao_btm_get_line(); - if (!strncmp(ao_btm_reply, "OK", 2)) - return 1; - if (!strncmp(ao_btm_reply, "ERROR", 5)) - return -1; - if (ao_btm_reply[0] == '\0') - return 0; - } -} - -void -ao_btm_string(__code char *cmd) -{ - char c; - - while (c = *cmd++) - ao_btm_putchar(c); -} - -uint8_t -ao_btm_cmd(__code char *cmd) -{ - ao_btm_drain(); - ao_btm_string(cmd); - return ao_btm_wait_reply(); -} - -uint8_t -ao_btm_set_name(void) -{ - char sn[8]; - char *s = sn + 8; - char c; - int n; - ao_btm_string("ATN=TeleBT-"); - *--s = '\0'; - *--s = '\r'; - n = ao_serial_number; - do { - *--s = '0' + n % 10; - } while (n /= 10); - while ((c = *s++)) - ao_btm_putchar(c); - return ao_btm_wait_reply(); -} - -uint8_t -ao_btm_try_speed(uint8_t speed) -{ - ao_serial_set_speed(speed); - ao_btm_drain(); - (void) ao_btm_cmd("\rATE0\rATQ0\r"); - if (ao_btm_cmd("AT\r") == 1) - return 1; - return 0; -} - -/* - * A thread to initialize the bluetooth device and - * hang around to blink the LED when connected - */ -void -ao_btm(void) -{ - /* - * Wait for the bluetooth device to boot - */ - ao_delay(AO_SEC_TO_TICKS(3)); - -#if HAS_BEEP - ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); -#endif - - /* - * The first time we connect, the BTM-180 comes up at 19200 baud. - * After that, it will remember and come up at 57600 baud. So, see - * if it is already running at 57600 baud, and if that doesn't work - * then tell it to switch to 57600 from 19200 baud. - */ - while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) { - ao_delay(AO_SEC_TO_TICKS(1)); - if (ao_btm_try_speed(AO_SERIAL_SPEED_19200)) - ao_btm_cmd("ATL4\r"); - ao_delay(AO_SEC_TO_TICKS(1)); - } - - /* Disable echo */ - ao_btm_cmd("ATE0\r"); - - /* Enable flow control */ - ao_btm_cmd("ATC1\r"); - - /* Set the reported name to something we can find on the host */ - ao_btm_set_name(); - - /* Turn off status reporting */ - ao_btm_cmd("ATQ1\r"); - - ao_btm_stdio = ao_add_stdio(ao_serial_pollchar, - ao_serial_putchar, - NULL); - ao_btm_echo(0); - - for (;;) { - while (!ao_btm_connected) - ao_sleep(&ao_btm_connected); - while (ao_btm_connected) { - ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20)); - ao_delay(AO_SEC_TO_TICKS(3)); - } - } -} - -__xdata struct ao_task ao_btm_task; - -#if BT_LINK_ON_P2 -#define BT_PICTL_ICON PICTL_P2ICON -#define BT_PIFG P2IFG -#define BT_PDIR P2DIR -#define BT_PINP P2INP -#define BT_IEN2_PIE IEN2_P2IE -#endif -#if BT_LINK_ON_P1 -#define BT_PICTL_ICON PICTL_P1ICON -#define BT_PIFG P1IFG -#define BT_PDIR P1DIR -#define BT_PINP P1INP -#define BT_IEN2_PIE IEN2_P1IE -#endif - -void -ao_btm_check_link() __critical -{ - /* Check the pin and configure the interrupt detector to wait for the - * pin to flip the other way - */ - if (BT_LINK_PIN) { - ao_btm_connected = 0; - PICTL |= BT_PICTL_ICON; - } else { - ao_btm_connected = 1; - PICTL &= ~BT_PICTL_ICON; - } -} - -void -ao_btm_isr(void) -#if BT_LINK_ON_P1 - __interrupt 15 -#endif -{ -#if BT_LINK_ON_P1 - P1IF = 0; -#endif - if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) { - ao_btm_check_link(); - ao_wakeup(&ao_btm_connected); - } - BT_PIFG = 0; -} - -void -ao_btm_init (void) -{ - ao_serial_init(); - ao_serial_set_speed(AO_SERIAL_SPEED_19200); - -#if BT_LINK_ON_P1 - /* - * Configure ser reset line - */ - - P1_6 = 0; - P1DIR |= (1 << 6); -#endif - - /* - * Configure link status line - */ - - /* Set pin to input */ - BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX); - - /* Set pin to tri-state */ - BT_PINP |= (1 << BT_LINK_PIN_INDEX); - - /* Enable interrupts */ - IEN2 |= BT_IEN2_PIE; - - /* Check current pin state */ - ao_btm_check_link(); - -#if BT_LINK_ON_P2 - /* Eable the pin interrupt */ - PICTL |= PICTL_P2IEN; -#endif -#if BT_LINK_ON_P1 - /* Enable pin interrupt */ - P1IEN |= (1 << BT_LINK_PIN_INDEX); -#endif - - ao_add_task(&ao_btm_task, ao_btm, "bt"); -} diff --git a/src/ao_cmd.c b/src/ao_cmd.c deleted file mode 100644 index 1442ebea..00000000 --- a/src/ao_cmd.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -__pdata uint16_t ao_cmd_lex_i; -__pdata uint32_t ao_cmd_lex_u32; -__pdata char ao_cmd_lex_c; -__pdata enum ao_cmd_status ao_cmd_status; - -#define CMD_LEN 32 - -static __xdata char cmd_line[CMD_LEN]; -static __pdata uint8_t cmd_len; -static __pdata uint8_t cmd_i; - -static void -put_string(__code char *s) -{ - char c; - while (c = *s++) - putchar(c); -} - -static void -readline(void) -{ - __pdata char c; - if (ao_echo()) - put_string("> "); - cmd_len = 0; - for (;;) { - flush(); - c = getchar(); - /* backspace/delete */ - if (c == '\010' || c == '\177') { - if (cmd_len != 0) { - if (ao_echo()) - put_string("\010 \010"); - --cmd_len; - } - continue; - } - - /* ^U */ - if (c == '\025') { - while (cmd_len != 0) { - if (ao_echo()) - put_string("\010 \010"); - --cmd_len; - } - continue; - } - - /* map CR to NL */ - if (c == '\r') - c = '\n'; - - if (c == '\n') { - if (ao_echo()) - putchar('\n'); - break; - } - - if (cmd_len >= CMD_LEN - 2) { - if (ao_echo()) - putchar('\007'); - continue; - } - cmd_line[cmd_len++] = c; - if (ao_echo()) - putchar(c); - } - cmd_line[cmd_len++] = '\n'; - cmd_line[cmd_len++] = '\0'; - cmd_i = 0; -} - -void -ao_cmd_lex(void) -{ - ao_cmd_lex_c = '\n'; - if (cmd_i < cmd_len) - ao_cmd_lex_c = cmd_line[cmd_i++]; -} - -static void -putnibble(uint8_t v) -{ - if (v < 10) - putchar(v + '0'); - else - putchar(v + ('a' - 10)); -} - -void -ao_cmd_put16(uint16_t v) -{ - ao_cmd_put8(v >> 8); - ao_cmd_put8(v); -} - -void -ao_cmd_put8(uint8_t v) -{ - putnibble((v >> 4) & 0xf); - putnibble(v & 0xf); -} - -void -ao_cmd_white(void) -{ - while (ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t') - ao_cmd_lex(); -} - -void -ao_cmd_hex(void) -{ - __pdata uint8_t r = ao_cmd_lex_error; - uint8_t n; - - ao_cmd_lex_i = 0; - ao_cmd_white(); - for(;;) { - if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') - n = (ao_cmd_lex_c - '0'); - else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f') - n = (ao_cmd_lex_c - 'a' + 10); - else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F') - n = (ao_cmd_lex_c - 'A' + 10); - else - break; - ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n; - r = ao_cmd_success; - ao_cmd_lex(); - } - if (r != ao_cmd_success) - ao_cmd_status = r; -} - -void -ao_cmd_decimal(void) -{ - __pdata uint8_t r = ao_cmd_lex_error; - - ao_cmd_lex_u32 = 0; - ao_cmd_white(); - for(;;) { - if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') - ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0'); - else - break; - r = ao_cmd_success; - ao_cmd_lex(); - } - if (r != ao_cmd_success) - ao_cmd_status = r; - ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32; -} - -uint8_t -ao_match_word(__code char *word) -{ - while (*word) { - if (ao_cmd_lex_c != *word) { - ao_cmd_status = ao_cmd_syntax_error; - return 0; - } - word++; - ao_cmd_lex(); - } - return 1; -} - -static void -eol(void) -{ - while (ao_cmd_lex_c != '\n') - ao_cmd_lex(); -} - -static void -echo(void) -{ - ao_cmd_hex(); - if (ao_cmd_status == ao_cmd_success) - ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0; -} - -static void -ao_reboot(void) -{ - ao_cmd_white(); - if (!ao_match_word("eboot")) - return; - WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64; - ao_delay(AO_SEC_TO_TICKS(2)); - ao_panic(AO_PANIC_REBOOT); -} - -static void -version(void) -{ - printf("manufacturer %s\n", ao_manufacturer); - printf("product %s\n", ao_product); - printf("serial-number %u\n", ao_serial_number); -#if HAS_EEPROM - printf("log-format %u\n", ao_log_format); -#endif - printf("software-version %s\n", ao_version); -} - -#define NUM_CMDS 11 - -static __code struct ao_cmds *__xdata (ao_cmds[NUM_CMDS]); -static __pdata uint8_t ao_ncmds; - -static void -help(void) -{ - register uint8_t cmds; - register uint8_t cmd; - register __code struct ao_cmds * cs; - - for (cmds = 0; cmds < ao_ncmds; cmds++) { - cs = ao_cmds[cmds]; - for (cmd = 0; cs[cmd].func; cmd++) - printf("%-45s %s\n", - cs[cmd].help, - cs[cmd].help+1+strlen(cs[cmd].help)); - } -} - -static void -report(void) -{ - switch(ao_cmd_status) { - case ao_cmd_lex_error: - case ao_cmd_syntax_error: - puts("Syntax error"); - ao_cmd_status = 0; - break; - } -} - -void -ao_cmd_register(__code struct ao_cmds *cmds) -{ - if (ao_ncmds >= NUM_CMDS) - ao_panic(AO_PANIC_CMD); - ao_cmds[ao_ncmds++] = cmds; -} - -void -ao_cmd(void) -{ - char c; - uint8_t cmd, cmds; - __code struct ao_cmds * __xdata cs; - void (*__xdata func)(void); - - for (;;) { - readline(); - ao_cmd_lex(); - ao_cmd_white(); - c = ao_cmd_lex_c; - ao_cmd_lex(); - if (c == '\r' || c == '\n') - continue; - func = (void (*)(void)) NULL; - for (cmds = 0; cmds < ao_ncmds; cmds++) { - cs = ao_cmds[cmds]; - for (cmd = 0; cs[cmd].func; cmd++) - if (cs[cmd].help[0] == c) { - func = cs[cmd].func; - break; - } - if (func) - break; - } - if (func) - (*func)(); - else - ao_cmd_status = ao_cmd_syntax_error; - report(); - } -} - -__xdata struct ao_task ao_cmd_task; - -__code struct ao_cmds ao_base_cmds[] = { - { help, "?\0Help" }, - { ao_task_info, "T\0Show tasks" }, - { echo, "E <0 off, 1 on>\0Set echo mode" }, - { ao_reboot, "r eboot\0Reboot" }, - { version, "v\0Version" }, - { 0, NULL }, -}; - -void -ao_cmd_init(void) -{ - ao_cmd_register(&ao_base_cmds[0]); - ao_add_task(&ao_cmd_task, ao_cmd, "cmd"); -} diff --git a/src/ao_companion.c b/src/ao_companion.c deleted file mode 100644 index 4c8f4269..00000000 --- a/src/ao_companion.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -#define ao_spi_slow() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ - UxGCR_CPHA_FIRST_EDGE | \ - UxGCR_ORDER_MSB | \ - (13 << UxGCR_BAUD_E_SHIFT))) - -#define ao_spi_fast() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ - UxGCR_CPHA_FIRST_EDGE | \ - UxGCR_ORDER_MSB | \ - (17 << UxGCR_BAUD_E_SHIFT))) - -#define COMPANION_SELECT() do { ao_spi_get_bit(COMPANION_CS); ao_spi_slow(); } while (0) -#define COMPANION_DESELECT() do { ao_spi_fast(); ao_spi_put_bit(COMPANION_CS); } while (0) - -static __xdata struct ao_companion_command ao_companion_command; -__xdata struct ao_companion_setup ao_companion_setup; - -__xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; -__pdata uint8_t ao_companion_running; -__xdata uint8_t ao_companion_mutex; - -static void -ao_companion_send_command(uint8_t command) -{ - ao_companion_command.command = command; - ao_companion_command.flight_state = ao_flight_state; - ao_companion_command.tick = ao_time(); - ao_companion_command.serial = ao_serial_number; - ao_companion_command.flight = ao_flight_number; - ao_spi_send(&ao_companion_command, sizeof (ao_companion_command)); -} - -static uint8_t -ao_companion_get_setup(void) -{ - COMPANION_SELECT(); - ao_companion_send_command(AO_COMPANION_SETUP); - ao_spi_recv(&ao_companion_setup, sizeof (ao_companion_setup)); - COMPANION_DESELECT(); - return (ao_companion_setup.board_id == - ~ao_companion_setup.board_id_inverse); -} - -static void -ao_companion_get_data(void) -{ - COMPANION_SELECT(); - ao_companion_send_command(AO_COMPANION_FETCH); - ao_mutex_get(&ao_companion_mutex); - ao_spi_recv(&ao_companion_data, ao_companion_setup.channels * 2); - ao_mutex_put(&ao_companion_mutex); - COMPANION_DESELECT(); -} - -static void -ao_companion_notify(void) -{ - COMPANION_SELECT(); - ao_companion_send_command(AO_COMPANION_NOTIFY); - COMPANION_DESELECT(); -} - -void -ao_companion(void) -{ - uint8_t i; - while (!ao_flight_number) - ao_sleep(&ao_flight_number); - for (i = 0; i < 10; i++) { - ao_delay(AO_SEC_TO_TICKS(1)); - if ((ao_companion_running = ao_companion_get_setup())) - break; - } - while (ao_companion_running) { - ao_alarm(ao_companion_setup.update_period); - if (ao_sleep(DATA_TO_XDATA(&ao_flight_state))) - ao_companion_get_data(); - else - ao_companion_notify(); - } - ao_exit(); -} - -void -ao_companion_status(void) __reentrant -{ - uint8_t i; - printf("Companion running: %d\n", ao_companion_running); - printf("device: %d\n", ao_companion_setup.board_id); - printf("update period: %d\n", ao_companion_setup.update_period); - printf("channels: %d\n", ao_companion_setup.channels); - printf("data:"); - for(i = 0; i < ao_companion_setup.channels; i++) - printf(" %5u", ao_companion_data[i]); - printf("\n"); -} - -__code struct ao_cmds ao_companion_cmds[] = { - { ao_companion_status, "L\0Companion link status" }, - { 0, NULL }, -}; - -static __xdata struct ao_task ao_companion_task; - -void -ao_companion_init(void) -{ - COMPANION_CS_PORT |= COMPANION_CS_MASK; /* raise all CS pins */ - COMPANION_CS_DIR |= COMPANION_CS_MASK; /* set CS pins as outputs */ - COMPANION_CS_SEL &= ~COMPANION_CS_MASK; /* set CS pins as GPIO */ - - ao_cmd_register(&ao_companion_cmds[0]); - ao_add_task(&ao_companion_task, ao_companion, "companion"); -} diff --git a/src/ao_config.c b/src/ao_config.c deleted file mode 100644 index 0c10e608..00000000 --- a/src/ao_config.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -__xdata struct ao_config ao_config; -__pdata uint8_t ao_config_loaded; -__pdata uint8_t ao_config_dirty; -__xdata uint8_t ao_config_mutex; - -#define AO_CONFIG_DEFAULT_MAIN_DEPLOY 250 -#define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0 -#define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL" -#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000 -#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0 -#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL -#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP -#if HAS_EEPROM -#ifndef USE_INTERNAL_FLASH -#error Please define USE_INTERNAL_FLASH -#endif -#endif -#if USE_INTERNAL_FLASH -#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config -#else -#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024) -#endif - -#if HAS_EEPROM -static void -_ao_config_put(void) -{ - ao_storage_setup(); - ao_storage_erase(ao_storage_config); - ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config)); - ao_log_write_erase(0); - ao_storage_flush(); -} - -void -ao_config_put(void) -{ - ao_mutex_get(&ao_config_mutex); - _ao_config_put(); - ao_mutex_put(&ao_config_mutex); -} -#endif - -static void -_ao_config_get(void) -{ - if (ao_config_loaded) - return; -#if HAS_EEPROM - ao_storage_setup(); - ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config)); -#endif - if (ao_config.major != AO_CONFIG_MAJOR) { - ao_config.major = AO_CONFIG_MAJOR; - ao_config.minor = 0; - ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY; - ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL; - memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); - memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, - sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); - } - if (ao_config.minor < AO_CONFIG_MINOR) { - /* Fixups for minor version 1 */ - if (ao_config.minor < 1) - ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY; - /* Fixups for minor version 2 */ - if (ao_config.minor < 2) { - ao_config.accel_plus_g = 0; - ao_config.accel_minus_g = 0; - } - /* Fixups for minor version 3 */ - if (ao_config.minor < 3) - ao_config.radio_cal = ao_radio_cal; - /* Fixups for minor version 4 */ - if (ao_config.minor < 4) - ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; - /* Fixupes for minor version 5 */ - if (ao_config.minor < 5) - ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; - if (ao_config.minor < 6) - ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; - if (ao_config.minor < 7) - ao_config.radio_setting = ao_config.radio_cal; - if (ao_config.minor < 8) - ao_config.radio_enable = TRUE; - ao_config.minor = AO_CONFIG_MINOR; - ao_config_dirty = 1; - } - ao_config_loaded = 1; -} - -static void -_ao_config_edit_start(void) -{ - ao_mutex_get(&ao_config_mutex); - _ao_config_get(); -} - -static void -_ao_config_edit_finish(void) -{ - ao_config_dirty = 1; - ao_mutex_put(&ao_config_mutex); -} - -void -ao_config_get(void) -{ - _ao_config_edit_start(); - ao_mutex_put(&ao_config_mutex); -} - -void -ao_config_callsign_show(void) -{ - printf ("Callsign: \"%s\"\n", ao_config.callsign); -} - -void -ao_config_callsign_set(void) __reentrant -{ - uint8_t c; - static __xdata char callsign[AO_MAX_CALLSIGN + 1]; - - memset(callsign, '\0', sizeof callsign); - ao_cmd_white(); - c = 0; - while (ao_cmd_lex_c != '\n') { - if (c < AO_MAX_CALLSIGN) - callsign[c++] = ao_cmd_lex_c; - else - ao_cmd_status = ao_cmd_lex_error; - ao_cmd_lex(); - } - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - memcpy(&ao_config.callsign, &callsign, - AO_MAX_CALLSIGN + 1); - _ao_config_edit_finish(); -} - -void -ao_config_radio_channel_show(void) __reentrant -{ - printf("Radio channel: %d\n", - ao_config.radio_channel); -} - -void -ao_config_radio_channel_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_channel = ao_cmd_lex_i; - _ao_config_edit_finish(); - ao_radio_recv_abort(); -} - -#if HAS_ADC - -void -ao_config_main_deploy_show(void) __reentrant -{ - printf("Main deploy: %d meters\n", - ao_config.main_deploy); -} - -void -ao_config_main_deploy_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.main_deploy = ao_cmd_lex_i; - _ao_config_edit_finish(); -} - -#if HAS_ACCEL -void -ao_config_accel_calibrate_show(void) __reentrant -{ - printf("Accel cal +1g: %d -1g: %d\n", - ao_config.accel_plus_g, ao_config.accel_minus_g); -} - -#define ACCEL_CALIBRATE_SAMPLES 1024 -#define ACCEL_CALIBRATE_SHIFT 10 - -static int16_t -ao_config_accel_calibrate_auto(char *orientation) __reentrant -{ - uint16_t i; - int32_t accel_total; - uint8_t cal_adc_ring; - - printf("Orient antenna %s and press a key...", orientation); - flush(); - (void) getchar(); - puts("\r\n"); flush(); - puts("Calibrating..."); flush(); - i = ACCEL_CALIBRATE_SAMPLES; - accel_total = 0; - cal_adc_ring = ao_sample_adc; - while (i) { - ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); - while (i && cal_adc_ring != ao_sample_adc) { - accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel; - cal_adc_ring = ao_adc_ring_next(cal_adc_ring); - i--; - } - } - return accel_total >> ACCEL_CALIBRATE_SHIFT; -} - -void -ao_config_accel_calibrate_set(void) __reentrant -{ - int16_t up, down; - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - if (ao_cmd_lex_i == 0) { - up = ao_config_accel_calibrate_auto("up"); - down = ao_config_accel_calibrate_auto("down"); - } else { - up = ao_cmd_lex_i; - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - down = ao_cmd_lex_i; - } - if (up >= down) { - printf("Invalid accel: up (%d) down (%d)\n", - up, down); - return; - } - _ao_config_edit_start(); - ao_config.accel_plus_g = up; - ao_config.accel_minus_g = down; - _ao_config_edit_finish(); -} -#endif /* HAS_ACCEL */ - -void -ao_config_apogee_delay_show(void) __reentrant -{ - printf("Apogee delay: %d seconds\n", - ao_config.apogee_delay); -} - -void -ao_config_apogee_delay_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.apogee_delay = ao_cmd_lex_i; - _ao_config_edit_finish(); -} - -#endif /* HAS_ADC */ - -void -ao_config_radio_cal_show(void) __reentrant -{ - printf("Radio cal: %ld\n", ao_config.radio_cal); -} - -void -ao_config_radio_cal_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_setting = ao_config.radio_cal = ao_cmd_lex_u32; - _ao_config_edit_finish(); -} - -#if HAS_EEPROM -void -ao_config_log_show(void) __reentrant -{ - printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10)); -} - -void -ao_config_log_set(void) __reentrant -{ - uint16_t block = (uint16_t) (ao_storage_block >> 10); - uint16_t config = (uint16_t) (ao_storage_config >> 10); - - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - if (ao_log_present()) - printf("Storage must be empty before changing log size\n"); - else if (block > 1024 && (ao_cmd_lex_i & (block - 1))) - printf("Flight log size must be multiple of %d kB\n", block); - else if (ao_cmd_lex_i > config) - printf("Flight log max %d kB\n", config); - else { - _ao_config_edit_start(); - ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10; - _ao_config_edit_finish(); - } -} -#endif /* HAS_EEPROM */ - -#if HAS_IGNITE -void -ao_config_ignite_mode_show(void) __reentrant -{ - printf("Ignite mode: %d\n", ao_config.ignite_mode); -} - -void -ao_config_ignite_mode_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.ignite_mode = ao_cmd_lex_i; - _ao_config_edit_finish(); -} -#endif - -#if HAS_ACCEL -void -ao_config_pad_orientation_show(void) __reentrant -{ - printf("Pad orientation: %d\n", ao_config.pad_orientation); -} - -void -ao_config_pad_orientation_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_cmd_lex_i &= 1; - if (ao_config.pad_orientation != ao_cmd_lex_i) { - uint16_t t; - t = ao_config.accel_plus_g; - ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g; - ao_config.accel_minus_g = 0x7fff - t; - } - ao_config.pad_orientation = ao_cmd_lex_i; - _ao_config_edit_finish(); -} -#endif - -void -ao_config_radio_setting_show(void) __reentrant -{ - printf("Radio setting: %ld\n", ao_config.radio_setting); -} - -void -ao_config_radio_setting_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_setting = ao_cmd_lex_u32; - ao_config.radio_channel = 0; - _ao_config_edit_finish(); - ao_radio_recv_abort(); -} - -void -ao_config_radio_enable_show(void) __reentrant -{ - printf("Radio enable: %d\n", ao_config.radio_enable); -} - -void -ao_config_radio_enable_set(void) __reentrant -{ - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - _ao_config_edit_start(); - ao_config.radio_enable = ao_cmd_lex_i; - _ao_config_edit_finish(); -} - -struct ao_config_var { - __code char *str; - void (*set)(void) __reentrant; - void (*show)(void) __reentrant; -}; - -static void -ao_config_help(void) __reentrant; - -static void -ao_config_show(void) __reentrant; - -static void -ao_config_write(void) __reentrant; - -__code struct ao_config_var ao_config_vars[] = { -#if HAS_ADC - { "m \0Main deploy (in meters)", - ao_config_main_deploy_set, ao_config_main_deploy_show, }, - { "d \0Apogee delay (in seconds)", - ao_config_apogee_delay_set, ao_config_apogee_delay_show }, -#endif /* HAS_ADC */ - { "r \0Radio channel (freq = 434.550 + chan * .1)", - ao_config_radio_channel_set, ao_config_radio_channel_show }, - { "c \0Callsign (8 char max)", - ao_config_callsign_set, ao_config_callsign_show }, - { "R \0Radio freq control (freq = 434.550 * setting/cal)", - ao_config_radio_setting_set, ao_config_radio_setting_show }, - { "e <0 disable, 1 enable>\0Enable telemetry and RDF", - ao_config_radio_enable_set, ao_config_radio_enable_show }, -#if HAS_ACCEL - { "a <+g> <-g>\0Accel calib (0 for auto)", - ao_config_accel_calibrate_set,ao_config_accel_calibrate_show }, -#endif /* HAS_ACCEL */ - { "f \0Radio calib (cal = rf/(xtal/2^16))", - ao_config_radio_cal_set, ao_config_radio_cal_show }, -#if HAS_EEPROM - { "l \0Flight log size in kB", - ao_config_log_set, ao_config_log_show }, -#endif -#if HAS_IGNITE - { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode", - ao_config_ignite_mode_set, ao_config_ignite_mode_show }, -#endif -#if HAS_ACCEL - { "o <0 antenna up, 1 antenna down>\0Set pad orientation", - ao_config_pad_orientation_set,ao_config_pad_orientation_show }, -#endif - { "s\0Show", - ao_config_show, 0 }, -#if HAS_EEPROM - { "w\0Write to eeprom", - ao_config_write, 0 }, -#endif - { "?\0Help", - ao_config_help, 0 }, - { 0, 0, 0 } -}; - -void -ao_config_set(void) -{ - char c; - uint8_t cmd; - void (*__xdata func)(void) __reentrant; - - ao_cmd_white(); - c = ao_cmd_lex_c; - ao_cmd_lex(); - func = 0; - for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) - if (ao_config_vars[cmd].str[0] == c) { - (*ao_config_vars[cmd].set)(); - return; - } - ao_cmd_status = ao_cmd_syntax_error; -} - -static void -ao_config_help(void) __reentrant -{ - uint8_t cmd; - for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) - printf("%-20s %s\n", - ao_config_vars[cmd].str, - ao_config_vars[cmd].str+1+strlen(ao_config_vars[cmd].str)); -} - -static void -ao_config_show(void) __reentrant -{ - uint8_t cmd; - printf("Config version: %d.%d\n", - ao_config.major, ao_config.minor); - for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) - if (ao_config_vars[cmd].show) - (*ao_config_vars[cmd].show)(); -} - -#if HAS_EEPROM -static void -ao_config_write(void) __reentrant -{ - uint8_t saved = 0; - ao_mutex_get(&ao_config_mutex); - if (ao_config_dirty) { - _ao_config_put(); - ao_config_dirty = 0; - saved = 1; - } - ao_mutex_put(&ao_config_mutex); - if (saved) - puts("Saved"); - else - puts("Nothing to save"); -} -#endif - -__code struct ao_cmds ao_config_cmds[] = { - { ao_config_set, "c \0Set config variable (? for help, s to show)" }, - { 0, NULL }, -}; - -void -ao_config_init(void) -{ - ao_cmd_register(&ao_config_cmds[0]); -} diff --git a/src/ao_convert.c b/src/ao_convert.c deleted file mode 100644 index 0969f107..00000000 --- a/src/ao_convert.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST) -#include "ao.h" -#endif - -static const int16_t altitude_table[] = { -#include "altitude.h" -}; - -#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS) -#define ALT_FRAC_MASK (ALT_FRAC_SCALE - 1) - -int16_t -ao_pres_to_altitude(int16_t pres) __reentrant -{ - uint8_t o; - int16_t part; - - if (pres < 0) - pres = 0; - o = pres >> ALT_FRAC_BITS; - part = pres & ALT_FRAC_MASK; - - return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) + - (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS; -} - -int16_t -ao_altitude_to_pres(int16_t alt) __reentrant -{ - int16_t span, sub_span; - uint8_t l, h, m; - int32_t pres; - - l = 0; - h = NALT - 1; - while ((h - l) != 1) { - m = (l + h) >> 1; - if (altitude_table[m] < alt) - h = m; - else - l = m; - } - span = altitude_table[l] - altitude_table[h]; - sub_span = altitude_table[l] - alt; - pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span; - if (pres > 32767) - pres = 32767; - if (pres < 0) - pres = 0; - return (int16_t) pres; -} - -int16_t -ao_temp_to_dC(int16_t temp) __reentrant -{ - int16_t ret; - - /* Output voltage at 0°C = 0.755V - * Coefficient = 0.00247V/°C - * Reference voltage = 1.25V - * - * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 - * = (value - 19791.268) / 32768 * 1.25 / 0.00247 - * ≃ (value - 19791) * 1012 / 65536 - */ - ret = ((temp - 19791) * 1012L) >> 16; - return ret; -} diff --git a/src/ao_convert_test.c b/src/ao_convert_test.c deleted file mode 100644 index e2c28b73..00000000 --- a/src/ao_convert_test.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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 -#define AO_CONVERT_TEST -#include "ao_host.h" -#include "ao_convert.c" - -#define STEP 1 - -static inline i_abs(int i) { return i < 0 ? -i : i; } - -main () -{ - int i; - int16_t p_to_a, p_to_a_to_p; - int16_t a_to_p, a_to_p_to_a; - int max_p_error = 0, max_p_error_p = -1; - int max_a_error = 0, max_a_error_a = -1; - int p_error; - int a_error; - int ret = 0; - - for (i = 0; i < 32767 + STEP; i += STEP) { - if (i > 32767) - i = 32767; - p_to_a = ao_pres_to_altitude(i); - p_to_a_to_p = ao_altitude_to_pres(p_to_a); - p_error = i_abs(p_to_a_to_p - i); - if (p_error > max_p_error) { - max_p_error = p_error; - max_p_error_p = i; - } -// printf ("pres %d alt %d pres %d\n", -// i, p_to_a, p_to_a_to_p); - } - for (i = -1578; i < 15835 + STEP; i += STEP) { - if (i > 15835) - i = 15835; - a_to_p = ao_altitude_to_pres(i); - a_to_p_to_a = ao_pres_to_altitude(a_to_p); - a_error = i_abs(a_to_p_to_a - i); - if (a_error > max_a_error) { - max_a_error = a_error; - max_a_error_a = i; - } -// printf ("alt %d pres %d alt %d\n", -// i, a_to_p, a_to_p_to_a); - } - if (max_p_error > 2) { - printf ("max p error %d at %d\n", max_p_error, - max_p_error_p); - ret++; - } - if (max_a_error > 1) { - printf ("max a error %d at %d\n", max_a_error, - max_a_error_a); - ret++; - } - return ret; -} diff --git a/src/ao_dbg.c b/src/ao_dbg.c deleted file mode 100644 index d4c9567f..00000000 --- a/src/ao_dbg.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "ao_pins.h" - -static void -ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant -{ - DBG_PORT = (DBG_PORT & ~msk) | (val & msk); - _asm - nop - nop - _endasm; -} - -void -ao_dbg_send_byte(uint8_t byte) -{ - __pdata uint8_t b, d; - - DBG_PORT |= DBG_DATA; - DBG_PORT_DIR |= DBG_DATA; - for (b = 0; b < 8; b++) { - d = 0; - if (byte & 0x80) - d = DBG_DATA; - byte <<= 1; - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, 0 |d); - } - DBG_PORT_DIR &= ~DBG_DATA; -} - -uint8_t -ao_dbg_recv_byte(void) -{ - __pdata uint8_t byte, b; - - byte = 0; - for (b = 0; b < 8; b++) { - byte = byte << 1; - ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK); - if (DBG_DATA_PIN) - byte |= 1; - ao_dbg_send_bits(DBG_CLOCK, 0); - } - return byte; -} - -/* 8051 instructions - */ -#define NOP 0x00 -#define MOV_direct_data 0x75 -#define LJMP 0x02 -#define MOV_Rn_data(n) (0x78 | (n)) -#define DJNZ_Rn_rel(n) (0xd8 | (n)) -#define MOV_A_direct 0xe5 -#define MOV_direct1_direct2 0x85 -#define MOV_direct_A 0xf5 -#define MOV_DPTR_data16 0x90 -#define MOV_A_data 0x74 -#define MOVX_atDPTR_A 0xf0 -#define MOVX_A_atDPTR 0xe0 -#define INC_DPTR 0xa3 -#define TRAP 0xa5 -#define SJMP 0x80 -#define JB 0x20 - -#define DEBUG_INSTR(l) (0x54 | (l)) - -#define SFR_PSW 0xD0 -#define SFR_DPL0 0x82 -#define SFR_DPH0 0x83 -#define SFR_DPL1 0x84 -#define SFR_DPH1 0x85 - -__pdata uint8_t save_acc; -__pdata uint8_t save_psw; -__pdata uint8_t save_dpl0; -__pdata uint8_t save_dph0; -__pdata uint8_t save_dpl1; -__pdata uint8_t save_dph1; - -static uint8_t -ao_dbg_inst1(uint8_t a) __reentrant -{ - ao_dbg_send_byte(DEBUG_INSTR(1)); - ao_dbg_send_byte(a); - return ao_dbg_recv_byte(); -} - -static uint8_t -ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant -{ - ao_dbg_send_byte(DEBUG_INSTR(2)); - ao_dbg_send_byte(a); - ao_dbg_send_byte(b); - return ao_dbg_recv_byte(); -} - -static uint8_t -ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant -{ - ao_dbg_send_byte(DEBUG_INSTR(3)); - ao_dbg_send_byte(a); - ao_dbg_send_byte(b); - ao_dbg_send_byte(c); - return ao_dbg_recv_byte(); -} - -void -ao_dbg_start_transfer(uint16_t addr) -{ - save_acc = ao_dbg_inst1(NOP); - save_psw = ao_dbg_inst2(MOV_A_direct, SFR_PSW); - save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0); - save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0); - save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1); - save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1); - ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr); -} - -void -ao_dbg_end_transfer(void) -{ - ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0); - ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0); - ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1); - ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1); - ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw); - ao_dbg_inst2(MOV_A_data, save_acc); -} - -void -ao_dbg_write_byte(uint8_t byte) -{ - ao_dbg_inst2(MOV_A_data, byte); - ao_dbg_inst1(MOVX_atDPTR_A); - ao_dbg_inst1(INC_DPTR); -} - -uint8_t -ao_dbg_read_byte(void) -{ - ao_dbg_inst1(MOVX_A_atDPTR); - return ao_dbg_inst1(INC_DPTR); -} - -static void -ao_dbg_set_pins(void) -{ - /* Make the DBG pins GPIOs. On TeleMetrum, this will - * disable the SPI link, so don't expect SPI to work after - * using the debugger. - */ - DBG_PORT_SEL &= ~(DBG_CLOCK|DBG_DATA|DBG_RESET_N); - - /* make DBG_DATA tri-state */ - DBG_PORT_INP |= DBG_DATA; - - /* Raise RESET_N and CLOCK */ - DBG_PORT |= DBG_RESET_N | DBG_CLOCK; - - /* RESET_N and CLOCK are outputs now */ - DBG_PORT_DIR |= DBG_RESET_N | DBG_CLOCK; - DBG_PORT_DIR &= ~DBG_DATA; -} - -static void -ao_dbg_long_delay(void) -{ - uint8_t n; - - for (n = 0; n < 20; n++) - _asm nop _endasm; -} - -#define AO_RESET_LOW_DELAY AO_MS_TO_TICKS(100) -#define AO_RESET_HIGH_DELAY AO_MS_TO_TICKS(100) - -void -ao_dbg_debug_mode(void) -{ - ao_dbg_set_pins(); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); - ao_delay(AO_RESET_LOW_DELAY); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA|DBG_RESET_N); - ao_delay(AO_RESET_HIGH_DELAY); -} - -void -ao_dbg_reset(void) -{ - ao_dbg_set_pins(); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_delay(AO_RESET_LOW_DELAY); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); - ao_dbg_long_delay(); - ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); - ao_delay(AO_RESET_HIGH_DELAY); -} - -static void -debug_enable(void) -{ - ao_dbg_debug_mode(); -} - -static void -debug_reset(void) -{ - ao_dbg_reset(); -} - -static void -debug_put(void) -{ - for (;;) { - ao_cmd_white (); - if (ao_cmd_lex_c == '\n') - break; - ao_cmd_hex(); - if (ao_cmd_status != ao_cmd_success) - break; - ao_dbg_send_byte(ao_cmd_lex_i); - } -} - -static void -debug_get(void) -{ - __pdata uint16_t count; - __pdata uint16_t i; - __pdata uint8_t byte; - ao_cmd_hex(); - if (ao_cmd_status != ao_cmd_success) - return; - count = ao_cmd_lex_i; - if (count > 256) { - ao_cmd_status = ao_cmd_syntax_error; - return; - } - for (i = 0; i < count; i++) { - if (i && (i & 7) == 0) - putchar('\n'); - byte = ao_dbg_recv_byte(); - ao_cmd_put8(byte); - putchar(' '); - } - putchar('\n'); -} - -static uint8_t -getnibble(void) -{ - __pdata char c; - - c = getchar(); - if ('0' <= c && c <= '9') - return c - '0'; - if ('a' <= c && c <= 'f') - return c - ('a' - 10); - if ('A' <= c && c <= 'F') - return c - ('A' - 10); - ao_cmd_status = ao_cmd_lex_error; - return 0; -} - -static void -debug_input(void) -{ - __pdata uint16_t count; - __pdata uint16_t addr; - __pdata uint8_t b; - __pdata uint8_t i; - - ao_cmd_hex(); - count = ao_cmd_lex_i; - ao_cmd_hex(); - addr = ao_cmd_lex_i; - if (ao_cmd_status != ao_cmd_success) - return; - ao_dbg_start_transfer(addr); - i = 0; - while (count--) { - if (!(i++ & 7)) - putchar('\n'); - b = ao_dbg_read_byte(); - ao_cmd_put8(b); - } - ao_dbg_end_transfer(); - putchar('\n'); -} - -static void -debug_output(void) -{ - __pdata uint16_t count; - __pdata uint16_t addr; - __pdata uint8_t b; - - ao_cmd_hex(); - count = ao_cmd_lex_i; - ao_cmd_hex(); - addr = ao_cmd_lex_i; - if (ao_cmd_status != ao_cmd_success) - return; - ao_dbg_start_transfer(addr); - while (count--) { - b = getnibble() << 4; - b |= getnibble(); - if (ao_cmd_status != ao_cmd_success) - return; - ao_dbg_write_byte(b); - } - ao_dbg_end_transfer(); -} - -__code struct ao_cmds ao_dbg_cmds[7] = { - { debug_enable, "D\0Enable debug" }, - { debug_get, "G \0Get data" }, - { debug_input, "I \0Input at " }, - { debug_output, "O \0Output at " }, - { debug_put, "P ...\0Put data" }, - { debug_reset, "R\0Reset" }, - { 0, NULL }, -}; - -void -ao_dbg_init(void) -{ - ao_cmd_register(&ao_dbg_cmds[0]); -} diff --git a/src/ao_dma.c b/src/ao_dma.c deleted file mode 100644 index 6052964a..00000000 --- a/src/ao_dma.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -#define NUM_DMA 5 - -/* - * The config address for DMA0 is programmed - * separately from that of DMA1-4, but for simplicity, - * we make them all contiguous. - */ - -static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA]; -static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA]; -static __data uint8_t ao_next_dma; - -uint8_t -ao_dma_alloc(__xdata uint8_t *done) -{ - uint8_t id; - - if (ao_next_dma == NUM_DMA) - ao_panic(AO_PANIC_DMA); - id = ao_next_dma++; - ao_dma_done[id] = done; - - /* When the first dma object is allocated, set up the DMA - * controller - */ - if (id == 0) { - DMAIRQ = 0; - DMAIF = 0; - IEN1 |= IEN1_DMAIE; - } - - return id; -} - -void -ao_dma_set_transfer(uint8_t id, - void __xdata *srcaddr, - void __xdata *dstaddr, - uint16_t count, - uint8_t cfg0, - uint8_t cfg1) -{ - if (DMAARM & (1 << id)) - ao_panic(AO_PANIC_DMA); - ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8; - ao_dma_config[id].src_low = ((uint16_t) srcaddr); - ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8; - ao_dma_config[id].dst_low = ((uint16_t) dstaddr); - ao_dma_config[id].len_high = count >> 8; - ao_dma_config[id].len_low = count; - ao_dma_config[id].cfg0 = cfg0; - ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK; - if (id == 0) { - DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8; - DMA0CFGL = ((uint16_t) (&ao_dma_config[0])); - } else { - DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8; - DMA1CFGL = ((uint16_t) (&ao_dma_config[1])); - } -} - -#define nop() _asm nop _endasm; - -void -ao_dma_start(uint8_t id) -{ - uint8_t mask = (1 << id); - DMAIRQ &= ~mask; - DMAARM = 0x80 | mask; - nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); - *(ao_dma_done[id]) = 0; - DMAARM = mask; - nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); - nop(); -} - -void -ao_dma_trigger(uint8_t id) -{ - DMAREQ |= (1 << id); -} - -void -ao_dma_abort(uint8_t id) -{ - uint8_t mask = (1 << id); - DMAARM = 0x80 | mask; - DMAIRQ &= ~mask; -} - -void -ao_dma_isr(void) __interrupt 8 -{ - uint8_t id, mask; - - /* Find the first DMA channel which is done */ - mask = 1; - for (id = 0; id < ao_next_dma; id++) { - if (DMAIRQ & mask) { - /* Clear CPU interrupt flag */ - DMAIF = 0; - /* Clear the completed ID */ - DMAIRQ = ~mask; - *(ao_dma_done[id]) = 1; - ao_wakeup(ao_dma_done[id]); - break; - } - mask <<= 1; - } -} diff --git a/src/ao_ee.c b/src/ao_ee.c deleted file mode 100644 index a2fe8dc1..00000000 --- a/src/ao_ee.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "25lc1024.h" - -#define EE_BLOCK_SIZE ((uint16_t) (256)) -#define EE_BLOCK_SHIFT 8 -#define EE_DEVICE_SIZE ((uint32_t) 128 * (uint32_t) 1024) - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -__pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -__pdata uint16_t ao_storage_unit; - -/* - * Using SPI on USART 0, with P1_2 as the chip select - */ - -#define EE_CS P1_2 -#define EE_CS_INDEX 2 - -static __xdata uint8_t ao_ee_mutex; - -#define ao_ee_delay() do { \ - _asm nop _endasm; \ - _asm nop _endasm; \ - _asm nop _endasm; \ -} while(0) - -#define ao_ee_cs_low() ao_spi_get_bit(EE_CS) - -#define ao_ee_cs_high() ao_spi_put_bit(EE_CS) - -struct ao_ee_instruction { - uint8_t instruction; - uint8_t address[3]; -} __xdata ao_ee_instruction; - -static void -ao_ee_write_enable(void) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_WREN; - ao_spi_send(&ao_ee_instruction, 1); - ao_ee_cs_high(); -} - -static uint8_t -ao_ee_rdsr(void) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_RDSR; - ao_spi_send(&ao_ee_instruction, 1); - ao_spi_recv(&ao_ee_instruction, 1); - ao_ee_cs_high(); - return ao_ee_instruction.instruction; -} - -static void -ao_ee_wrsr(uint8_t status) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_WRSR; - ao_ee_instruction.address[0] = status; - ao_spi_send(&ao_ee_instruction, 2); - ao_ee_cs_high(); -} - -#define EE_BLOCK_NONE 0xffff - -static __xdata uint8_t ao_ee_data[EE_BLOCK_SIZE]; -static __pdata uint16_t ao_ee_block = EE_BLOCK_NONE; -static __pdata uint8_t ao_ee_block_dirty; - -/* Write the current block to the EEPROM */ -static void -ao_ee_write_block(void) -{ - uint8_t status; - - status = ao_ee_rdsr(); - if (status & (EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN)) { - status &= ~(EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN); - ao_ee_wrsr(status); - } - ao_ee_write_enable(); - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_WRITE; - ao_ee_instruction.address[0] = ao_ee_block >> 8; - ao_ee_instruction.address[1] = ao_ee_block; - ao_ee_instruction.address[2] = 0; - ao_spi_send(&ao_ee_instruction, 4); - ao_spi_send(ao_ee_data, EE_BLOCK_SIZE); - ao_ee_cs_high(); - for (;;) { - uint8_t status = ao_ee_rdsr(); - if ((status & EE_STATUS_WIP) == 0) - break; - } -} - -/* Read the current block from the EEPROM */ -static void -ao_ee_read_block(void) -{ - ao_ee_cs_low(); - ao_ee_instruction.instruction = EE_READ; - ao_ee_instruction.address[0] = ao_ee_block >> 8; - ao_ee_instruction.address[1] = ao_ee_block; - ao_ee_instruction.address[2] = 0; - ao_spi_send(&ao_ee_instruction, 4); - ao_spi_recv(ao_ee_data, EE_BLOCK_SIZE); - ao_ee_cs_high(); -} - -static void -ao_ee_flush_internal(void) -{ - if (ao_ee_block_dirty) { - ao_ee_write_block(); - ao_ee_block_dirty = 0; - } -} - -static void -ao_ee_fill(uint16_t block) -{ - if (block != ao_ee_block) { - ao_ee_flush_internal(); - ao_ee_block = block; - ao_ee_read_block(); - } -} - -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); - - /* Transfer the data */ - ao_mutex_get(&ao_ee_mutex); { - if (len != EE_BLOCK_SIZE) - ao_ee_fill(block); - else { - ao_ee_flush_internal(); - ao_ee_block = block; - } - memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len); - ao_ee_block_dirty = 1; - } ao_mutex_put(&ao_ee_mutex); - return 1; -} - -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); - - /* Transfer the data */ - ao_mutex_get(&ao_ee_mutex); { - ao_ee_fill(block); - memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len); - } ao_mutex_put(&ao_ee_mutex); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ - ao_mutex_get(&ao_ee_mutex); { - ao_ee_flush_internal(); - } ao_mutex_put(&ao_ee_mutex); -} - -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - ao_mutex_get(&ao_ee_mutex); { - ao_ee_flush_internal(); - ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT); - memset(ao_ee_data, 0xff, EE_BLOCK_SIZE); - ao_ee_block_dirty = 1; - } ao_mutex_put(&ao_ee_mutex); - return 1; -} - -static void -ee_store(void) __reentrant -{ -} - -void -ao_storage_setup(void) -{ - if (ao_storage_total == 0) { - ao_storage_total = EE_DEVICE_SIZE; - ao_storage_block = EE_BLOCK_SIZE; - ao_storage_config = EE_DEVICE_SIZE - EE_BLOCK_SIZE; - ao_storage_unit = EE_BLOCK_SIZE; - } -} - -void -ao_storage_device_info(void) __reentrant -{ -} - -/* - * To initialize the chip, set up the CS line and - * the SPI interface - */ -void -ao_storage_device_init(void) -{ - /* set up CS */ - EE_CS = 1; - P1DIR |= (1 << EE_CS_INDEX); - P1SEL &= ~(1 << EE_CS_INDEX); -} diff --git a/src/ao_ee_fake.c b/src/ao_ee_fake.c deleted file mode 100644 index b0c1d61e..00000000 --- a/src/ao_ee_fake.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -/* - * For hardware without eeprom, the config code still - * wants to call these functions - */ -uint8_t -ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant -{ - (void) buf; - (void) len; - return 1; -} - -uint8_t -ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant -{ - memset(buf, '\0', len); - return 1; -} diff --git a/src/ao_flash.c b/src/ao_flash.c deleted file mode 100644 index bb40f6f7..00000000 --- a/src/ao_flash.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "at45db161d.h" - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -__pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -__pdata uint16_t ao_storage_unit; - -#define FLASH_CS P1_1 -#define FLASH_CS_INDEX 1 - -#define FLASH_BLOCK_SIZE_MAX 512 - -__xdata uint8_t ao_flash_mutex; - -#define ao_flash_delay() do { \ - _asm nop _endasm; \ - _asm nop _endasm; \ - _asm nop _endasm; \ -} while(0) - -#define ao_flash_cs_low() ao_spi_get_bit(FLASH_CS) - -#define ao_flash_cs_high() ao_spi_put_bit(FLASH_CS) - -struct ao_flash_instruction { - uint8_t instruction; - uint8_t address[3]; -} __xdata ao_flash_instruction; - -static void -ao_flash_set_pagesize_512(void) -{ - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_SET_CONFIG; - ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0; - ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1; - ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2; - ao_spi_send(&ao_flash_instruction, 4); - ao_flash_cs_high(); -} - - -static uint8_t -ao_flash_read_status(void) -{ - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_READ_STATUS; - ao_spi_send(&ao_flash_instruction, 1); - ao_spi_recv(&ao_flash_instruction, 1); - ao_flash_cs_high(); - return ao_flash_instruction.instruction; -} - -#define FLASH_BLOCK_NONE 0xffff - -static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX]; -static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE; -static __pdata uint8_t ao_flash_block_dirty; -static __pdata uint8_t ao_flash_write_pending; -static __pdata uint8_t ao_flash_setup_done; -static __pdata uint8_t ao_flash_block_shift; -static __pdata uint16_t ao_flash_block_size; -static __pdata uint16_t ao_flash_block_mask; - -void -ao_storage_setup(void) __reentrant -{ - uint8_t status; - - if (ao_flash_setup_done) - return; - - ao_mutex_get(&ao_flash_mutex); - if (ao_flash_setup_done) { - ao_mutex_put(&ao_flash_mutex); - return; - } - - /* On first use, check to see if the flash chip has - * been programmed to use 512 byte pages. If not, do so. - * And then, because the flash part must be power cycled - * for that change to take effect, panic. - */ - status = ao_flash_read_status(); - - if (!(status & FLASH_STATUS_PAGESIZE_512)) { - ao_flash_set_pagesize_512(); - ao_panic(AO_PANIC_FLASH); - } - - switch (status & 0x3c) { - - /* AT45DB321D */ - case 0x34: - ao_flash_block_shift = 9; - ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024); - break; - - /* AT45DB161D */ - case 0x2c: - ao_flash_block_shift = 9; - ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024); - break; - - /* AT45DB081D */ - case 0x24: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024); - break; - - /* AT45DB041D */ - case 0x1c: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024); - break; - - /* AT45DB021D */ - case 0x14: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024); - break; - - /* AT45DB011D */ - case 0x0c: - ao_flash_block_shift = 8; - ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024); - break; - - default: - ao_panic(AO_PANIC_FLASH); - } - ao_flash_block_size = 1 << ao_flash_block_shift; - ao_flash_block_mask = ao_flash_block_size - 1; - - ao_storage_block = ao_flash_block_size; - ao_storage_config = ao_storage_total - ao_storage_block; - ao_storage_unit = ao_flash_block_size; - - ao_flash_setup_done = 1; - ao_mutex_put(&ao_flash_mutex); -} - -static void -ao_flash_wait_write(void) -{ - if (ao_flash_write_pending) { - for (;;) { - uint8_t status = ao_flash_read_status(); - if ((status & FLASH_STATUS_RDY)) - break; - } - ao_flash_write_pending = 0; - } -} - -/* Write the current block to the FLASHPROM */ -static void -ao_flash_write_block(void) -{ - ao_flash_wait_write(); - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_WRITE; - - /* 13/14 block bits + 9/8 byte bits (always 0) */ - ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); - ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); - ao_flash_instruction.address[2] = 0; - ao_spi_send(&ao_flash_instruction, 4); - ao_spi_send(ao_flash_data, ao_storage_block); - ao_flash_cs_high(); - ao_flash_write_pending = 1; -} - -/* Read the current block from the FLASHPROM */ -static void -ao_flash_read_block(void) -{ - ao_flash_wait_write(); - ao_flash_cs_low(); - ao_flash_instruction.instruction = FLASH_READ; - - /* 13/14 block bits + 9/8 byte bits (always 0) */ - ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); - ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); - ao_flash_instruction.address[2] = 0; - ao_spi_send(&ao_flash_instruction, 4); - ao_spi_recv(ao_flash_data, ao_flash_block_size); - ao_flash_cs_high(); -} - -static void -ao_flash_flush_internal(void) -{ - if (ao_flash_block_dirty) { - ao_flash_write_block(); - ao_flash_block_dirty = 0; - } -} - -static void -ao_flash_fill(uint16_t block) -{ - if (block != ao_flash_block) { - ao_flash_flush_internal(); - ao_flash_block = block; - ao_flash_read_block(); - } -} - -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); - - /* Transfer the data */ - ao_mutex_get(&ao_flash_mutex); { - if (len != ao_flash_block_size) - ao_flash_fill(block); - else { - ao_flash_flush_internal(); - ao_flash_block = block; - } - memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), - buf, - len); - ao_flash_block_dirty = 1; - } ao_mutex_put(&ao_flash_mutex); - return 1; -} - -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); - - /* Transfer the data */ - ao_mutex_get(&ao_flash_mutex); { - ao_flash_fill(block); - memcpy(buf, - ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), - len); - } ao_mutex_put(&ao_flash_mutex); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ - ao_mutex_get(&ao_flash_mutex); { - ao_flash_flush_internal(); - } ao_mutex_put(&ao_flash_mutex); -} - -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - ao_mutex_get(&ao_flash_mutex); { - ao_flash_flush_internal(); - ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift); - memset(ao_flash_data, 0xff, ao_flash_block_size); - ao_flash_block_dirty = 1; - } ao_mutex_put(&ao_flash_mutex); - return 1; -} - -void -ao_storage_device_info(void) __reentrant -{ - uint8_t status; - - ao_storage_setup(); - ao_mutex_get(&ao_flash_mutex); { - status = ao_flash_read_status(); - printf ("Flash status: 0x%02x\n", status); - printf ("Flash block shift: %d\n", ao_flash_block_shift); - printf ("Flash block size: %d\n", ao_flash_block_size); - printf ("Flash block mask: %d\n", ao_flash_block_mask); - printf ("Flash device size: %ld\n", ao_storage_total); - } ao_mutex_put(&ao_flash_mutex); -} - -/* - * To initialize the chip, set up the CS line and - * the SPI interface - */ -void -ao_storage_device_init(void) -{ - /* set up CS */ - FLASH_CS = 1; - P1DIR |= (1 << FLASH_CS_INDEX); - P1SEL &= ~(1 << FLASH_CS_INDEX); -} diff --git a/src/ao_flight.c b/src/ao_flight.c deleted file mode 100644 index 85c1825b..00000000 --- a/src/ao_flight.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef AO_FLIGHT_TEST -#include "ao.h" -#endif - -#ifndef HAS_ACCEL -#error Please define HAS_ACCEL -#endif - -#ifndef HAS_GPS -#error Please define HAS_GPS -#endif - -#ifndef HAS_USB -#error Please define HAS_USB -#endif - -/* Main flight thread. */ - -__pdata enum ao_flight_state ao_flight_state; /* current flight state */ -__pdata uint16_t ao_launch_tick; /* time of launch detect */ - -/* - * track min/max data over a long interval to detect - * resting - */ -__pdata uint16_t ao_interval_end; -__pdata int16_t ao_interval_min_height; -__pdata int16_t ao_interval_max_height; -__pdata uint8_t ao_flight_force_idle; - -/* We also have a clock, which can be used to sanity check things in - * case of other failures - */ - -#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) - -/* Landing is detected by getting constant readings from both pressure and accelerometer - * for a fairly long time (AO_INTERVAL_TICKS) - */ -#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10) - -#define abs(a) ((a) < 0 ? -(a) : (a)) - -void -ao_flight(void) -{ - ao_sample_init(); - ao_flight_state = ao_flight_startup; - for (;;) { - - /* - * Process ADC samples, just looping - * until the sensors are calibrated. - */ - if (!ao_sample()) - continue; - - switch (ao_flight_state) { - case ao_flight_startup: - - /* Check to see what mode we should go to. - * - Invalid mode if accel cal appears to be out - * - pad mode if we're upright, - * - idle mode otherwise - */ -#if HAS_ACCEL - if (ao_config.accel_plus_g == 0 || - ao_config.accel_minus_g == 0 || - ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || - ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) - { - /* Detected an accel value outside -1.5g to 1.5g - * (or uncalibrated values), so we go into invalid mode - */ - ao_flight_state = ao_flight_invalid; - - } else -#endif - if (!ao_flight_force_idle -#if HAS_ACCEL - && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP -#endif - ) - { - /* Set pad mode - we can fly! */ - ao_flight_state = ao_flight_pad; -#if HAS_USB - /* Disable the USB controller in flight mode - * to save power - */ - ao_usb_disable(); -#endif - - /* Disable packet mode in pad state */ - ao_packet_slave_stop(); - - /* Turn on telemetry system */ - ao_rdf_set(1); - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); - - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - } else { - /* Set idle mode */ - ao_flight_state = ao_flight_idle; - - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - } - /* wakeup threads due to state change */ - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - - break; - case ao_flight_pad: - - /* pad to boost: - * - * barometer: > 20m vertical motion - * OR - * accelerometer: > 2g AND velocity > 5m/s - * - * The accelerometer should always detect motion before - * the barometer, but we use both to make sure this - * transition is detected. If the device - * doesn't have an accelerometer, then ignore the - * speed and acceleration as they are quite noisy - * on the pad. - */ - if (ao_height > AO_M_TO_HEIGHT(20) -#if HAS_ACCEL - || (ao_accel > AO_MSS_TO_ACCEL(20) && - ao_speed > AO_MS_TO_SPEED(5)) -#endif - ) - { - ao_flight_state = ao_flight_boost; - ao_launch_tick = ao_sample_tick; - - /* start logging data */ - ao_log_start(); - - /* Increase telemetry rate */ - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT); - - /* disable RDF beacon */ - ao_rdf_set(0); - -#if HAS_GPS - /* Record current GPS position by waking up GPS log tasks */ - ao_wakeup(&ao_gps_data); - ao_wakeup(&ao_gps_tracking_data); -#endif - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - case ao_flight_boost: - - /* boost to fast: - * - * accelerometer: start to fall at > 1/4 G - * OR - * time: boost for more than 15 seconds - * - * Detects motor burn out by the switch from acceleration to - * deceleration, or by waiting until the maximum burn duration - * (15 seconds) has past. - */ - if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || - (int16_t) (ao_sample_tick - ao_launch_tick) > BOOST_TICKS_MAX) - { -#if HAS_ACCEL - ao_flight_state = ao_flight_fast; -#else - ao_flight_state = ao_flight_coast; -#endif - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; -#if HAS_ACCEL - case ao_flight_fast: - /* - * This is essentially the same as coast, - * but the barometer is being ignored as - * it may be unreliable. - */ - if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) - { - ao_flight_state = ao_flight_coast; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; -#endif - case ao_flight_coast: - - /* apogee detect: coast to drogue deploy: - * - * speed: < 0 - * - * Also make sure the model altitude is tracking - * the measured altitude reasonably closely; otherwise - * we're probably transsonic. - */ - if (ao_speed < 0 -#if !HAS_ACCEL - && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) -#endif - ) - { - /* ignite the drogue charge */ - ao_ignite(ao_igniter_drogue); - - /* slow down the telemetry system */ - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); - - /* Turn the RDF beacon back on */ - ao_rdf_set(1); - - /* and enter drogue state */ - ao_flight_state = ao_flight_drogue; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - - break; - case ao_flight_drogue: - - /* drogue to main deploy: - * - * barometer: reach main deploy altitude - * - * Would like to use the accelerometer for this test, but - * the orientation of the flight computer is unknown after - * drogue deploy, so we ignore it. Could also detect - * high descent rate using the pressure sensor to - * recognize drogue deploy failure and eject the main - * at that point. Perhaps also use the drogue sense lines - * to notice continutity? - */ - if (ao_height <= ao_config.main_deploy) - { - ao_ignite(ao_igniter_main); - - /* - * Start recording min/max height - * to figure out when the rocket has landed - */ - - /* initialize interval values */ - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - - ao_interval_min_height = ao_interval_max_height = ao_avg_height; - - ao_flight_state = ao_flight_main; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - - /* fall through... */ - case ao_flight_main: - - /* main to land: - * - * barometer: altitude stable - */ - - if (ao_avg_height < ao_interval_min_height) - ao_interval_min_height = ao_avg_height; - if (ao_avg_height > ao_interval_max_height) - ao_interval_max_height = ao_avg_height; - - if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { - if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4)) - { - ao_flight_state = ao_flight_landed; - - /* turn off the ADC capture */ - ao_timer_set_adc_interval(0); - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - ao_interval_min_height = ao_interval_max_height = ao_avg_height; - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - } - break; - case ao_flight_landed: - break; - } - } -} - -static __xdata struct ao_task flight_task; - -void -ao_flight_init(void) -{ - ao_flight_state = ao_flight_startup; - ao_add_task(&flight_task, ao_flight, "flight"); -} diff --git a/src/ao_flight_nano.c b/src/ao_flight_nano.c deleted file mode 100644 index 2e332b12..00000000 --- a/src/ao_flight_nano.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -/* Main flight thread. */ - -__pdata enum ao_flight_state ao_flight_state; /* current flight state */ -__pdata uint16_t ao_launch_tick; /* time of launch detect */ - -/* - * track min/max data over a long interval to detect - * resting - */ -__pdata uint16_t ao_interval_end; -__pdata int16_t ao_interval_min_height; -__pdata int16_t ao_interval_max_height; - -__pdata uint8_t ao_flight_force_idle; - -/* Landing is detected by getting constant readings from both pressure and accelerometer - * for a fairly long time (AO_INTERVAL_TICKS) - */ -#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5) - -static void -ao_flight_nano(void) -{ - ao_sample_init(); - ao_flight_state = ao_flight_startup; - - for (;;) { - /* - * Process ADC samples, just looping - * until the sensors are calibrated. - */ - if (!ao_sample()) - continue; - - switch (ao_flight_state) { - case ao_flight_startup: - if (ao_flight_force_idle) { - /* Set idle mode */ - ao_flight_state = ao_flight_idle; - } else { - ao_flight_state = ao_flight_pad; - /* Disable packet mode in pad state */ - ao_packet_slave_stop(); - - /* Turn on telemetry system */ - ao_rdf_set(1); - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); - } - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - - /* wakeup threads due to state change */ - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - break; - case ao_flight_pad: - if (ao_height> AO_M_TO_HEIGHT(20)) { - ao_flight_state = ao_flight_drogue; - ao_launch_tick = ao_sample_tick; - - /* start logging data */ - ao_log_start(); - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - case ao_flight_drogue: - /* drogue/main to land: - * - * barometer: altitude stable - */ - - if (ao_height < ao_interval_min_height) - ao_interval_min_height = ao_height; - if (ao_height > ao_interval_max_height) - ao_interval_max_height = ao_height; - - if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { - if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) - { - ao_flight_state = ao_flight_landed; - - /* turn off the ADC capture */ - ao_timer_set_adc_interval(0); - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - ao_interval_min_height = ao_interval_max_height = ao_height; - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - } - break; - } - } -} - -static __xdata struct ao_task flight_task; - -void -ao_flight_nano_init(void) -{ - ao_flight_state = ao_flight_startup; - ao_add_task(&flight_task, ao_flight_nano, "flight"); -} diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c deleted file mode 100644 index 56733c89..00000000 --- a/src/ao_flight_test.c +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 -#include -#include -#include -#include -#include - -#define AO_HERTZ 100 - -#define AO_ADC_RING 64 -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) - -#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) -#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) -#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) - -/* - * One set of samples read from the A/D converter - */ -struct ao_adc { - uint16_t tick; /* tick when the sample was read */ - int16_t accel; /* accelerometer */ - int16_t pres; /* pressure sensor */ - int16_t pres_real; /* unclipped */ - int16_t temp; /* temperature sensor */ - int16_t v_batt; /* battery voltage */ - int16_t sense_d; /* drogue continuity sense */ - int16_t sense_m; /* main continuity sense */ -}; - -#define __pdata -#define __data -#define __xdata -#define __code -#define __reentrant - -#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) -#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) -#define from_fix(x) ((x) >> 16) - -/* - * 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) - -/* - * Above this speed, baro measurements are unreliable - */ -#define AO_MAX_BARO_SPEED 200 - -#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 -#define TRUE 1 - -struct ao_adc ao_adc_ring[AO_ADC_RING]; -uint8_t ao_adc_head; -int ao_summary = 0; - -#define ao_led_on(l) -#define ao_led_off(l) -#define ao_timer_set_adc_interval(i) -#define ao_wakeup(wchan) ao_dump_state() -#define ao_cmd_register(c) -#define ao_usb_disable() -#define ao_telemetry_set_interval(x) -#define ao_rdf_set(rdf) -#define ao_packet_slave_start() -#define ao_packet_slave_stop() - -enum ao_igniter { - ao_igniter_drogue = 0, - ao_igniter_main = 1 -}; - -struct ao_adc ao_adc_static; - -int drogue_height; -double drogue_time; -int main_height; -double main_time; - -int tick_offset; - -static int32_t ao_k_height; - -void -ao_ignite(enum ao_igniter igniter) -{ - double time = (double) (ao_adc_static.tick + tick_offset) / 100; - - if (igniter == ao_igniter_drogue) { - drogue_time = time; - drogue_height = ao_k_height >> 16; - } else { - main_time = time; - main_height = ao_k_height >> 16; - } -} - -struct ao_task { - int dummy; -}; - -#define ao_add_task(t,f,n) - -#define ao_log_start() -#define ao_log_stop() - -#define AO_MS_TO_TICKS(ms) ((ms) / 10) -#define AO_SEC_TO_TICKS(s) ((s) * 100) - -#define AO_FLIGHT_TEST - -int ao_flight_debug; - -FILE *emulator_in; -char *emulator_app; -char *emulator_name; -double emulator_error_max = 4; -double emulator_height_error_max = 20; /* noise in the baro sensor */ - -void -ao_dump_state(void); - -void -ao_sleep(void *wchan); - -const char const * const ao_state_names[] = { - "startup", "idle", "pad", "boost", "fast", - "coast", "drogue", "main", "landed", "invalid" -}; - -struct ao_cmds { - void (*func)(void); - const char *help; -}; - -#include "ao_convert.c" - -struct ao_config { - uint16_t main_deploy; - int16_t accel_plus_g; - int16_t accel_minus_g; - uint8_t pad_orientation; -}; - -#define AO_PAD_ORIENTATION_ANTENNA_UP 0 -#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 - -#define ao_config_get() - -struct ao_config ao_config; - -#define DATA_TO_XDATA(x) (x) - -#define HAS_FLIGHT 1 -#define HAS_ADC 1 -#define HAS_USB 1 -#define HAS_GPS 1 -#ifndef HAS_ACCEL -#define HAS_ACCEL 1 -#define HAS_ACCEL_REF 0 -#endif - -#define GRAVITY 9.80665 -extern int16_t ao_ground_accel, ao_flight_accel; -extern int16_t ao_accel_2g; - -extern uint16_t ao_sample_tick; - -extern int16_t ao_sample_height; -extern int16_t ao_sample_accel; -extern int32_t ao_accel_scale; -extern int16_t ao_ground_height; -extern int16_t ao_sample_alt; - -int ao_sample_prev_tick; -uint16_t prev_tick; - -#include "ao_kalman.c" -#include "ao_sample.c" -#include "ao_flight.c" - -#define to_double(f) ((f) / 65536.0) - -static int ao_records_read = 0; -static int ao_eof_read = 0; -static int ao_flight_ground_accel; -static int ao_flight_started = 0; -static int ao_test_max_height; -static double ao_test_max_height_time; -static int ao_test_main_height; -static double ao_test_main_height_time; -static double ao_test_landed_time; -static double ao_test_landed_height; -static double ao_test_landed_time; -static int landed_set; -static double landed_time; -static double landed_height; - -void -ao_test_exit(void) -{ - double drogue_error; - double main_error; - double landed_error; - double landed_time_error; - - if (!ao_test_main_height_time) { - ao_test_main_height_time = ao_test_max_height_time; - ao_test_main_height = ao_test_max_height; - } - drogue_error = fabs(ao_test_max_height_time - drogue_time); - main_error = fabs(ao_test_main_height_time - main_time); - landed_error = fabs(ao_test_landed_height - landed_height); - landed_time_error = ao_test_landed_time - landed_time; - if (drogue_error > emulator_error_max || main_error > emulator_error_max || - landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) { - printf ("%s %s\n", - emulator_app, emulator_name); - printf ("\tApogee error %g\n", drogue_error); - printf ("\tMain error %g\n", main_error); - printf ("\tLanded height error %g\n", landed_error); - printf ("\tLanded time error %g\n", landed_time_error); - printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", - ao_test_max_height, ao_test_max_height_time, - ao_test_main_height, ao_test_main_height_time, - ao_test_landed_height, ao_test_landed_time); - printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", - drogue_height, drogue_time, main_height, main_time, - landed_height, landed_time); - exit (1); - } - exit(0); -} - -void -ao_insert(void) -{ - double time; - - ao_adc_ring[ao_adc_head] = ao_adc_static; - ao_adc_head = ao_adc_ring_next(ao_adc_head); - if (ao_flight_state != ao_flight_startup) { - double height = ao_pres_to_altitude(ao_adc_static.pres_real) - ao_ground_height; - double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / - (ao_config.accel_minus_g - ao_config.accel_plus_g); - - if (!tick_offset) - tick_offset = -ao_adc_static.tick; - if ((prev_tick - ao_adc_static.tick) > 0x400) - tick_offset += 65536; - prev_tick = ao_adc_static.tick; - time = (double) (ao_adc_static.tick + tick_offset) / 100; - - if (ao_test_max_height < height) { - ao_test_max_height = height; - ao_test_max_height_time = time; - ao_test_landed_height = height; - ao_test_landed_time = time; - } - if (height > ao_config.main_deploy) { - ao_test_main_height_time = time; - ao_test_main_height = height; - } - - if (ao_test_landed_height > height) { - ao_test_landed_height = height; - ao_test_landed_time = time; - } - - if (ao_flight_state == ao_flight_landed && !landed_set) { - landed_set = 1; - landed_time = time; - landed_height = height; - } - - 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", - time, - height, - accel, - ao_state_names[ao_flight_state], - ao_k_height / 65536.0, - ao_k_speed / 65536.0 / 16.0, - ao_k_accel / 65536.0 / 16.0, - ao_avg_height, - drogue_height, - main_height, - ao_error_h_sq_avg); - -// if (ao_flight_state == ao_flight_landed) -// ao_test_exit(); - } - } -} - -#define AO_MAX_CALLSIGN 8 -#define AO_MAX_VERSION 8 -#define AO_MAX_TELEMETRY 128 - -struct ao_telemetry_generic { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t payload[27]; /* 5 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 -#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 -#define AO_TELEMETRY_SENSOR_TELENANO 0x03 - -struct ao_telemetry_sensor { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t state; /* 5 flight state */ - int16_t accel; /* 6 accelerometer (TM only) */ - int16_t pres; /* 8 pressure sensor */ - int16_t temp; /* 10 temperature sensor */ - int16_t v_batt; /* 12 battery voltage */ - int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ - int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ - - int16_t acceleration; /* 18 m/s² * 16 */ - int16_t speed; /* 20 m/s * 16 */ - int16_t height; /* 22 m */ - - int16_t ground_pres; /* 24 average pres on pad */ - int16_t ground_accel; /* 26 average accel on pad */ - int16_t accel_plus_g; /* 28 accel calibration at +1g */ - int16_t accel_minus_g; /* 30 accel calibration at -1g */ - /* 32 */ -}; - -#define AO_TELEMETRY_CONFIGURATION 0x04 - -struct ao_telemetry_configuration { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t device; /* 5 device type */ - uint16_t flight; /* 6 flight number */ - uint8_t config_major; /* 8 Config major version */ - uint8_t config_minor; /* 9 Config minor version */ - uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ - uint16_t main_deploy; /* 12 Main deploy alt in meters */ - uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ - char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ - char version[AO_MAX_VERSION]; /* 24 Software version */ - /* 32 */ -}; - -#define AO_TELEMETRY_LOCATION 0x05 - -#define AO_GPS_MODE_NOT_VALID 'N' -#define AO_GPS_MODE_AUTONOMOUS 'A' -#define AO_GPS_MODE_DIFFERENTIAL 'D' -#define AO_GPS_MODE_ESTIMATED 'E' -#define AO_GPS_MODE_MANUAL 'M' -#define AO_GPS_MODE_SIMULATED 'S' - -struct ao_telemetry_location { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - - uint8_t flags; /* 5 Number of sats and other flags */ - int16_t altitude; /* 6 GPS reported altitude (m) */ - int32_t latitude; /* 8 latitude (degrees * 10⁷) */ - int32_t longitude; /* 12 longitude (degrees * 10⁷) */ - uint8_t year; /* 16 (- 2000) */ - uint8_t month; /* 17 (1-12) */ - uint8_t day; /* 18 (1-31) */ - uint8_t hour; /* 19 (0-23) */ - uint8_t minute; /* 20 (0-59) */ - uint8_t second; /* 21 (0-59) */ - uint8_t pdop; /* 22 (m * 5) */ - uint8_t hdop; /* 23 (m * 5) */ - uint8_t vdop; /* 24 (m * 5) */ - uint8_t mode; /* 25 */ - uint16_t ground_speed; /* 26 cm/s */ - int16_t climb_rate; /* 28 cm/s */ - uint8_t course; /* 30 degrees / 2 */ - uint8_t unused[1]; /* 31 */ - /* 32 */ -}; - -#define AO_TELEMETRY_SATELLITE 0x06 - -struct ao_telemetry_satellite_info { - uint8_t svid; - uint8_t c_n_1; -}; - -struct ao_telemetry_satellite { - uint16_t serial; /* 0 */ - uint16_t tick; /* 2 */ - uint8_t type; /* 4 */ - uint8_t channels; /* 5 number of reported sats */ - - struct ao_telemetry_satellite_info sats[12]; /* 6 */ - uint8_t unused[2]; /* 30 */ - /* 32 */ -}; - -union ao_telemetry_all { - struct ao_telemetry_generic generic; - struct ao_telemetry_sensor sensor; - struct ao_telemetry_configuration configuration; - struct ao_telemetry_location location; - struct ao_telemetry_satellite satellite; -}; - -uint16_t -uint16(uint8_t *bytes, int off) -{ - off++; - return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8); -} - -int16_t -int16(uint8_t *bytes, int off) -{ - return (int16_t) uint16(bytes, off); -} - -void -ao_sleep(void *wchan) -{ - if (wchan == &ao_adc_head) { - char type; - uint16_t tick; - uint16_t a, b; - int ret; - uint8_t bytes[1024]; - union ao_telemetry_all telem; - char line[1024]; - char *saveptr; - char *l; - char *words[64]; - int nword; - - for (;;) { - if (ao_records_read > 2 && ao_flight_state == ao_flight_startup) - { - ao_adc_static.accel = ao_flight_ground_accel; - ao_insert(); - return; - } - - if (!fgets(line, sizeof (line), emulator_in)) { - if (++ao_eof_read >= 1000) { - if (!ao_summary) - printf ("no more data, exiting simulation\n"); - ao_test_exit(); - } - ao_adc_static.tick += 10; - ao_insert(); - return; - } - l = line; - for (nword = 0; nword < 64; nword++) { - words[nword] = strtok_r(l, " \t\n", &saveptr); - l = NULL; - if (words[nword] == NULL) - break; - } - if (nword == 4) { - 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'; - } 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]); - } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { - ao_config.main_deploy = atoi(words[2]); - } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { - tick = atoi(words[10]); - if (!ao_flight_started) { - type = 'F'; - a = atoi(words[26]); - ao_flight_started = 1; - } else { - type = 'A'; - a = atoi(words[12]); - b = atoi(words[14]); - } - } else if (nword == 3 && strcmp(words[0], "BARO") == 0) { - tick = strtol(words[1], NULL, 16); - a = 16384 - 328; - b = strtol(words[2], NULL, 10); - type = 'A'; - if (!ao_flight_started) { - ao_flight_ground_accel = 16384 - 328; - ao_config.accel_plus_g = 16384 - 328; - ao_config.accel_minus_g = 16384 + 328; - ao_flight_started = 1; - } - } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { - char *hex = words[1]; - char elt[3]; - int i, len; - uint8_t sum; - - len = strlen(hex); - if (len > sizeof (bytes) * 2) { - len = sizeof (bytes)*2; - hex[len] = '\0'; - } - for (i = 0; i < len; i += 2) { - elt[0] = hex[i]; - elt[1] = hex[i+1]; - elt[2] = '\0'; - bytes[i/2] = (uint8_t) strtol(elt, NULL, 16); - } - len = i/2; - if (bytes[0] != len - 2) { - printf ("bad length %d != %d\n", bytes[0], len - 2); - continue; - } - sum = 0x5a; - for (i = 1; i < len-1; i++) - sum += bytes[i]; - if (sum != bytes[len-1]) { - printf ("bad checksum\n"); - continue; - } - if ((bytes[len-2] & 0x80) == 0) { - continue; - } - if (len == 36) { - memcpy(&telem, bytes + 1, 32); - tick = telem.generic.tick; - switch (telem.generic.type) { - case AO_TELEMETRY_SENSOR_TELEMETRUM: - case AO_TELEMETRY_SENSOR_TELEMINI: - case AO_TELEMETRY_SENSOR_TELENANO: - if (!ao_flight_started) { - ao_flight_ground_accel = telem.sensor.ground_accel; - ao_config.accel_plus_g = telem.sensor.accel_plus_g; - ao_config.accel_minus_g = telem.sensor.accel_minus_g; - ao_flight_started = 1; - } - type = 'A'; - a = telem.sensor.accel; - b = telem.sensor.pres; - break; - } - } 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); - type = 'A'; - a = int16(bytes, 23); - b = int16(bytes, 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); - type = 'A'; - a = int16(bytes, 22); - b = int16(bytes, 24); - } else { - printf("unknown len %d\n", len); - continue; - } - } - if (type != 'F' && !ao_flight_started) - continue; - - switch (type) { - case 'F': - ao_flight_ground_accel = a; - if (ao_config.accel_plus_g == 0) { - ao_config.accel_plus_g = a; - ao_config.accel_minus_g = a + 530; - } - if (ao_config.main_deploy == 0) - ao_config.main_deploy = 250; - ao_flight_started = 1; - break; - case 'S': - break; - case 'A': - ao_adc_static.tick = tick; - ao_adc_static.accel = a; - ao_adc_static.pres_real = b; - if (b < AO_MIN_BARO_VALUE) - b = AO_MIN_BARO_VALUE; - ao_adc_static.pres = b; - ao_records_read++; - ao_insert(); - return; - case 'T': - ao_adc_static.tick = tick; - ao_adc_static.temp = a; - ao_adc_static.v_batt = b; - break; - case 'D': - case 'G': - case 'N': - case 'W': - case 'H': - break; - } - } - - } -} -#define COUNTS_PER_G 264.8 - -void -ao_dump_state(void) -{ -} - -static const struct option options[] = { - { .name = "summary", .has_arg = 0, .val = 's' }, - { .name = "debug", .has_arg = 0, .val = 'd' }, - { 0, 0, 0, 0}, -}; - -void run_flight_fixed(char *name, FILE *f, int summary) -{ - emulator_name = name; - emulator_in = f; - ao_summary = summary; - ao_flight_init(); - ao_flight(); -} - -int -main (int argc, char **argv) -{ - int summary = 0; - int c; - int i; - -#if HAS_ACCEL - emulator_app="full"; -#else - emulator_app="baro"; -#endif - while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) { - switch (c) { - case 's': - summary = 1; - break; - case 'd': - ao_flight_debug = 1; - break; - } - } - - if (optind == argc) - run_flight_fixed("", stdin, summary); - 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); - fclose(f); - } -} diff --git a/src/ao_gps_print.c b/src/ao_gps_print.c deleted file mode 100644 index fcdedd30..00000000 --- a/src/ao_gps_print.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef AO_GPS_TEST -#include "ao.h" -#endif -#include "ao_telem.h" - -void -ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant -{ - char state; - - if (gps_data->flags & AO_GPS_VALID) - state = AO_TELEM_GPS_STATE_LOCKED; - else if (gps_data->flags & AO_GPS_RUNNING) - state = AO_TELEM_GPS_STATE_UNLOCKED; - else - state = AO_TELEM_GPS_STATE_ERROR; - printf(AO_TELEM_GPS_STATE " %c " - AO_TELEM_GPS_NUM_SAT " %d ", - state, - (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT); - if (!(gps_data->flags & AO_GPS_VALID)) - return; - printf(AO_TELEM_GPS_LATITUDE " %ld " - AO_TELEM_GPS_LONGITUDE " %ld " - AO_TELEM_GPS_ALTITUDE " %d ", - gps_data->latitude, - gps_data->longitude, - gps_data->altitude); - - if (gps_data->flags & AO_GPS_DATE_VALID) - printf(AO_TELEM_GPS_YEAR " %d " - AO_TELEM_GPS_MONTH " %d " - AO_TELEM_GPS_DAY " %d ", - gps_data->year, - gps_data->month, - gps_data->day); - - printf(AO_TELEM_GPS_HOUR " %d " - AO_TELEM_GPS_MINUTE " %d " - AO_TELEM_GPS_SECOND " %d ", - gps_data->hour, - gps_data->minute, - gps_data->second); - - printf(AO_TELEM_GPS_HDOP " %d ", - gps_data->hdop * 2); - - if (gps_data->flags & AO_GPS_COURSE_VALID) { - printf(AO_TELEM_GPS_HERROR " %d " - AO_TELEM_GPS_VERROR " %d " - AO_TELEM_GPS_VERTICAL_SPEED " %d " - AO_TELEM_GPS_HORIZONTAL_SPEED " %d " - AO_TELEM_GPS_COURSE " %d ", - gps_data->h_error, - gps_data->v_error, - gps_data->climb_rate, - gps_data->ground_speed, - (int) gps_data->course * 2); - } -} - -void -ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant -{ - uint8_t c, n, v; - __xdata struct ao_gps_sat_orig *sat; - - n = gps_tracking_data->channels; - if (n == 0) - return; - - sat = gps_tracking_data->sats; - v = 0; - for (c = 0; c < n; c++) { - if (sat->svid) - v++; - sat++; - } - - printf (AO_TELEM_SAT_NUM " %d ", - v); - - sat = gps_tracking_data->sats; - v = 0; - for (c = 0; c < n; c++) { - if (sat->svid) { - printf (AO_TELEM_SAT_SVID "%d %d " - AO_TELEM_SAT_C_N_0 "%d %d ", - v, sat->svid, - v, sat->c_n_1); - v++; - } - sat++; - } -} diff --git a/src/ao_gps_report.c b/src/ao_gps_report.c deleted file mode 100644 index e57f8744..00000000 --- a/src/ao_gps_report.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -void -ao_gps_report(void) -{ - static __xdata struct ao_log_record gps_log; - static __xdata struct ao_telemetry_location gps_data; - uint8_t date_reported = 0; - - for (;;) { - ao_sleep(&ao_gps_data); - ao_mutex_get(&ao_gps_mutex); - memcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data)); - ao_mutex_put(&ao_gps_mutex); - - if (!(gps_data.flags & AO_GPS_VALID)) - continue; - - gps_log.tick = ao_gps_tick; - gps_log.type = AO_LOG_GPS_TIME; - gps_log.u.gps_time.hour = gps_data.hour; - gps_log.u.gps_time.minute = gps_data.minute; - gps_log.u.gps_time.second = gps_data.second; - gps_log.u.gps_time.flags = gps_data.flags; - ao_log_data(&gps_log); - gps_log.type = AO_LOG_GPS_LAT; - gps_log.u.gps_latitude = gps_data.latitude; - ao_log_data(&gps_log); - gps_log.type = AO_LOG_GPS_LON; - gps_log.u.gps_longitude = gps_data.longitude; - ao_log_data(&gps_log); - gps_log.type = AO_LOG_GPS_ALT; - gps_log.u.gps_altitude.altitude = gps_data.altitude; - gps_log.u.gps_altitude.unused = 0xffff; - ao_log_data(&gps_log); - if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) { - gps_log.type = AO_LOG_GPS_DATE; - gps_log.u.gps_date.year = gps_data.year; - gps_log.u.gps_date.month = gps_data.month; - gps_log.u.gps_date.day = gps_data.day; - gps_log.u.gps_date.extra = 0; - date_reported = ao_log_data(&gps_log); - } - } -} - -void -ao_gps_tracking_report(void) -{ - static __xdata struct ao_log_record gps_log; - static __xdata struct ao_telemetry_satellite gps_tracking_data; - uint8_t c, n; - - for (;;) { - ao_sleep(&ao_gps_tracking_data); - ao_mutex_get(&ao_gps_mutex); - gps_log.tick = ao_gps_tick; - memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data)); - ao_mutex_put(&ao_gps_mutex); - - if (!(n = gps_tracking_data.channels)) - continue; - - gps_log.type = AO_LOG_GPS_SAT; - for (c = 0; c < n; c++) - if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid)) - { - gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1; - ao_log_data(&gps_log); - } - } -} - -__xdata struct ao_task ao_gps_report_task; -__xdata struct ao_task ao_gps_tracking_report_task; - -void -ao_gps_report_init(void) -{ - ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report"); - ao_add_task(&ao_gps_tracking_report_task, ao_gps_tracking_report, "gps_tracking_report"); -} diff --git a/src/ao_gps_sirf.c b/src/ao_gps_sirf.c deleted file mode 100644 index f2abbf84..00000000 --- a/src/ao_gps_sirf.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef AO_GPS_TEST -#include "ao.h" -#endif - -__xdata uint8_t ao_gps_mutex; -__pdata uint16_t ao_gps_tick; -__xdata struct ao_telemetry_location ao_gps_data; -__xdata struct ao_telemetry_satellite ao_gps_tracking_data; - -static const char ao_gps_set_nmea[] = "\r\n$PSRF100,0,57600,8,1,0*37\r\n"; - -const char ao_gps_config[] = { - - 0xa0, 0xa2, 0x00, 0x0e, /* length: 14 bytes */ - 136, /* mode control */ - 0, 0, /* reserved */ - 0, /* degraded mode (allow 1-SV navigation) */ - 0, 0, /* reserved */ - 0, 0, /* user specified altitude */ - 2, /* alt hold mode (disabled, require 3d fixes) */ - 0, /* alt hold source (use last computed altitude) */ - 0, /* reserved */ - 10, /* Degraded time out (10 sec) */ - 10, /* Dead Reckoning time out (10 sec) */ - 0, /* Track smoothing (disabled) */ - 0x00, 0x8e, 0xb0, 0xb3, - - 0xa0, 0xa2, 0x00, 0x08, /* length: 8 bytes */ - 166, /* Set message rate */ - 2, /* enable/disable all messages */ - 0, /* message id (ignored) */ - 0, /* update rate (0 = disable) */ - 0, 0, 0, 0, /* reserved */ - 0x00, 0xa8, 0xb0, 0xb3, - - 0xa0, 0xa2, 0x00, 0x02, /* length: 2 bytes */ - 143, /* static navigation */ - 0, /* disable */ - 0x00, 0x8f, 0xb0, 0xb3, -}; - -#define NAV_TYPE_GPS_FIX_TYPE_MASK (7 << 0) -#define NAV_TYPE_NO_FIX (0 << 0) -#define NAV_TYPE_SV_KF (1 << 0) -#define NAV_TYPE_2_SV_KF (2 << 0) -#define NAV_TYPE_3_SV_KF (3 << 0) -#define NAV_TYPE_4_SV_KF (4 << 0) -#define NAV_TYPE_2D_LEAST_SQUARES (5 << 0) -#define NAV_TYPE_3D_LEAST_SQUARES (6 << 0) -#define NAV_TYPE_DR (7 << 0) -#define NAV_TYPE_TRICKLE_POWER (1 << 3) -#define NAV_TYPE_ALTITUDE_HOLD_MASK (3 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_NONE (0 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_KF (1 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_USER (2 << 4) -#define NAV_TYPE_ALTITUDE_HOLD_ALWAYS (3 << 4) -#define NAV_TYPE_DOP_LIMIT_EXCEEDED (1 << 6) -#define NAV_TYPE_DGPS_APPLIED (1 << 7) -#define NAV_TYPE_SENSOR_DR (1 << 8) -#define NAV_TYPE_OVERDETERMINED (1 << 9) -#define NAV_TYPE_DR_TIMEOUT_EXCEEDED (1 << 10) -#define NAV_TYPE_FIX_MI_EDIT (1 << 11) -#define NAV_TYPE_INVALID_VELOCITY (1 << 12) -#define NAV_TYPE_ALTITUDE_HOLD_DISABLED (1 << 13) -#define NAV_TYPE_DR_ERROR_STATUS_MASK (3 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_GPS_ONLY (0 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_DR_FROM_GPS (1 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_DR_SENSOR_ERROR (2 << 14) -#define NAV_TYPE_DR_ERROR_STATUS_DR_IN_TEST (3 << 14) - -struct sirf_geodetic_nav_data { - uint16_t nav_type; - uint16_t utc_year; - uint8_t utc_month; - uint8_t utc_day; - uint8_t utc_hour; - uint8_t utc_minute; - uint16_t utc_second; - int32_t lat; - int32_t lon; - int32_t alt_msl; - uint16_t ground_speed; - uint16_t course; - int16_t climb_rate; - uint32_t h_error; - uint32_t v_error; - uint8_t num_sv; - uint8_t hdop; -}; - -static __xdata struct sirf_geodetic_nav_data ao_sirf_data; - -struct sirf_measured_sat_data { - uint8_t svid; - uint8_t c_n_1; -}; - -struct sirf_measured_tracker_data { - int16_t gps_week; - uint32_t gps_tow; - uint8_t channels; - struct sirf_measured_sat_data sats[12]; -}; - -static __xdata struct sirf_measured_tracker_data ao_sirf_tracker_data; - -static __pdata uint16_t ao_sirf_cksum; -static __pdata uint16_t ao_sirf_len; - -#define ao_sirf_byte() ((uint8_t) ao_serial_getchar()) - -static uint8_t data_byte(void) -{ - uint8_t c = ao_sirf_byte(); - --ao_sirf_len; - ao_sirf_cksum += c; - return c; -} - -static char __xdata *sirf_target; - -static void sirf_u16(uint8_t offset) -{ - uint16_t __xdata *ptr = (uint16_t __xdata *) (sirf_target + offset); - uint16_t val; - - val = data_byte() << 8; - val |= data_byte (); - *ptr = val; -} - -static void sirf_u8(uint8_t offset) -{ - uint8_t __xdata *ptr = (uint8_t __xdata *) (sirf_target + offset); - uint8_t val; - - val = data_byte (); - *ptr = val; -} - -static void sirf_u32(uint8_t offset) __reentrant -{ - uint32_t __xdata *ptr = (uint32_t __xdata *) (sirf_target + offset); - uint32_t val; - - val = ((uint32_t) data_byte ()) << 24; - val |= ((uint32_t) data_byte ()) << 16; - val |= ((uint32_t) data_byte ()) << 8; - val |= ((uint32_t) data_byte ()); - *ptr = val; -} - -static void sirf_discard(uint8_t len) -{ - while (len--) - data_byte(); -} - -#define SIRF_END 0 -#define SIRF_DISCARD 1 -#define SIRF_U8 2 -#define SIRF_U16 3 -#define SIRF_U32 4 -#define SIRF_U8X10 5 - -struct sirf_packet_parse { - uint8_t type; - uint8_t offset; -}; - -static void -ao_sirf_parse(void __xdata *target, const struct sirf_packet_parse *parse) __reentrant -{ - uint8_t i, offset, j; - - sirf_target = target; - for (i = 0; ; i++) { - offset = parse[i].offset; - switch (parse[i].type) { - case SIRF_END: - return; - case SIRF_DISCARD: - sirf_discard(offset); - break; - case SIRF_U8: - sirf_u8(offset); - break; - case SIRF_U16: - sirf_u16(offset); - break; - case SIRF_U32: - sirf_u32(offset); - break; - case SIRF_U8X10: - for (j = 10; j--;) - sirf_u8(offset++); - break; - } - } -} - -static const struct sirf_packet_parse geodetic_nav_data_packet[] = { - { SIRF_DISCARD, 2 }, /* 1 nav valid */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, nav_type) }, /* 3 */ - { SIRF_DISCARD, 6 }, /* 5 week number, time of week */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_year) }, /* 11 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_month) }, /* 13 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_day) }, /* 14 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_hour) }, /* 15 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_minute) }, /* 16 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_second) }, /* 17 */ - { SIRF_DISCARD, 4 }, /* satellite id list */ /* 19 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lat) }, /* 23 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lon) }, /* 27 */ - { SIRF_DISCARD, 4 }, /* altitude from ellipsoid */ /* 31 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, alt_msl) }, /* 35 */ - { SIRF_DISCARD, 1 }, /* map datum */ /* 39 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, ground_speed) }, /* 40 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, course) }, /* 42 */ - { SIRF_DISCARD, 2 }, /* magnetic variation */ /* 44 */ - { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, climb_rate) }, /* 46 */ - { SIRF_DISCARD, 2 }, /* turn rate */ /* 48 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, h_error) }, /* 50 */ - { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, v_error) }, /* 54 */ - { SIRF_DISCARD, 30 }, /* time error, h_vel error, clock_bias, - clock bias error, clock drift, - clock drift error, distance, - distance error, heading error */ /* 58 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, num_sv) }, /* 88 */ - { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, hdop) }, /* 89 */ - { SIRF_DISCARD, 1 }, /* additional mode info */ /* 90 */ - { SIRF_END, 0 }, /* 91 */ -}; - -static void -ao_sirf_parse_41(void) __reentrant -{ - ao_sirf_parse(&ao_sirf_data, geodetic_nav_data_packet); -} - -static const struct sirf_packet_parse measured_tracker_data_packet[] = { - { SIRF_U16, offsetof (struct sirf_measured_tracker_data, gps_week) }, /* 1 week */ - { SIRF_U32, offsetof (struct sirf_measured_tracker_data, gps_tow) }, /* 3 time of week */ - { SIRF_U8, offsetof (struct sirf_measured_tracker_data, channels) }, /* 7 channels */ - { SIRF_END, 0 }, -}; - -static const struct sirf_packet_parse measured_sat_data_packet[] = { - { SIRF_U8, offsetof (struct sirf_measured_sat_data, svid) }, /* 0 SV id */ - { SIRF_DISCARD, 4 }, /* 1 azimuth, 2 elevation, 3 state */ - { SIRF_U8, offsetof (struct sirf_measured_sat_data, c_n_1) }, /* C/N0 1 */ - { SIRF_DISCARD, 9 }, /* C/N0 2-10 */ - { SIRF_END, 0 }, -}; - -static void -ao_sirf_parse_4(void) __reentrant -{ - uint8_t i; - ao_sirf_parse(&ao_sirf_tracker_data, measured_tracker_data_packet); - for (i = 0; i < 12; i++) - ao_sirf_parse(&ao_sirf_tracker_data.sats[i], measured_sat_data_packet); -} - -static void -ao_gps_setup(void) __reentrant -{ - uint8_t i, k; - ao_serial_set_speed(AO_SERIAL_SPEED_4800); - for (i = 0; i < 64; i++) - ao_serial_putchar(0x00); - for (k = 0; k < 3; k++) - for (i = 0; i < sizeof (ao_gps_set_nmea); i++) - ao_serial_putchar(ao_gps_set_nmea[i]); - ao_serial_set_speed(AO_SERIAL_SPEED_57600); - for (i = 0; i < 64; i++) - ao_serial_putchar(0x00); -} - -static const char ao_gps_set_message_rate[] = { - 0xa0, 0xa2, 0x00, 0x08, - 166, - 0, -}; - -void -ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant -{ - uint16_t cksum = 0x00a6; - uint8_t i; - - for (i = 0; i < sizeof (ao_gps_set_message_rate); i++) - ao_serial_putchar(ao_gps_set_message_rate[i]); - ao_serial_putchar(msg); - ao_serial_putchar(rate); - cksum = 0xa6 + msg + rate; - for (i = 0; i < 4; i++) - ao_serial_putchar(0); - ao_serial_putchar((cksum >> 8) & 0x7f); - ao_serial_putchar(cksum & 0xff); - ao_serial_putchar(0xb0); - ao_serial_putchar(0xb3); -} - -static const uint8_t sirf_disable[] = { - 2, - 9, - 10, - 27, - 50, - 52, -}; - -void -ao_gps(void) __reentrant -{ - uint8_t i, k; - uint16_t cksum; - - ao_gps_setup(); - for (k = 0; k < 5; k++) - { - for (i = 0; i < sizeof (ao_gps_config); i++) - ao_serial_putchar(ao_gps_config[i]); - for (i = 0; i < sizeof (sirf_disable); i++) - ao_sirf_set_message_rate(sirf_disable[i], 0); - ao_sirf_set_message_rate(41, 1); - ao_sirf_set_message_rate(4, 1); - } - for (;;) { - /* Locate the begining of the next record */ - while (ao_sirf_byte() != (uint8_t) 0xa0) - ; - if (ao_sirf_byte() != (uint8_t) 0xa2) - continue; - - /* Length */ - ao_sirf_len = ao_sirf_byte() << 8; - ao_sirf_len |= ao_sirf_byte(); - if (ao_sirf_len > 1023) - continue; - - ao_sirf_cksum = 0; - - /* message ID */ - i = data_byte (); /* 0 */ - - switch (i) { - case 41: - if (ao_sirf_len < 90) - break; - ao_sirf_parse_41(); - break; - case 4: - if (ao_sirf_len < 187) - break; - ao_sirf_parse_4(); - break; - } - if (ao_sirf_len != 0) - continue; - - /* verify checksum and end sequence */ - ao_sirf_cksum &= 0x7fff; - cksum = ao_sirf_byte() << 8; - cksum |= ao_sirf_byte(); - if (ao_sirf_cksum != cksum) - continue; - if (ao_sirf_byte() != (uint8_t) 0xb0) - continue; - if (ao_sirf_byte() != (uint8_t) 0xb3) - continue; - - switch (i) { - case 41: - ao_mutex_get(&ao_gps_mutex); - ao_gps_tick = ao_time(); - ao_gps_data.hour = ao_sirf_data.utc_hour; - ao_gps_data.minute = ao_sirf_data.utc_minute; - ao_gps_data.second = ao_sirf_data.utc_second / 1000; - ao_gps_data.flags = ((ao_sirf_data.num_sv << AO_GPS_NUM_SAT_SHIFT) & AO_GPS_NUM_SAT_MASK) | AO_GPS_RUNNING; - if ((ao_sirf_data.nav_type & NAV_TYPE_GPS_FIX_TYPE_MASK) >= NAV_TYPE_4_SV_KF) - ao_gps_data.flags |= AO_GPS_VALID; - ao_gps_data.latitude = ao_sirf_data.lat; - ao_gps_data.longitude = ao_sirf_data.lon; - ao_gps_data.altitude = ao_sirf_data.alt_msl / 100; - ao_gps_data.ground_speed = ao_sirf_data.ground_speed; - ao_gps_data.course = ao_sirf_data.course / 200; - ao_gps_data.hdop = ao_sirf_data.hdop; - ao_gps_data.climb_rate = ao_sirf_data.climb_rate; - ao_gps_data.flags |= AO_GPS_COURSE_VALID; -#if 0 - if (ao_sirf_data.h_error > 6553500) - ao_gps_data.h_error = 65535; - else - ao_gps_data.h_error = ao_sirf_data.h_error / 100; - if (ao_sirf_data.v_error > 6553500) - ao_gps_data.v_error = 65535; - else - ao_gps_data.v_error = ao_sirf_data.v_error / 100; -#endif - ao_mutex_put(&ao_gps_mutex); - ao_wakeup(&ao_gps_data); - break; - case 4: - ao_mutex_get(&ao_gps_mutex); - ao_gps_tracking_data.channels = ao_sirf_tracker_data.channels; - for (i = 0; i < 12; i++) { - ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid; - ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1; - } - ao_mutex_put(&ao_gps_mutex); - ao_wakeup(&ao_gps_tracking_data); - break; - } - } -} - -__xdata struct ao_task ao_gps_task; - -void -ao_gps_init(void) -{ - ao_add_task(&ao_gps_task, ao_gps, "gps"); -} diff --git a/src/ao_gps_skytraq.c b/src/ao_gps_skytraq.c deleted file mode 100644 index 7ac26946..00000000 --- a/src/ao_gps_skytraq.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef AO_GPS_TEST -#include "ao.h" -#endif - -#define AO_GPS_LEADER 2 - -static __code char ao_gps_header[] = "GP"; - -__xdata uint8_t ao_gps_mutex; -static __data char ao_gps_char; -static __pdata uint8_t ao_gps_cksum; -static __pdata uint8_t ao_gps_error; - -__pdata uint16_t ao_gps_tick; -__xdata struct ao_telemetry_location ao_gps_data; -__xdata struct ao_telemetry_satellite ao_gps_tracking_data; - -static __pdata uint16_t ao_gps_next_tick; -static __xdata struct ao_telemetry_location ao_gps_next; -static __pdata uint8_t ao_gps_date_flags; -static __xdata struct ao_telemetry_satellite ao_gps_tracking_next; - -#define STQ_S 0xa0, 0xa1 -#define STQ_E 0x0d, 0x0a -#define SKYTRAQ_MSG_2(id,a,b) \ - STQ_S, 0, 3, id, a,b, (id^a^b), STQ_E -#define SKYTRAQ_MSG_3(id,a,b,c) \ - STQ_S, 0, 4, id, a,b,c, (id^a^b^c), STQ_E -#define SKYTRAQ_MSG_8(id,a,b,c,d,e,f,g,h) \ - STQ_S, 0, 9, id, a,b,c,d,e,f,g,h, (id^a^b^c^d^e^f^g^h), STQ_E -#define SKYTRAQ_MSG_14(id,a,b,c,d,e,f,g,h,i,j,k,l,m,n) \ - STQ_S, 0,15, id, a,b,c,d,e,f,g,h,i,j,k,l,m,n, \ - (id^a^b^c^d^e^f^g^h^i^j^k^l^m^n), STQ_E - -static __code uint8_t ao_gps_config[] = { - SKYTRAQ_MSG_8(0x08, 1, 1, 1, 1, 1, 1, 1, 0), /* configure nmea */ - /* gga interval */ - /* gsa interval */ - /* gsv interval */ - /* gll interval */ - /* rmc interval */ - /* vtg interval */ - /* zda interval */ - /* attributes (0 = update to sram, 1 = update flash too) */ - - SKYTRAQ_MSG_2(0x3c, 0x00, 0x00), /* configure navigation mode */ - /* 0 = car, 1 = pedestrian */ - /* 0 = update to sram, 1 = update sram + flash */ -}; - -static void -ao_gps_lexchar(void) -{ - if (ao_gps_error) - ao_gps_char = '\n'; - else - ao_gps_char = ao_serial_getchar(); - ao_gps_cksum ^= ao_gps_char; -} - -void -ao_gps_skip_field(void) -{ - while (ao_gps_char != ',' && ao_gps_char != '*' && ao_gps_char != '\n') - ao_gps_lexchar(); -} - -void -ao_gps_skip_sep(void) -{ - if (ao_gps_char == ',' || ao_gps_char == '.' || ao_gps_char == '*') - ao_gps_lexchar(); -} - -__pdata static uint8_t ao_gps_num_width; - -static int16_t -ao_gps_decimal(uint8_t max_width) -{ - int16_t v; - __pdata uint8_t neg = 0; - - ao_gps_skip_sep(); - if (ao_gps_char == '-') { - neg = 1; - ao_gps_lexchar(); - } - v = 0; - ao_gps_num_width = 0; - while (ao_gps_num_width < max_width) { - if (ao_gps_char < '0' || '9' < ao_gps_char) - break; - v = v * (int16_t) 10 + ao_gps_char - '0'; - ao_gps_num_width++; - ao_gps_lexchar(); - } - if (neg) - v = -v; - return v; -} - -static uint8_t -ao_gps_hex(uint8_t max_width) -{ - uint8_t v, d; - - ao_gps_skip_sep(); - v = 0; - ao_gps_num_width = 0; - while (ao_gps_num_width < max_width) { - if ('0' <= ao_gps_char && ao_gps_char <= '9') - d = ao_gps_char - '0'; - else if ('A' <= ao_gps_char && ao_gps_char <= 'F') - d = ao_gps_char - 'A' + 10; - else if ('a' <= ao_gps_char && ao_gps_char <= 'f') - d = ao_gps_char - 'a' + 10; - else - break; - v = (v << 4) | d; - ao_gps_num_width++; - ao_gps_lexchar(); - } - return v; -} - -static int32_t -ao_gps_parse_pos(uint8_t deg_width) __reentrant -{ - int32_t d; - int32_t m; - int32_t f; - - d = ao_gps_decimal(deg_width); - m = ao_gps_decimal(2); - if (ao_gps_char == '.') { - f = ao_gps_decimal(4); - while (ao_gps_num_width < 4) { - f *= 10; - ao_gps_num_width++; - } - } else { - f = 0; - if (ao_gps_char != ',') - ao_gps_error = 1; - } - d = d * 10000000l; - m = m * 10000l + f; - d = d + m * 50 / 3; - return d; -} - -static uint8_t -ao_gps_parse_flag(char no_c, char yes_c) __reentrant -{ - uint8_t ret = 0; - ao_gps_skip_sep(); - if (ao_gps_char == yes_c) - ret = 1; - else if (ao_gps_char == no_c) - ret = 0; - else - ao_gps_error = 1; - ao_gps_lexchar(); - return ret; -} - -static void -ao_nmea_gga() -{ - uint8_t i; - - /* Now read the data into the gps data record - * - * $GPGGA,025149.000,4528.1723,N,12244.2480,W,1,05,2.0,103.5,M,-19.5,M,,0000*66 - * - * Essential fix data - * - * 025149.000 time (02:51:49.000 GMT) - * 4528.1723,N Latitude 45°28.1723' N - * 12244.2480,W Longitude 122°44.2480' W - * 1 Fix quality: - * 0 = invalid - * 1 = GPS fix (SPS) - * 2 = DGPS fix - * 3 = PPS fix - * 4 = Real Time Kinematic - * 5 = Float RTK - * 6 = estimated (dead reckoning) - * 7 = Manual input mode - * 8 = Simulation mode - * 05 Number of satellites (5) - * 2.0 Horizontal dilution - * 103.5,M Altitude, 103.5M above msl - * -19.5,M Height of geoid above WGS84 ellipsoid - * ? time in seconds since last DGPS update - * 0000 DGPS station ID - * *66 checksum - */ - - ao_gps_next_tick = ao_time(); - ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags; - ao_gps_next.hour = ao_gps_decimal(2); - ao_gps_next.minute = ao_gps_decimal(2); - ao_gps_next.second = ao_gps_decimal(2); - ao_gps_skip_field(); /* skip seconds fraction */ - - ao_gps_next.latitude = ao_gps_parse_pos(2); - if (ao_gps_parse_flag('N', 'S')) - ao_gps_next.latitude = -ao_gps_next.latitude; - ao_gps_next.longitude = ao_gps_parse_pos(3); - if (ao_gps_parse_flag('E', 'W')) - ao_gps_next.longitude = -ao_gps_next.longitude; - - i = ao_gps_decimal(0xff); - if (i == 1) - ao_gps_next.flags |= AO_GPS_VALID; - - i = ao_gps_decimal(0xff) << AO_GPS_NUM_SAT_SHIFT; - if (i > AO_GPS_NUM_SAT_MASK) - i = AO_GPS_NUM_SAT_MASK; - ao_gps_next.flags |= i; - - ao_gps_lexchar(); - i = ao_gps_decimal(0xff); - if (i <= 50) { - i = (uint8_t) 5 * i; - if (ao_gps_char == '.') - i = (i + ((uint8_t) ao_gps_decimal(1) >> 1)); - } else - i = 255; - ao_gps_next.hdop = i; - ao_gps_skip_field(); - - ao_gps_next.altitude = ao_gps_decimal(0xff); - ao_gps_skip_field(); /* skip any fractional portion */ - - /* Skip remaining fields */ - while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { - ao_gps_lexchar(); - ao_gps_skip_field(); - } - if (ao_gps_char == '*') { - uint8_t cksum = ao_gps_cksum ^ '*'; - if (cksum != ao_gps_hex(2)) - ao_gps_error = 1; - } else - ao_gps_error = 1; - if (!ao_gps_error) { - ao_mutex_get(&ao_gps_mutex); - ao_gps_tick = ao_gps_next_tick; - memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data)); - ao_mutex_put(&ao_gps_mutex); - ao_wakeup(&ao_gps_data); - } -} - -static void -ao_nmea_gsv(void) -{ - char c; - uint8_t i; - uint8_t done; - /* Now read the data into the GPS tracking data record - * - * $GPGSV,3,1,12,05,54,069,45,12,44,061,44,21,07,184,46,22,78,289,47*72 - * - * Satellites in view data - * - * 3 Total number of GSV messages - * 1 Sequence number of current GSV message - * 12 Total sats in view (0-12) - * 05 SVID - * 54 Elevation - * 069 Azimuth - * 45 C/N0 in dB - * ... other SVIDs - * 72 checksum - */ - c = ao_gps_decimal(1); /* total messages */ - i = ao_gps_decimal(1); /* message sequence */ - if (i == 1) { - ao_gps_tracking_next.channels = 0; - } - done = (uint8_t) c == i; - ao_gps_lexchar(); - ao_gps_skip_field(); /* sats in view */ - while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { - i = ao_gps_tracking_next.channels; - c = ao_gps_decimal(2); /* SVID */ - if (i < AO_MAX_GPS_TRACKING) - ao_gps_tracking_next.sats[i].svid = c; - ao_gps_lexchar(); - ao_gps_skip_field(); /* elevation */ - ao_gps_lexchar(); - ao_gps_skip_field(); /* azimuth */ - c = ao_gps_decimal(2); /* C/N0 */ - if (i < AO_MAX_GPS_TRACKING) { - if ((ao_gps_tracking_next.sats[i].c_n_1 = c) != 0) - ao_gps_tracking_next.channels = i + 1; - } - } - if (ao_gps_char == '*') { - uint8_t cksum = ao_gps_cksum ^ '*'; - if (cksum != ao_gps_hex(2)) - ao_gps_error = 1; - } - else - ao_gps_error = 1; - if (ao_gps_error) - ao_gps_tracking_next.channels = 0; - else if (done) { - ao_mutex_get(&ao_gps_mutex); - memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, - sizeof(ao_gps_tracking_data)); - ao_mutex_put(&ao_gps_mutex); - ao_wakeup(&ao_gps_tracking_data); - } -} - -static void -ao_nmea_rmc(void) -{ - char a, c; - uint8_t i; - /* Parse the RMC record to read out the current date */ - - /* $GPRMC,111636.932,A,2447.0949,N,12100.5223,E,000.0,000.0,030407,,,A*61 - * - * Recommended Minimum Specific GNSS Data - * - * 111636.932 UTC time 11:16:36.932 - * A Data Valid (V = receiver warning) - * 2447.0949 Latitude - * N North/south indicator - * 12100.5223 Longitude - * E East/west indicator - * 000.0 Speed over ground - * 000.0 Course over ground - * 030407 UTC date (ddmmyy format) - * A Mode indicator: - * N = data not valid - * A = autonomous mode - * D = differential mode - * E = estimated (dead reckoning) mode - * M = manual input mode - * S = simulator mode - * 61 checksum - */ - ao_gps_skip_field(); - for (i = 0; i < 8; i++) { - ao_gps_lexchar(); - ao_gps_skip_field(); - } - a = ao_gps_decimal(2); - c = ao_gps_decimal(2); - i = ao_gps_decimal(2); - /* Skip remaining fields */ - while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { - ao_gps_lexchar(); - ao_gps_skip_field(); - } - if (ao_gps_char == '*') { - uint8_t cksum = ao_gps_cksum ^ '*'; - if (cksum != ao_gps_hex(2)) - ao_gps_error = 1; - } else - ao_gps_error = 1; - if (!ao_gps_error) { - ao_gps_next.year = i; - ao_gps_next.month = c; - ao_gps_next.day = a; - ao_gps_date_flags = AO_GPS_DATE_VALID; - } -} - -#define ao_skytraq_sendstruct(s) ao_skytraq_sendbytes((s), sizeof(s)) - -static void -ao_skytraq_sendbytes(__code uint8_t *b, uint8_t l) -{ - while (l--) { - uint8_t c = *b++; - if (c == 0xa0) - ao_delay(AO_MS_TO_TICKS(500)); - ao_serial_putchar(c); - } -} - -static void -ao_gps_nmea_parse(void) -{ - uint8_t a, b, c; - - ao_gps_cksum = 0; - ao_gps_error = 0; - - for (a = 0; a < AO_GPS_LEADER; a++) { - ao_gps_lexchar(); - if (ao_gps_char != ao_gps_header[a]) - return; - } - - ao_gps_lexchar(); - a = ao_gps_char; - ao_gps_lexchar(); - b = ao_gps_char; - ao_gps_lexchar(); - c = ao_gps_char; - ao_gps_lexchar(); - - if (ao_gps_char != ',') - return; - - if (a == (uint8_t) 'G' && b == (uint8_t) 'G' && c == (uint8_t) 'A') { - ao_nmea_gga(); - } else if (a == (uint8_t) 'G' && b == (uint8_t) 'S' && c == (uint8_t) 'V') { - ao_nmea_gsv(); - } else if (a == (uint8_t) 'R' && b == (uint8_t) 'M' && c == (uint8_t) 'C') { - ao_nmea_rmc(); - } -} - -void -ao_gps(void) __reentrant -{ - ao_serial_set_speed(AO_SERIAL_SPEED_9600); - - /* give skytraq time to boot in case of cold start */ - ao_delay(AO_MS_TO_TICKS(2000)); - - ao_skytraq_sendstruct(ao_gps_config); - - for (;;) { - /* Locate the begining of the next record */ - if (ao_serial_getchar() == '$') { - ao_gps_nmea_parse(); - } - - } -} - -__xdata struct ao_task ao_gps_task; - -static void -gps_dump(void) __reentrant -{ - uint8_t i; - ao_mutex_get(&ao_gps_mutex); - printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day); - printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second); - printf ("Lat/Lon: %ld %ld\n", ao_gps_data.latitude, ao_gps_data.longitude); - printf ("Alt: %d\n", ao_gps_data.altitude); - printf ("Flags: 0x%x\n", ao_gps_data.flags); - printf ("Sats: %d", ao_gps_tracking_data.channels); - for (i = 0; i < ao_gps_tracking_data.channels; i++) - printf (" %d %d", - ao_gps_tracking_data.sats[i].svid, - ao_gps_tracking_data.sats[i].c_n_1); - printf ("\ndone\n"); - ao_mutex_put(&ao_gps_mutex); -} - -__code struct ao_cmds ao_gps_cmds[] = { - { gps_dump, "g\0Display GPS" }, - { 0, NULL }, -}; - -void -ao_gps_init(void) -{ - ao_add_task(&ao_gps_task, ao_gps, "gps"); - ao_cmd_register(&ao_gps_cmds[0]); -} diff --git a/src/ao_gps_test.c b/src/ao_gps_test.c deleted file mode 100644 index 93d7a9ab..00000000 --- a/src/ao_gps_test.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 -#include -#include -#include -#include -#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_gps_orig { - 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 hdop; /* * 5 */ - int16_t climb_rate; /* cm/s */ - uint16_t h_error; /* m */ - uint16_t v_error; /* m */ -}; - -#define SIRF_SAT_STATE_ACQUIRED (1 << 0) -#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1) -#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2) -#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3) -#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4) -#define SIRF_SAT_CODE_LOCKED (1 << 5) -#define SIRF_SAT_ACQUISITION_FAILED (1 << 6) -#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7) - -struct ao_gps_sat_orig { - uint8_t svid; - uint8_t c_n_1; -}; - -#define AO_MAX_GPS_TRACKING 12 - -struct ao_gps_tracking_orig { - uint8_t channels; - struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; -}; - -#define ao_telemetry_location ao_gps_orig -#define ao_telemetry_satellite ao_gps_tracking_orig -#define ao_telemetry_satellite_info ao_gps_sat_orig - -void -ao_mutex_get(uint8_t *mutex) -{ -} - -void -ao_mutex_put(uint8_t *mutex) -{ -} - -static int -ao_gps_fd; - -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)); -} - -#define QUEUE_LEN 4096 - -static char input_queue[QUEUE_LEN]; -int input_head, input_tail; - -#include - -int -get_millis(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -static void -check_sirf_message(char *from, uint8_t *msg, int len) -{ - uint16_t encoded_len, encoded_cksum; - uint16_t cksum; - uint8_t id; - int i; - - if (msg[0] != 0xa0 || msg[1] != 0xa2) { - printf ("bad header\n"); - return; - } - if (len < 7) { - printf("short\n"); - return; - } - if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { - printf ("bad trailer\n"); - return; - } - encoded_len = (msg[2] << 8) | msg[3]; - id = msg[4]; -/* printf ("%9d: %3d\n", get_millis(), id); */ - if (encoded_len != len - 8) { - if (id != 52) - printf ("length mismatch (got %d, wanted %d)\n", - len - 8, encoded_len); - return; - } - encoded_cksum = (msg[len - 4] << 8) | msg[len-3]; - cksum = 0; - for (i = 4; i < len - 4; i++) - cksum = (cksum + msg[i]) & 0x7fff; - if (encoded_cksum != cksum) { - printf ("cksum mismatch (got %04x wanted %04x)\n", - cksum, encoded_cksum); - return; - } - id = msg[4]; - switch (id) { - case 41:{ - int off = 4; - - uint8_t id; - uint16_t nav_valid; - uint16_t nav_type; - uint16_t week; - uint32_t tow; - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint16_t second; - uint32_t sat_list; - int32_t lat; - int32_t lon; - int32_t alt_ell; - int32_t alt_msl; - int8_t datum; - uint16_t sog; - uint16_t cog; - int16_t mag_var; - int16_t climb_rate; - int16_t heading_rate; - uint32_t h_error; - uint32_t v_error; - uint32_t t_error; - uint16_t h_v_error; - -#define get_u8(u) u = (msg[off]); off+= 1 -#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 -#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 - - get_u8(id); - get_u16(nav_valid); - get_u16(nav_type); - get_u16(week); - get_u32(tow); - get_u16(year); - get_u8(month); - get_u8(day); - get_u8(hour); - get_u8(minute); - get_u16(second); - get_u32(sat_list); - get_u32(lat); - get_u32(lon); - get_u32(alt_ell); - get_u32(alt_msl); - get_u8(datum); - get_u16(sog); - get_u16(cog); - get_u16(mag_var); - get_u16(climb_rate); - get_u16(heading_rate); - get_u32(h_error); - get_u32(v_error); - get_u32(t_error); - get_u16(h_v_error); - - - printf ("Geodetic Navigation Data (41):\n"); - printf ("\tNav valid %04x\n", nav_valid); - printf ("\tNav type %04x\n", nav_type); - printf ("\tWeek %5d", week); - printf (" TOW %9d", tow); - printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n", - year, month, day, - hour, minute, second / 1000.0); - printf ("\tsats: %08x\n", sat_list); - printf ("\tlat: %g", lat / 1.0e7); - printf (" lon: %g", lon / 1.0e7); - printf (" alt_ell: %g", alt_ell / 100.0); - printf (" alt_msll: %g", alt_msl / 100.0); - printf (" datum: %d\n", datum); - printf ("\tground speed: %g", sog / 100.0); - printf (" course: %g", cog / 100.0); - printf (" climb: %g", climb_rate / 100.0); - printf (" heading rate: %g\n", heading_rate / 100.0); - printf ("\th error: %g", h_error / 100.0); - printf (" v error: %g", v_error / 100.0); - printf (" t error: %g", t_error / 100.0); - printf (" h vel error: %g\n", h_v_error / 100.0); - break; - } - case 4: { - int off = 4; - uint8_t id; - int16_t gps_week; - uint32_t gps_tow; - uint8_t channels; - int j, k; - - get_u8(id); - get_u16(gps_week); - get_u32(gps_tow); - get_u8(channels); - - printf ("Measured Tracker Data (4):\n"); - printf ("GPS week: %d\n", gps_week); - printf ("GPS time of week: %d\n", gps_tow); - printf ("channels: %d\n", channels); - for (j = 0; j < 12; j++) { - uint8_t svid, azimuth, elevation; - uint16_t state; - uint8_t c_n[10]; - get_u8(svid); - get_u8(azimuth); - get_u8(elevation); - get_u16(state); - for (k = 0; k < 10; k++) { - get_u8(c_n[k]); - } - printf ("Sat %3d:", svid); - printf (" aziumuth: %6.1f", azimuth * 1.5); - printf (" elevation: %6.1f", elevation * 0.5); - printf (" state: 0x%02x", state); - printf (" c_n:"); - for (k = 0; k < 10; k++) - printf(" %3d", c_n[k]); - if (state & SIRF_SAT_STATE_ACQUIRED) - printf(" acq,"); - if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID) - printf(" car,"); - if (state & SIRF_SAT_BIT_SYNC_COMPLETE) - printf(" bit,"); - if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE) - printf(" sub,"); - if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE) - printf(" pullin,"); - if (state & SIRF_SAT_CODE_LOCKED) - printf(" code,"); - if (state & SIRF_SAT_ACQUISITION_FAILED) - printf(" fail,"); - if (state & SIRF_SAT_EPHEMERIS_AVAILABLE) - printf(" ephem,"); - printf ("\n"); - } - break; - } - default: - return; - printf ("%s %4d:", from, encoded_len); - for (i = 4; i < len - 4; i++) { - if (((i - 4) & 0xf) == 0) - printf("\n "); - printf (" %3d", msg[i]); - } - printf ("\n"); - } -} - -static uint8_t sirf_message[4096]; -static int sirf_message_len; -static uint8_t sirf_in_message[4096]; -static int sirf_in_len; - -char -ao_serial_getchar(void) -{ - char c; - uint8_t uc; - - while (input_head == input_tail) { - for (;;) { - input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); - if (input_tail < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - perror ("getchar"); - exit (1); - } - input_head = 0; - break; - } - } - c = input_queue[input_head]; - input_head = (input_head + 1) % QUEUE_LEN; - uc = c; - if (sirf_in_len || uc == 0xa0) { - if (sirf_in_len < 4096) - sirf_in_message[sirf_in_len++] = uc; - if (uc == 0xb3) { - check_sirf_message("recv", sirf_in_message, sirf_in_len); - sirf_in_len = 0; - } - } - return c; -} - - -void -ao_serial_putchar(char c) -{ - int i; - uint8_t uc = (uint8_t) c; - - if (sirf_message_len || uc == 0xa0) { - if (sirf_message_len < 4096) - sirf_message[sirf_message_len++] = uc; - if (uc == 0xb3) { - check_sirf_message("send", sirf_message, sirf_message_len); - sirf_message_len = 0; - } - } - for (;;) { - i = write(ao_gps_fd, &c, 1); - if (i == 1) { - if ((uint8_t) c == 0xb3 || c == '\r') { - static const struct timespec delay = { - .tv_sec = 0, - .tv_nsec = 100 * 1000 * 1000 - }; - tcdrain(ao_gps_fd); -// nanosleep(&delay, NULL); - } - break; - } - if (i < 0 && (errno == EINTR || errno == EAGAIN)) - continue; - perror("putchar"); - exit(1); - } -} - -#define AO_SERIAL_SPEED_4800 0 -#define AO_SERIAL_SPEED_57600 1 - -static void -ao_serial_set_speed(uint8_t speed) -{ - int fd = ao_gps_fd; - struct termios termios; - - tcdrain(fd); - tcgetattr(fd, &termios); - switch (speed) { - case AO_SERIAL_SPEED_4800: - cfsetspeed(&termios, B4800); - break; - case AO_SERIAL_SPEED_57600: - cfsetspeed(&termios, B57600); - break; - } - tcsetattr(fd, TCSAFLUSH, &termios); - tcflush(fd, TCIFLUSH); -} - -#define ao_time() 0 - -#include "ao_gps_print.c" -#include "ao_gps_sirf.c" - -void -ao_dump_state(void *wchan) -{ - double lat, lon; - int i; - if (wchan == &ao_gps_data) - ao_gps_print(&ao_gps_data); - else - ao_gps_tracking_print(&ao_gps_tracking_data); - putchar('\n'); - return; - printf ("%02d:%02d:%02d", - ao_gps_data.hour, ao_gps_data.minute, - ao_gps_data.second); - printf (" nsat %d %svalid", - ao_gps_data.flags & AO_GPS_NUM_SAT_MASK, - ao_gps_data.flags & AO_GPS_VALID ? "" : "not "); - printf (" lat %g lon %g alt %d", - ao_gps_data.latitude / 1.0e7, - ao_gps_data.longitude / 1.0e7, - ao_gps_data.altitude); - printf (" speed %g climb %g course %d", - ao_gps_data.ground_speed / 100.0, - ao_gps_data.climb_rate / 100.0, - ao_gps_data.course * 2); - printf (" hdop %g h_error %d v_error %d", - ao_gps_data.hdop / 5.0, - ao_gps_data.h_error, ao_gps_data.v_error); - printf("\n"); - printf ("\t"); - for (i = 0; i < 12; i++) - printf (" %2d(%02d)", - ao_gps_tracking_data.sats[i].svid, - ao_gps_tracking_data.sats[i].c_n_1); - printf ("\n"); -} - -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 - -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 ]\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_setup(); - ao_gps(); -} diff --git a/src/ao_gps_test_skytraq.c b/src/ao_gps_test_skytraq.c deleted file mode 100644 index a78fae0f..00000000 --- a/src/ao_gps_test_skytraq.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 -#include -#include -#include -#include -#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_gps_orig { - 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 hdop; /* * 5 */ - int16_t climb_rate; /* cm/s */ - uint16_t h_error; /* m */ - uint16_t v_error; /* m */ -}; - -#define SIRF_SAT_STATE_ACQUIRED (1 << 0) -#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1) -#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2) -#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3) -#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4) -#define SIRF_SAT_CODE_LOCKED (1 << 5) -#define SIRF_SAT_ACQUISITION_FAILED (1 << 6) -#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7) - -struct ao_gps_sat_orig { - uint8_t svid; - uint8_t c_n_1; -}; - -#define AO_MAX_GPS_TRACKING 12 - -struct ao_gps_tracking_orig { - uint8_t channels; - struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; -}; - -#define ao_telemetry_location ao_gps_orig -#define ao_telemetry_satellite ao_gps_tracking_orig -#define ao_telemetry_satellite_info ao_gps_sat_orig - -void -ao_mutex_get(uint8_t *mutex) -{ -} - -void -ao_mutex_put(uint8_t *mutex) -{ -} - -static int -ao_gps_fd; - -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)); -} - -#define QUEUE_LEN 4096 - -static char input_queue[QUEUE_LEN]; -int input_head, input_tail; - -#include - -int -get_millis(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -static void -check_skytraq_message(char *from, uint8_t *msg, int len) -{ - uint16_t encoded_len, encoded_cksum; - uint16_t cksum; - uint8_t id; - int i; - -// fwrite(msg, 1, len, stdout); - return; - if (msg[0] != 0xa0 || msg[1] != 0xa2) { - printf ("bad header\n"); - return; - } - if (len < 7) { - printf("short\n"); - return; - } - if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { - printf ("bad trailer\n"); - return; - } - encoded_len = (msg[2] << 8) | msg[3]; - id = msg[4]; -/* printf ("%9d: %3d\n", get_millis(), id); */ - if (encoded_len != len - 8) { - if (id != 52) - printf ("length mismatch (got %d, wanted %d)\n", - len - 8, encoded_len); - return; - } - encoded_cksum = (msg[len - 4] << 8) | msg[len-3]; - cksum = 0; - for (i = 4; i < len - 4; i++) - cksum = (cksum + msg[i]) & 0x7fff; - if (encoded_cksum != cksum) { - printf ("cksum mismatch (got %04x wanted %04x)\n", - cksum, encoded_cksum); - return; - } - id = msg[4]; - switch (id) { - case 41:{ - int off = 4; - - uint8_t id; - uint16_t nav_valid; - uint16_t nav_type; - uint16_t week; - uint32_t tow; - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint16_t second; - uint32_t sat_list; - int32_t lat; - int32_t lon; - int32_t alt_ell; - int32_t alt_msl; - int8_t datum; - uint16_t sog; - uint16_t cog; - int16_t mag_var; - int16_t climb_rate; - int16_t heading_rate; - uint32_t h_error; - uint32_t v_error; - uint32_t t_error; - uint16_t h_v_error; - -#define get_u8(u) u = (msg[off]); off+= 1 -#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 -#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 - - get_u8(id); - get_u16(nav_valid); - get_u16(nav_type); - get_u16(week); - get_u32(tow); - get_u16(year); - get_u8(month); - get_u8(day); - get_u8(hour); - get_u8(minute); - get_u16(second); - get_u32(sat_list); - get_u32(lat); - get_u32(lon); - get_u32(alt_ell); - get_u32(alt_msl); - get_u8(datum); - get_u16(sog); - get_u16(cog); - get_u16(mag_var); - get_u16(climb_rate); - get_u16(heading_rate); - get_u32(h_error); - get_u32(v_error); - get_u32(t_error); - get_u16(h_v_error); - - - printf ("Geodetic Navigation Data (41):\n"); - printf ("\tNav valid %04x\n", nav_valid); - printf ("\tNav type %04x\n", nav_type); - printf ("\tWeek %5d", week); - printf (" TOW %9d", tow); - printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n", - year, month, day, - hour, minute, second / 1000.0); - printf ("\tsats: %08x\n", sat_list); - printf ("\tlat: %g", lat / 1.0e7); - printf (" lon: %g", lon / 1.0e7); - printf (" alt_ell: %g", alt_ell / 100.0); - printf (" alt_msll: %g", alt_msl / 100.0); - printf (" datum: %d\n", datum); - printf ("\tground speed: %g", sog / 100.0); - printf (" course: %g", cog / 100.0); - printf (" climb: %g", climb_rate / 100.0); - printf (" heading rate: %g\n", heading_rate / 100.0); - printf ("\th error: %g", h_error / 100.0); - printf (" v error: %g", v_error / 100.0); - printf (" t error: %g", t_error / 100.0); - printf (" h vel error: %g\n", h_v_error / 100.0); - break; - } - case 4: { - int off = 4; - uint8_t id; - int16_t gps_week; - uint32_t gps_tow; - uint8_t channels; - int j, k; - - get_u8(id); - get_u16(gps_week); - get_u32(gps_tow); - get_u8(channels); - - printf ("Measured Tracker Data (4):\n"); - printf ("GPS week: %d\n", gps_week); - printf ("GPS time of week: %d\n", gps_tow); - printf ("channels: %d\n", channels); - for (j = 0; j < 12; j++) { - uint8_t svid, azimuth, elevation; - uint16_t state; - uint8_t c_n[10]; - get_u8(svid); - get_u8(azimuth); - get_u8(elevation); - get_u16(state); - for (k = 0; k < 10; k++) { - get_u8(c_n[k]); - } - printf ("Sat %3d:", svid); - printf (" aziumuth: %6.1f", azimuth * 1.5); - printf (" elevation: %6.1f", elevation * 0.5); - printf (" state: 0x%02x", state); - printf (" c_n:"); - for (k = 0; k < 10; k++) - printf(" %3d", c_n[k]); - if (state & SIRF_SAT_STATE_ACQUIRED) - printf(" acq,"); - if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID) - printf(" car,"); - if (state & SIRF_SAT_BIT_SYNC_COMPLETE) - printf(" bit,"); - if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE) - printf(" sub,"); - if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE) - printf(" pullin,"); - if (state & SIRF_SAT_CODE_LOCKED) - printf(" code,"); - if (state & SIRF_SAT_ACQUISITION_FAILED) - printf(" fail,"); - if (state & SIRF_SAT_EPHEMERIS_AVAILABLE) - printf(" ephem,"); - printf ("\n"); - } - break; - } - default: - return; - printf ("%s %4d:", from, encoded_len); - for (i = 4; i < len - 4; i++) { - if (((i - 4) & 0xf) == 0) - printf("\n "); - printf (" %3d", msg[i]); - } - printf ("\n"); - } -} - -static uint8_t skytraq_message[4096]; -static int skytraq_message_len; -static uint8_t skytraq_in_message[4096]; -static int skytraq_in_len; - -char -ao_serial_getchar(void) -{ - char c; - uint8_t uc; - - while (input_head == input_tail) { - for (;;) { - input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); - if (input_tail < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - perror ("getchar"); - exit (1); - } - input_head = 0; - break; - } - } - c = input_queue[input_head]; - input_head = (input_head + 1) % QUEUE_LEN; - uc = c; -// printf ("c: %02x %c\n", uc, uc); - if (skytraq_in_len || uc == '$') { - if (skytraq_in_len < 4096) - skytraq_in_message[skytraq_in_len++] = uc; - if (uc == 0x0a) { - check_skytraq_message("recv", skytraq_in_message, skytraq_in_len); - skytraq_in_len = 0; - } - } - return c; -} - - -void -ao_serial_putchar(char c) -{ - int i; - uint8_t uc = (uint8_t) c; - - if (skytraq_message_len || uc == 0xa0) { - if (skytraq_message_len < 4096) - skytraq_message[skytraq_message_len++] = uc; - if (uc == 0x0a) { - check_skytraq_message("send", skytraq_message, skytraq_message_len); - skytraq_message_len = 0; - } - } - for (;;) { - i = write(ao_gps_fd, &c, 1); - if (i == 1) { - if ((uint8_t) c == 0xb3 || c == '\r') { - static const struct timespec delay = { - .tv_sec = 0, - .tv_nsec = 100 * 1000 * 1000 - }; - tcdrain(ao_gps_fd); -// nanosleep(&delay, NULL); - } - 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 - -static void -ao_serial_set_speed(uint8_t speed) -{ - int fd = ao_gps_fd; - struct termios termios; - - tcdrain(fd); - tcgetattr(fd, &termios); - switch (speed) { - case AO_SERIAL_SPEED_4800: - cfsetspeed(&termios, B4800); - break; - case AO_SERIAL_SPEED_9600: - cfsetspeed(&termios, B38400); - break; - case AO_SERIAL_SPEED_57600: - cfsetspeed(&termios, B57600); - break; - } - tcsetattr(fd, TCSAFLUSH, &termios); - tcflush(fd, TCIFLUSH); -} - -#define ao_time() 0 - -#include "ao_gps_print.c" -#include "ao_gps_skytraq.c" - -void -ao_dump_state(void *wchan) -{ - double lat, lon; - int i; - 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 - -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 ]\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(); -} diff --git a/src/ao_host.h b/src/ao_host.h deleted file mode 100644 index 65c25fe5..00000000 --- a/src/ao_host.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 -#include -#include -#include -#include - -#define AO_ADC_RING 64 -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) - -/* - * One set of samples read from the A/D converter - */ -struct ao_adc { - uint16_t tick; /* tick when the sample was read */ - int16_t accel; /* accelerometer */ - int16_t pres; /* pressure sensor */ - int16_t temp; /* temperature sensor */ - int16_t v_batt; /* battery voltage */ - int16_t sense_d; /* drogue continuity sense */ - int16_t sense_m; /* main continuity sense */ -}; - -#define __pdata -#define __data -#define __xdata -#define __code -#define __reentrant - -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 -}; - -struct ao_adc ao_adc_ring[AO_ADC_RING]; -uint8_t ao_adc_head; - -#define ao_led_on(l) -#define ao_led_off(l) -#define ao_timer_set_adc_interval(i) -#define ao_wakeup(wchan) ao_dump_state(wchan) -#define ao_cmd_register(c) -#define ao_usb_disable() -#define ao_telemetry_set_interval(x) -#define ao_delay(x) - -enum ao_igniter { - ao_igniter_drogue = 0, - ao_igniter_main = 1 -}; - -void -ao_ignite(enum ao_igniter igniter) -{ - printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main"); -} - -struct ao_task { - int dummy; -}; - -#define ao_add_task(t,f,n) - -#define ao_log_start() -#define ao_log_stop() - -#define AO_MS_TO_TICKS(ms) ((ms) / 10) -#define AO_SEC_TO_TICKS(s) ((s) * 100) - -#define AO_FLIGHT_TEST - -struct ao_adc ao_adc_static; - -FILE *emulator_in; - -void -ao_dump_state(void *wchan); - -void -ao_sleep(void *wchan); - -const char const * const ao_state_names[] = { - "startup", "idle", "pad", "boost", "fast", - "coast", "drogue", "main", "landed", "invalid" -}; - -struct ao_cmds { - void (*func)(void); - const char *help; -}; - - -struct ao_config { - uint16_t main_deploy; - int16_t accel_zero_g; -}; - -#define ao_config_get() - -struct ao_config ao_config = { 250, 16000 }; diff --git a/src/ao_ignite.c b/src/ao_ignite.c deleted file mode 100644 index 5238beb4..00000000 --- a/src/ao_ignite.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -#if IGNITE_ON_P2 -#define AO_IGNITER_DROGUE P2_3 -#define AO_IGNITER_MAIN P2_4 -#define AO_IGNITER_DIR P2DIR -#define AO_IGNITER_DROGUE_BIT (1 << 3) -#define AO_IGNITER_MAIN_BIT (1 << 4) -#endif - -#if IGNITE_ON_P0 -#define AO_IGNITER_DROGUE P0_5 -#define AO_IGNITER_MAIN P0_4 -#define AO_IGNITER_DIR P0DIR -#define AO_IGNITER_DROGUE_BIT (1 << 5) -#define AO_IGNITER_MAIN_BIT (1 << 4) -#endif - -/* test these values with real igniters */ -#define AO_IGNITER_OPEN 1000 -#define AO_IGNITER_CLOSED 7000 -#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50) -#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000) - -struct ao_ignition { - uint8_t request; - uint8_t fired; - uint8_t firing; -}; - -__xdata struct ao_ignition ao_ignition[2]; - -void -ao_ignite(enum ao_igniter igniter) __critical -{ - ao_ignition[igniter].request = 1; - ao_wakeup(&ao_ignition); -} - -enum ao_igniter_status -ao_igniter_status(enum ao_igniter igniter) -{ - __xdata struct ao_adc adc; - __pdata int16_t value; - __pdata uint8_t request, firing, fired; - - __critical { - ao_adc_get(&adc); - request = ao_ignition[igniter].request; - fired = ao_ignition[igniter].fired; - firing = ao_ignition[igniter].firing; - } - if (firing || (request && !fired)) - return ao_igniter_active; - - value = (AO_IGNITER_CLOSED>>1); - switch (igniter) { - case ao_igniter_drogue: - value = adc.sense_d; - break; - case ao_igniter_main: - value = adc.sense_m; - break; - } - if (value < AO_IGNITER_OPEN) - return ao_igniter_open; - else if (value > AO_IGNITER_CLOSED) - return ao_igniter_ready; - else - return ao_igniter_unknown; -} - -void -ao_igniter_fire(enum ao_igniter igniter) __critical -{ - ao_ignition[igniter].firing = 1; - switch(ao_config.ignite_mode) { - case AO_IGNITE_MODE_DUAL: - switch (igniter) { - case ao_igniter_drogue: - AO_IGNITER_DROGUE = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_DROGUE = 0; - break; - case ao_igniter_main: - AO_IGNITER_MAIN = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_MAIN = 0; - break; - } - break; - case AO_IGNITE_MODE_APOGEE: - switch (igniter) { - case ao_igniter_drogue: - AO_IGNITER_DROGUE = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_DROGUE = 0; - ao_delay(AO_IGNITER_CHARGE_TIME); - AO_IGNITER_MAIN = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_MAIN = 0; - break; - } - break; - case AO_IGNITE_MODE_MAIN: - switch (igniter) { - case ao_igniter_main: - AO_IGNITER_DROGUE = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_DROGUE = 0; - ao_delay(AO_IGNITER_CHARGE_TIME); - AO_IGNITER_MAIN = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_MAIN = 0; - break; - } - break; - } - ao_ignition[igniter].firing = 0; -} - -void -ao_igniter(void) -{ - __xdata enum ao_ignter igniter; - - ao_config_get(); - for (;;) { - ao_sleep(&ao_ignition); - for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) { - if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) { - if (igniter == ao_igniter_drogue && ao_config.apogee_delay) - ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay)); - - ao_igniter_fire(igniter); - ao_delay(AO_IGNITER_CHARGE_TIME); - ao_ignition[igniter].fired = 1; - } - } - } -} - -void -ao_ignite_manual(void) -{ - ao_cmd_white(); - if (!ao_match_word("DoIt")) - return; - ao_cmd_white(); - if (ao_cmd_lex_c == 'm') { - if(ao_match_word("main")) - ao_igniter_fire(ao_igniter_main); - } else { - if(ao_match_word("drogue")) - ao_igniter_fire(ao_igniter_drogue); - } -} - -static __code char * __code igniter_status_names[] = { - "unknown", "ready", "active", "open" -}; - -void -ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant -{ - enum ao_igniter_status status = ao_igniter_status(igniter); - printf("Igniter: %6s Status: %s\n", - name, - igniter_status_names[status]); -} - -void -ao_ignite_test(void) -{ - ao_ignite_print_status(ao_igniter_drogue, "drogue"); - ao_ignite_print_status(ao_igniter_main, "main"); -} - -__code struct ao_cmds ao_ignite_cmds[] = { - { ao_ignite_manual, "i {main|drogue}\0Fire igniter. is doit with D&I" }, - { ao_ignite_test, "t\0Test igniter" }, - { 0, NULL }, -}; - -__xdata struct ao_task ao_igniter_task; - -void -ao_ignite_set_pins(void) -{ - AO_IGNITER_DROGUE = 0; - AO_IGNITER_MAIN = 0; - AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT; -} - -void -ao_igniter_init(void) -{ - ao_ignite_set_pins(); - ao_cmd_register(&ao_ignite_cmds[0]); - ao_add_task(&ao_igniter_task, ao_igniter, "igniter"); -} diff --git a/src/ao_intflash.c b/src/ao_intflash.c deleted file mode 100644 index d76d954e..00000000 --- a/src/ao_intflash.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright © 2011 Anthony Towns - * - * 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 "ao.h" -#include "cc1111.h" - -#define ENDOFCODE (CODESIZE) -#define AO_INTFLASH_BLOCK 1024 -#define AO_INTFLASH_BLOCKS ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK) -#define AO_INTFLASH_SIZE (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS) -#define AO_INTFLASH_LOCATION (0x8000 - AO_INTFLASH_SIZE) - -/* - * 21000 * 24e6 - * FWT = ------------ - * 16e9 - * - * = 31.5 - * - * Round up and use 32 - */ - -#define FLASH_TIMING 0x20 - -#if AO_INTFLASH_BLOCKS < 2 -#error "Too few pages" -#endif - -#if AO_INFTLASH_LOCATION % 1024 != 0 -#error "Pages aren't aligned properly" -#endif - -__xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE]; - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total = sizeof(ao_intflash); - -/* Block size - device is erased in these units. */ -__pdata uint32_t ao_storage_block = AO_INTFLASH_BLOCK; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK; - -/* Storage unit size - device reads and writes must be within blocks of this size. */ -__pdata uint16_t ao_storage_unit = AO_INTFLASH_BLOCK; - -__xdata static uint8_t ao_intflash_dma_done; -static uint8_t ao_intflash_dma; - -/* - * The internal flash chip is arranged in 1kB sectors; the - * chip cannot erase in units smaller than that. - * - * Writing happens in units of 2 bytes and - * can only change bits from 1 to 0. So, you can rewrite - * the same contents, or append to an existing page easily enough - */ - -/* - * Erase the specified sector - */ -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - uint16_t addr; - - if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) - return 0; - - addr = ((uint16_t)(ao_intflash + pos) >> 1); - - FADDRH = addr >> 8; - FADDRL = addr; - - __critical { - _asm - .even - orl _FCTL, #FCTL_ERASE; ; FCTL |= FCTL_ERASE - nop ; Required, see datasheet. - _endasm; - } - - return 1; -} - -/* - * Write to flash - */ - -static void -ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant -{ - pos = ((uint16_t) ao_intflash + pos) >> 1; - - ao_dma_set_transfer(ao_intflash_dma, - d, - &FWDATAXADDR, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_FLASH, - DMA_CFG1_SRCINC_1 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_HIGH); - - FADDRH = pos >> 8; - FADDRL = pos; - - ao_dma_start(ao_intflash_dma); - - __critical { - _asm - .even - orl _FCTL, #FCTL_WRITE; ; FCTL |= FCTL_WRITE - nop - _endasm; - } -} - -static void -ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant -{ - static __xdata uint8_t b[2]; - - if (pos & 1) { - b[0] = 0xff; - b[1] = byte; - } else { - b[0] = byte; - b[1] = 0xff; - } - ao_intflash_write_aligned(pos, b, 2); -} - -uint8_t -ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant -{ - uint16_t pos = pos32; - __xdata uint8_t *d = v; - uint8_t oddlen; - - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - if (len == 0) - return 1; - - if (pos & 1) { - ao_intflash_write_byte(pos++, *d++); - len--; - } - oddlen = len & 1; - len -= oddlen; - if (len) - ao_intflash_write_aligned(pos, d, len); - if (oddlen) - ao_intflash_write_byte(pos + len, d[len]); - - return 1; -} - -/* - * Read from flash - */ -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant -{ - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - memcpy(d, ao_intflash+pos, len); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ -} - -void -ao_storage_setup(void) -{ -} - -void -ao_storage_device_info(void) __reentrant -{ - printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION); -} - -void -ao_storage_device_init(void) -{ - ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done); - - FWT = FLASH_TIMING; -} diff --git a/src/ao_kalman.c b/src/ao_kalman.c deleted file mode 100644 index ee01949e..00000000 --- a/src/ao_kalman.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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. - */ - -#ifndef AO_FLIGHT_TEST -#include "ao.h" -#endif - -#include "ao_kalman.h" - -static __pdata int32_t ao_k_height; -static __pdata int32_t ao_k_speed; -static __pdata int32_t ao_k_accel; - -#define AO_K_STEP_100 to_fix16(0.01) -#define AO_K_STEP_2_2_100 to_fix16(0.00005) - -#define AO_K_STEP_10 to_fix16(0.1) -#define AO_K_STEP_2_2_10 to_fix16(0.005) - -#define AO_K_STEP_1 to_fix16(1) -#define AO_K_STEP_2_2_1 to_fix16(0.5) - -__pdata int16_t ao_height; -__pdata int16_t ao_speed; -__pdata int16_t ao_accel; -__pdata int16_t ao_max_height; -static __pdata int32_t ao_avg_height_scaled; -__pdata int16_t ao_avg_height; - -__pdata int16_t ao_error_h; -__pdata int16_t ao_error_h_sq_avg; - -#if HAS_ACCEL -__pdata int16_t ao_error_a; -#endif - -static void -ao_kalman_predict(void) -{ -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) { - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 + - (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1; - - return; - } - if (ao_sample_tick - ao_sample_prev_tick > 5) { - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + - (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; - - return; - } - if (ao_flight_debug) { - printf ("predict speed %g + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0, - (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0)); - } -#endif - ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + - (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; - ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; -} - -static void -ao_kalman_err_height(void) -{ - int16_t e; - int16_t height_distrust; -#if HAS_ACCEL - int16_t speed_distrust; -#endif - - ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16); - - e = ao_error_h; - if (e < 0) - e = -e; - if (e > 127) - e = 127; -#if HAS_ACCEL - ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2; - ao_error_h_sq_avg += (e * e) >> 2; -#else - ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; - ao_error_h_sq_avg += (e * e) >> 4; -#endif - - if (ao_flight_state >= ao_flight_drogue) - return; - height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT; -#if HAS_ACCEL - /* speed is stored * 16, but we need to ramp between 200 and 328, so - * we want to multiply by 2. The result is a shift by 3. - */ - speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1); - if (speed_distrust <= 0) - speed_distrust = 0; - else if (speed_distrust > height_distrust) - height_distrust = speed_distrust; -#endif - if (height_distrust > 0) { -#ifdef AO_FLIGHT_TEST - int old_ao_error_h = ao_error_h; -#endif - if (height_distrust > 0x100) - height_distrust = 0x100; - ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8); -#ifdef AO_FLIGHT_TEST - if (ao_flight_debug) { - printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", - (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT), - (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0, - height_distrust / 256.0, - old_ao_error_h, ao_error_h); - } -#endif - } -} - -static void -ao_kalman_correct_baro(void) -{ - ao_kalman_err_height(); -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) { - ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_1 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_1 * ao_error_h; - return; - } - if (ao_sample_tick - ao_sample_prev_tick > 5) { - ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; - return; - } -#endif - ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; - ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; - ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; -} - -#if HAS_ACCEL - -static void -ao_kalman_err_accel(void) -{ - int32_t accel; - - accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale; - - /* Can't use ao_accel here as it is the pre-prediction value still */ - ao_error_a = (accel - ao_k_accel) >> 16; -} - -static void -ao_kalman_correct_both(void) -{ - ao_kalman_err_height(); - ao_kalman_err_accel(); - -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) { - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_1 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_1 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_1 * ao_error_h + - (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0)); - } - ao_k_height += - (int32_t) AO_BOTH_K00_1 * ao_error_h + - (int32_t) AO_BOTH_K01_1 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_1 * ao_error_h + - (int32_t) AO_BOTH_K11_1 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_1 * ao_error_h + - (int32_t) AO_BOTH_K21_1 * ao_error_a; - return; - } - if (ao_sample_tick - ao_sample_prev_tick > 5) { - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_10 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_10 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_10 * ao_error_h + - (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0)); - } - ao_k_height += - (int32_t) AO_BOTH_K00_10 * ao_error_h + - (int32_t) AO_BOTH_K01_10 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_10 * ao_error_h + - (int32_t) AO_BOTH_K11_10 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_10 * ao_error_h + - (int32_t) AO_BOTH_K21_10 * ao_error_a; - return; - } - if (ao_flight_debug) { - printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", - ao_k_speed / (65536.0 * 16.0), - (double) ao_error_h, AO_BOTH_K10_100 / 65536.0, - (double) ao_error_a, AO_BOTH_K11_100 / 65536.0, - (ao_k_speed + - (int32_t) AO_BOTH_K10_100 * ao_error_h + - (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0)); - } -#endif - ao_k_height += - (int32_t) AO_BOTH_K00_100 * ao_error_h + - (int32_t) AO_BOTH_K01_100 * ao_error_a; - ao_k_speed += - (int32_t) AO_BOTH_K10_100 * ao_error_h + - (int32_t) AO_BOTH_K11_100 * ao_error_a; - ao_k_accel += - (int32_t) AO_BOTH_K20_100 * ao_error_h + - (int32_t) AO_BOTH_K21_100 * ao_error_a; -} - -#ifdef FORCE_ACCEL -static void -ao_kalman_correct_accel(void) -{ - ao_kalman_err_accel(); - - if (ao_sample_tick - ao_sample_prev_tick > 5) { - ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; - ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; - ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; - return; - } - ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; - ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; - ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; -} -#endif -#endif /* HAS_ACCEL */ - -void -ao_kalman(void) -{ - ao_kalman_predict(); -#if HAS_ACCEL - if (ao_flight_state <= ao_flight_coast) { -#ifdef FORCE_ACCEL - ao_kalman_correct_accel(); -#else - ao_kalman_correct_both(); -#endif - } else -#endif - ao_kalman_correct_baro(); - ao_height = from_fix(ao_k_height); - ao_speed = from_fix(ao_k_speed); - ao_accel = from_fix(ao_k_accel); - if (ao_height > ao_max_height) - ao_max_height = ao_height; - ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height; -#ifdef AO_FLIGHT_TEST - if (ao_sample_tick - ao_sample_prev_tick > 50) - ao_avg_height = (ao_avg_height_scaled + 1) >> 1; - else if (ao_sample_tick - ao_sample_prev_tick > 5) - ao_avg_height = (ao_avg_height_scaled + 7) >> 4; - else -#endif - ao_avg_height = (ao_avg_height_scaled + 63) >> 7; -#ifdef AO_FLIGHT_TEST - ao_sample_prev_tick = ao_sample_tick; -#endif -} diff --git a/src/ao_led.c b/src/ao_led.c deleted file mode 100644 index 5beed58d..00000000 --- a/src/ao_led.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -__pdata uint8_t ao_led_enable; - -void -ao_led_on(uint8_t colors) -{ - P1 |= (colors & ao_led_enable); -} - -void -ao_led_off(uint8_t colors) -{ - P1 &= ~(colors & ao_led_enable); -} - -void -ao_led_set(uint8_t colors) -{ - P1 = (P1 & ~(ao_led_enable)) | (colors & ao_led_enable); -} - -void -ao_led_toggle(uint8_t colors) -{ - P1 ^= (colors & ao_led_enable); -} - -void -ao_led_for(uint8_t colors, uint16_t ticks) __reentrant -{ - ao_led_on(colors); - ao_delay(ticks); - ao_led_off(colors); -} - -void -ao_led_init(uint8_t enable) -{ - ao_led_enable = enable; - P1SEL &= ~enable; - P1 &= ~enable; - P1DIR |= enable; -} diff --git a/src/ao_log.c b/src/ao_log.c deleted file mode 100644 index 6d3ad535..00000000 --- a/src/ao_log.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -__pdata uint32_t ao_log_current_pos; -__pdata uint32_t ao_log_end_pos; -__pdata uint32_t ao_log_start_pos; -__xdata uint8_t ao_log_running; -__pdata enum flight_state ao_log_state; -__xdata uint16_t ao_flight_number; - -__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL; - -void -ao_log_flush(void) -{ - ao_storage_flush(); -} - -/* - * When erasing a flight log, make sure the config block - * has an up-to-date version of the current flight number - */ - -struct ao_log_erase { - uint8_t unused; - uint16_t flight; -}; - -static __xdata struct ao_log_erase erase; - -#define LOG_MAX_ERASE 16 - -static uint32_t -ao_log_erase_pos(uint8_t i) -{ - return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG; -} - -void -ao_log_write_erase(uint8_t pos) -{ - erase.unused = 0x00; - erase.flight = ao_flight_number; - ao_storage_write(ao_log_erase_pos(pos), &erase, sizeof (erase)); - ao_storage_flush(); -} - -static void -ao_log_read_erase(uint8_t pos) -{ - ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase)); -} - - -static void -ao_log_erase_mark(void) -{ - uint8_t i; - - for (i = 0; i < LOG_MAX_ERASE; i++) { - ao_log_read_erase(i); - if (erase.unused == 0 && erase.flight == ao_flight_number) - return; - if (erase.unused == 0xff) { - ao_log_write_erase(i); - return; - } - } - ao_config_put(); -} - -static uint8_t -ao_log_slots() -{ - return (uint8_t) (ao_storage_config / ao_config.flight_log_max); -} - -uint32_t -ao_log_pos(uint8_t slot) -{ - return ((slot) * ao_config.flight_log_max); -} - -static uint16_t -ao_log_max_flight(void) -{ - uint8_t log_slot; - uint8_t log_slots; - uint16_t log_flight; - uint16_t max_flight = 0; - - /* Scan the log space looking for the biggest flight number */ - log_slots = ao_log_slots(); - for (log_slot = 0; log_slot < log_slots; log_slot++) { - log_flight = ao_log_flight(log_slot); - if (!log_flight) - continue; - if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0) - max_flight = log_flight; - } - return max_flight; -} - -void -ao_log_scan(void) __reentrant -{ - uint8_t log_slot; - uint8_t log_slots; - uint8_t log_want; - - ao_config_get(); - - ao_flight_number = ao_log_max_flight(); - if (ao_flight_number) - if (++ao_flight_number == 0) - ao_flight_number = 1; - - /* Now look through the log of flight numbers from erase operations and - * see if the last one is bigger than what we found above - */ - for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) { - ao_log_read_erase(log_slot); - if (erase.unused == 0) { - if (ao_flight_number == 0 || - (int16_t) (erase.flight - ao_flight_number) > 0) - ao_flight_number = erase.flight; - break; - } - } - if (ao_flight_number == 0) - ao_flight_number = 1; - - /* With a flight number in hand, find a place to write a new log, - * use the target flight number to index the available log slots so - * that we write logs to each spot about the same number of times. - */ - - /* Find a log slot for the next flight, if available */ - ao_log_current_pos = ao_log_end_pos = 0; - log_slots = ao_log_slots(); - log_want = (ao_flight_number - 1) % log_slots; - log_slot = log_want; - do { - if (ao_log_flight(log_slot) == 0) { - ao_log_current_pos = ao_log_pos(log_slot); - ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; - break; - } - if (++log_slot >= log_slots) - log_slot = 0; - } while (log_slot != log_want); - - ao_wakeup(&ao_flight_number); -} - -void -ao_log_start(void) -{ - /* start logging */ - ao_log_running = 1; - ao_wakeup(&ao_log_running); -} - -void -ao_log_stop(void) -{ - ao_log_running = 0; - ao_log_flush(); -} - -uint8_t -ao_log_present(void) -{ - return ao_log_max_flight() != 0; -} - -uint8_t -ao_log_full(void) -{ - return ao_log_current_pos == ao_log_end_pos; -} - -static __xdata struct ao_task ao_log_task; - -void -ao_log_list(void) __reentrant -{ - uint8_t slot; - uint8_t slots; - uint16_t flight; - - slots = ao_log_slots(); - for (slot = 0; slot < slots; slot++) - { - flight = ao_log_flight(slot); - if (flight) - printf ("flight %d start %x end %x\n", - flight, - (uint16_t) (ao_log_pos(slot) >> 8), - (uint16_t) (ao_log_pos(slot+1) >> 8)); - } - printf ("done\n"); -} - -void -ao_log_delete(void) __reentrant -{ - uint8_t slot; - uint8_t slots; - - ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - - slots = ao_log_slots(); - /* Look for the flight log matching the requested flight */ - if (ao_cmd_lex_i) { - for (slot = 0; slot < slots; slot++) { - if (ao_log_flight(slot) == ao_cmd_lex_i) { - ao_log_erase_mark(); - ao_log_current_pos = ao_log_pos(slot); - ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; - while (ao_log_current_pos < ao_log_end_pos) { - uint8_t i; - static __xdata uint8_t b; - - /* - * Check to see if we've reached the end of - * the used memory to avoid re-erasing the same - * memory over and over again - */ - for (i = 0; i < 16; i++) { - if (ao_storage_read(ao_log_current_pos + i, &b, 1)) - if (b != 0xff) - break; - } - if (i == 16) - break; - ao_storage_erase(ao_log_current_pos); - ao_log_current_pos += ao_storage_block; - } - puts("Erased"); - return; - } - } - } - printf("No such flight: %d\n", ao_cmd_lex_i); -} - -__code struct ao_cmds ao_log_cmds[] = { - { ao_log_list, "l\0List flight logs" }, - { ao_log_delete, "d \0Delete flight" }, - { 0, NULL }, -}; - -void -ao_log_init(void) -{ - ao_log_running = 0; - - /* For now, just log the flight starting at the begining of eeprom */ - ao_log_state = ao_flight_invalid; - - ao_cmd_register(&ao_log_cmds[0]); - - /* Create a task to log events to eeprom */ - ao_add_task(&ao_log_task, ao_log, "log"); -} diff --git a/src/ao_log_big.c b/src/ao_log_big.c deleted file mode 100644 index 74d94c4b..00000000 --- a/src/ao_log_big.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -static __xdata uint8_t ao_log_mutex; -static __xdata struct ao_log_record log; - -static uint8_t -ao_log_csum(__xdata uint8_t *b) __reentrant -{ - uint8_t sum = 0x5a; - uint8_t i; - - for (i = 0; i < sizeof (struct ao_log_record); i++) - sum += *b++; - return -sum; -} - -uint8_t -ao_log_data(__xdata struct ao_log_record *log) __reentrant -{ - uint8_t wrote = 0; - /* set checksum */ - log->csum = 0; - log->csum = ao_log_csum((__xdata uint8_t *) log); - ao_mutex_get(&ao_log_mutex); { - if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) - ao_log_stop(); - if (ao_log_running) { - wrote = 1; - ao_storage_write(ao_log_current_pos, - log, - sizeof (struct ao_log_record)); - ao_log_current_pos += sizeof (struct ao_log_record); - } - } ao_mutex_put(&ao_log_mutex); - return wrote; -} - -static uint8_t -ao_log_dump_check_data(void) -{ - if (ao_log_csum((uint8_t *) &log) != 0) - return 0; - return 1; -} - -static __data uint8_t ao_log_adc_pos; - -/* a hack to make sure that ao_log_records fill the eeprom block in even units */ -typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ; - -#define AO_SENSOR_INTERVAL_ASCENT 1 -#define AO_SENSOR_INTERVAL_DESCENT 10 -#define AO_OTHER_INTERVAL 32 - -void -ao_log(void) -{ - __pdata uint16_t next_sensor, next_other; - - ao_storage_setup(); - - ao_log_scan(); - - while (!ao_log_running) - ao_sleep(&ao_log_running); - - log.type = AO_LOG_FLIGHT; - log.tick = ao_sample_tick; -#if HAS_ACCEL - log.u.flight.ground_accel = ao_ground_accel; -#endif - log.u.flight.flight = ao_flight_number; - ao_log_data(&log); - - /* Write the whole contents of the ring to the log - * when starting up. - */ - ao_log_adc_pos = ao_adc_ring_next(ao_sample_adc); - next_other = next_sensor = ao_adc_ring[ao_log_adc_pos].tick; - ao_log_state = ao_flight_startup; - for (;;) { - /* Write samples to EEPROM */ - while (ao_log_adc_pos != ao_sample_adc) { - log.tick = ao_adc_ring[ao_log_adc_pos].tick; - if ((int16_t) (log.tick - next_sensor) >= 0) { - log.type = AO_LOG_SENSOR; - log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel; - log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres; - ao_log_data(&log); - if (ao_log_state <= ao_flight_coast) - next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT; - else - next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT; - } - if ((int16_t) (log.tick - next_other) >= 0) { - log.type = AO_LOG_TEMP_VOLT; - log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp; - log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt; - ao_log_data(&log); - log.type = AO_LOG_DEPLOY; - log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d; - log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m; - ao_log_data(&log); - next_other = log.tick + AO_OTHER_INTERVAL; - } - ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos); - } - /* Write state change to EEPROM */ - if (ao_flight_state != ao_log_state) { - ao_log_state = ao_flight_state; - log.type = AO_LOG_STATE; - log.tick = ao_sample_tick; - log.u.state.state = ao_log_state; - log.u.state.reason = 0; - ao_log_data(&log); - - if (ao_log_state == ao_flight_landed) - ao_log_stop(); - } - - /* Wait for a while */ - ao_delay(AO_MS_TO_TICKS(100)); - - /* Stop logging when told to */ - while (!ao_log_running) - ao_sleep(&ao_log_running); - } -} - -uint16_t -ao_log_flight(uint8_t slot) -{ - if (!ao_storage_read(ao_log_pos(slot), - &log, - sizeof (struct ao_log_record))) - return 0; - - if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) - return log.u.flight.flight; - return 0; -} diff --git a/src/ao_log_telem.c b/src/ao_log_telem.c deleted file mode 100644 index 1b472efe..00000000 --- a/src/ao_log_telem.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -void -ao_log_write_erase(uint8_t pos) -{ - (void) pos; -} - -uint8_t -ao_log_present(void) -{ - return 0; -} diff --git a/src/ao_log_tiny.c b/src/ao_log_tiny.c deleted file mode 100644 index d5a3b99f..00000000 --- a/src/ao_log_tiny.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -static __data uint16_t ao_log_tiny_interval; - -#define AO_LOG_TINY_INTERVAL_DEFAULT AO_MS_TO_TICKS(1000) -#if USE_FAST_ASCENT_LOG -#define AO_LOG_TINY_INTERVAL_ASCENT AO_MS_TO_TICKS(100) -#define AO_PAD_RING 8 -#else -#define AO_LOG_TINY_INTERVAL_ASCENT AO_LOG_TINY_INTERVAL_DEFAULT -#define AO_PAD_RING 2 -#endif - -__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY; - -void -ao_log_tiny_set_interval(uint16_t ticks) -{ - ao_log_tiny_interval = ticks; -} - - -static void ao_log_tiny_data(uint16_t d) -{ - if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) - ao_log_stop(); - if (ao_log_running) { - ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2); - ao_log_current_pos += 2; - } -} - -static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING]; -static __pdata uint8_t ao_log_pad_ring_pos; - -#define ao_pad_ring_next(n) (((n) + 1) & (AO_PAD_RING - 1)) - -static void ao_log_tiny_queue(uint16_t d) -{ - ao_log_pad_ring[ao_log_pad_ring_pos] = d; - ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos); -} - -static void ao_log_tiny_start(void) -{ - uint8_t p; - uint16_t d; - - ao_log_tiny_data(ao_flight_number); - ao_log_tiny_data(ao_ground_pres); - p = ao_log_pad_ring_pos; - do { - d = ao_log_pad_ring[p]; - /* - * ignore unwritten slots - */ - if (d) - ao_log_tiny_data(d); - p = ao_pad_ring_next(p); - } while (p != ao_log_pad_ring_pos); -} - -void -ao_log(void) -{ - uint16_t last_time; - uint16_t now; - enum ao_flight_state ao_log_tiny_state; - int32_t sum; - int16_t count; - uint8_t ao_log_adc; - uint8_t ao_log_started = 0; - - ao_storage_setup(); - - ao_log_scan(); - - ao_log_tiny_state = ao_flight_invalid; - ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; - sum = 0; - count = 0; - ao_log_adc = ao_sample_adc; - last_time = ao_time(); - for (;;) { - - /* - * Add in pending sample data - */ - ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); - while (ao_log_adc != ao_sample_adc) { - sum += ao_adc_ring[ao_log_adc].pres; - count++; - ao_log_adc = ao_adc_ring_next(ao_log_adc); - } - if (ao_log_running) { - if (!ao_log_started) { - ao_log_tiny_start(); - ao_log_started = 1; - } - if (ao_flight_state != ao_log_tiny_state) { - ao_log_tiny_data(ao_flight_state | 0x8000); - ao_log_tiny_state = ao_flight_state; - ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT; -#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT - if (ao_log_tiny_state <= ao_flight_coast) - ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; -#endif - if (ao_log_tiny_state == ao_flight_landed) - ao_log_stop(); - } - } - - /* Stop logging when told to */ - if (!ao_log_running && ao_log_started) - ao_exit(); - - /* - * Write out the sample when finished - */ - now = ao_time(); - if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) { - count = sum / count; - if (ao_log_started) - ao_log_tiny_data(count); - else - ao_log_tiny_queue(count); - sum = 0; - count = 0; - last_time = now; - } - } -} - -uint16_t -ao_log_flight(uint8_t slot) -{ - static __xdata uint16_t flight; - - (void) slot; - ao_storage_read(0, &flight, 2); - if (flight == 0xffff) - flight = 0; - return flight; -} diff --git a/src/ao_m25.c b/src/ao_m25.c deleted file mode 100644 index d7208273..00000000 --- a/src/ao_m25.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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 "ao.h" - -/* Total bytes of available storage */ -__pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -__pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -__pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -__pdata uint16_t ao_storage_unit; - -/* - * Each flash chip is arranged in 64kB sectors; the - * chip cannot erase in units smaller than that. - * - * Writing happens in units of 256 byte pages and - * can only change bits from 1 to 0. So, you can rewrite - * the same contents, or append to an existing page easily enough - */ - -#define M25_WREN 0x06 /* Write Enable */ -#define M25_WRDI 0x04 /* Write Disable */ -#define M25_RDID 0x9f /* Read Identification */ -#define M25_RDSR 0x05 /* Read Status Register */ -#define M25_WRSR 0x01 /* Write Status Register */ -#define M25_READ 0x03 /* Read Data Bytes */ -#define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ -#define M25_PP 0x02 /* Page Program */ -#define M25_SE 0xd8 /* Sector Erase */ -#define M25_BE 0xc7 /* Bulk Erase */ -#define M25_DP 0xb9 /* Deep Power-down */ - -/* RDID response */ -#define M25_MANUF_OFFSET 0 -#define M25_MEMORY_TYPE_OFFSET 1 -#define M25_CAPACITY_OFFSET 2 -#define M25_UID_OFFSET 3 -#define M25_CFI_OFFSET 4 -#define M25_RDID_LEN 4 /* that's all we need */ - -#define M25_CAPACITY_128KB 0x11 -#define M25_CAPACITY_256KB 0x12 -#define M25_CAPACITY_512KB 0x13 -#define M25_CAPACITY_1MB 0x14 -#define M25_CAPACITY_2MB 0x15 - -/* - * Status register bits - */ - -#define M25_STATUS_SRWD (1 << 7) /* Status register write disable */ -#define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */ -#define M25_STATUS_BP_SHIFT (2) -#define M25_STATUS_WEL (1 << 1) /* Write enable latch */ -#define M25_STATUS_WIP (1 << 0) /* Write in progress */ - -/* - * On teleterra, the m25 chip select pins are - * wired on P0_0 through P0_3. - */ - -#if M25_MAX_CHIPS > 1 -static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */ -static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */ -static uint8_t ao_m25_numchips; /* number of chips detected */ -#endif -static uint8_t ao_m25_total; /* total sectors available */ -static uint8_t ao_m25_wip; /* write in progress */ - -static __xdata uint8_t ao_m25_mutex; - -/* - * This little array is abused to send and receive data. A particular - * caution -- the read and write addresses are written into the last - * three bytes of the array by ao_m25_set_page_address and then the - * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither - * of which touch those last three bytes. - */ - -static __xdata uint8_t ao_m25_instruction[4]; - -#define M25_SELECT(cs) ao_spi_get_mask(SPI_CS_PORT,cs) -#define M25_DESELECT(cs) ao_spi_put_mask(SPI_CS_PORT,cs) - -#define M25_BLOCK_SHIFT 16 -#define M25_BLOCK 65536L -#define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT)) -#define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT) - -/* - * Block until the specified chip is done writing - */ -static void -ao_m25_wait_wip(uint8_t cs) -{ - if (ao_m25_wip & cs) { - M25_SELECT(cs); - ao_m25_instruction[0] = M25_RDSR; - ao_spi_send(ao_m25_instruction, 1); - do { - ao_spi_recv(ao_m25_instruction, 1); - } while (ao_m25_instruction[0] & M25_STATUS_WIP); - M25_DESELECT(cs); - ao_m25_wip &= ~cs; - } -} - -/* - * Set the write enable latch so that page program and sector - * erase commands will work. Also mark the chip as busy writing - * so that future operations will block until the WIP bit goes off - */ -static void -ao_m25_write_enable(uint8_t cs) -{ - M25_SELECT(cs); - ao_m25_instruction[0] = M25_WREN; - ao_spi_send(&ao_m25_instruction, 1); - M25_DESELECT(cs); - ao_m25_wip |= cs; -} - - -/* - * Returns the number of 64kB sectors - */ -static uint8_t -ao_m25_read_capacity(uint8_t cs) -{ - uint8_t capacity; - M25_SELECT(cs); - ao_m25_instruction[0] = M25_RDID; - ao_spi_send(ao_m25_instruction, 1); - ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); - M25_DESELECT(cs); - - /* Check to see if the chip is present */ - if (ao_m25_instruction[0] == 0xff) - return 0; - capacity = ao_m25_instruction[M25_CAPACITY_OFFSET]; - - /* Sanity check capacity number */ - if (capacity < 0x11 || 0x1f < capacity) - return 0; - return 1 << (capacity - 0x10); -} - -static uint8_t -ao_m25_set_address(uint32_t pos) -{ - uint8_t chip; -#if M25_MAX_CHIPS > 1 - uint8_t size; - - for (chip = 0; chip < ao_m25_numchips; chip++) { - size = ao_m25_size[chip]; - if (M25_POS_TO_SECTOR(pos) < size) - break; - pos -= M25_SECTOR_TO_POS(size); - } - if (chip == ao_m25_numchips) - return 0xff; - - chip = ao_m25_pin[chip]; -#else - chip = M25_CS_MASK; -#endif - ao_m25_wait_wip(chip); - - ao_m25_instruction[1] = pos >> 16; - ao_m25_instruction[2] = pos >> 8; - ao_m25_instruction[3] = pos; - return chip; -} - -/* - * Scan the possible chip select lines - * to see which flash chips are connected - */ -static uint8_t -ao_m25_scan(void) -{ -#if M25_MAX_CHIPS > 1 - uint8_t pin, size; -#endif - - if (ao_m25_total) - return 1; - -#if M25_MAX_CHIPS > 1 - ao_m25_numchips = 0; - for (pin = 1; pin != 0; pin <<= 1) { - if (M25_CS_MASK & pin) { - size = ao_m25_read_capacity(pin); - if (size != 0) { - ao_m25_size[ao_m25_numchips] = size; - ao_m25_pin[ao_m25_numchips] = pin; - ao_m25_total += size; - ao_m25_numchips++; - } - } - } -#else - ao_m25_total = ao_m25_read_capacity(M25_CS_MASK); -#endif - if (!ao_m25_total) - return 0; - ao_storage_total = M25_SECTOR_TO_POS(ao_m25_total); - ao_storage_block = M25_BLOCK; - ao_storage_config = ao_storage_total - M25_BLOCK; - ao_storage_unit = 256; - return 1; -} - -/* - * Erase the specified sector - */ -uint8_t -ao_storage_erase(uint32_t pos) __reentrant -{ - uint8_t cs; - - if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) - return 0; - - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - - cs = ao_m25_set_address(pos); - - ao_m25_wait_wip(cs); - ao_m25_write_enable(cs); - - ao_m25_instruction[0] = M25_SE; - M25_SELECT(cs); - ao_spi_send(ao_m25_instruction, 4); - M25_DESELECT(cs); - ao_m25_wip |= cs; - - ao_mutex_put(&ao_m25_mutex); - return 1; -} - -/* - * Write to flash - */ -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant -{ - uint8_t cs; - - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - - cs = ao_m25_set_address(pos); - ao_m25_write_enable(cs); - - ao_m25_instruction[0] = M25_PP; - M25_SELECT(cs); - ao_spi_send(ao_m25_instruction, 4); - ao_spi_send(d, len); - M25_DESELECT(cs); - - ao_mutex_put(&ao_m25_mutex); - return 1; -} - -/* - * Read from flash - */ -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant -{ - uint8_t cs; - - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - - cs = ao_m25_set_address(pos); - - /* No need to use the FAST_READ as we're running at only 8MHz */ - ao_m25_instruction[0] = M25_READ; - M25_SELECT(cs); - ao_spi_send(ao_m25_instruction, 4); - ao_spi_recv(d, len); - M25_DESELECT(cs); - - ao_mutex_put(&ao_m25_mutex); - return 1; -} - -void -ao_storage_flush(void) __reentrant -{ -} - -void -ao_storage_setup(void) -{ - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - ao_mutex_put(&ao_m25_mutex); -} - -void -ao_storage_device_info(void) __reentrant -{ - uint8_t cs; -#if M25_MAX_CHIPS > 1 - uint8_t chip; -#endif - - ao_mutex_get(&ao_m25_mutex); - ao_m25_scan(); - ao_mutex_put(&ao_m25_mutex); - -#if M25_MAX_CHIPS > 1 - printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total); - for (chip = 0; chip < ao_m25_numchips; chip++) - printf ("Flash chip %d select %02x size %d\n", - chip, ao_m25_pin[chip], ao_m25_size[chip]); -#else - printf ("Detected chips 1 size %d\n", ao_m25_total); -#endif - - printf ("Available chips:\n"); - for (cs = 1; cs != 0; cs <<= 1) { - if ((M25_CS_MASK & cs) == 0) - continue; - - ao_mutex_get(&ao_m25_mutex); - M25_SELECT(cs); - ao_m25_instruction[0] = M25_RDID; - ao_spi_send(ao_m25_instruction, 1); - ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); - M25_DESELECT(cs); - - printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n", - cs, - ao_m25_instruction[M25_MANUF_OFFSET], - ao_m25_instruction[M25_MEMORY_TYPE_OFFSET], - ao_m25_instruction[M25_CAPACITY_OFFSET], - ao_m25_instruction[M25_UID_OFFSET]); - ao_mutex_put(&ao_m25_mutex); - } -} - -void -ao_storage_device_init(void) -{ - /* Set up chip select wires */ - SPI_CS_PORT |= M25_CS_MASK; /* raise all CS pins */ - SPI_CS_DIR |= M25_CS_MASK; /* set CS pins as outputs */ - SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */ -} diff --git a/src/ao_main.c b/src/ao_main.c deleted file mode 100644 index 25acccfc..00000000 --- a/src/ao_main.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the red LED until the system is stable */ - ao_led_init(); - ao_led_on(AO_LED_RED); - - ao_timer_init(); - ao_adc_init(); - ao_beep_init(); - ao_cmd_init(); - ao_ee_init(); - ao_flight_init(); - ao_log_init(); - ao_report_init(); - ao_usb_init(); - ao_serial_init(); - ao_gps_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_start_scheduler(); -} diff --git a/src/ao_monitor.c b/src/ao_monitor.c deleted file mode 100644 index 69eb58e8..00000000 --- a/src/ao_monitor.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "ao_telem.h" - -#if !HAS_MONITOR -#error Must define HAS_MONITOR to 1 -#endif - -__xdata uint8_t ao_monitoring; -__pdata uint8_t ao_monitor_led; - -#define AO_MONITOR_RING 8 - -__xdata union ao_monitor { - struct ao_telemetry_raw_recv raw; - struct ao_telemetry_orig_recv orig; - struct ao_telemetry_tiny_recv tiny; -} ao_monitor_ring[AO_MONITOR_RING]; - -#define ao_monitor_ring_next(n) (((n) + 1) & (AO_MONITOR_RING - 1)) - -__data uint8_t ao_monitor_head; - -void -ao_monitor_get(void) -{ - uint8_t size; - - for (;;) { - switch (ao_monitoring) { - case 0: - ao_sleep(&ao_monitoring); - continue; - case AO_MONITORING_ORIG: - size = sizeof (struct ao_telemetry_orig_recv); - break; - case AO_MONITORING_TINY: - size = sizeof (struct ao_telemetry_tiny_recv); - break; - default: - if (ao_monitoring > AO_MAX_TELEMETRY) - ao_monitoring = AO_MAX_TELEMETRY; - size = ao_monitoring; - break; - } - if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2)) - continue; - ao_monitor_head = ao_monitor_ring_next(ao_monitor_head); - ao_wakeup(DATA_TO_XDATA(&ao_monitor_head)); - ao_led_toggle(ao_monitor_led); - } -} - -void -ao_monitor_put(void) -{ - __xdata char callsign[AO_MAX_CALLSIGN+1]; - - uint8_t ao_monitor_tail; - uint8_t state; - uint8_t sum, byte; - int16_t rssi; - __xdata union ao_monitor *m; - -#define recv_raw ((m->raw)) -#define recv_orig ((m->orig)) -#define recv_tiny ((m->tiny)) - - ao_monitor_tail = ao_monitor_head; - for (;;) { - while (ao_monitor_tail == ao_monitor_head) - ao_sleep(DATA_TO_XDATA(&ao_monitor_head)); - m = &ao_monitor_ring[ao_monitor_tail]; - ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail); - switch (ao_monitoring) { - case AO_MONITORING_ORIG: - state = recv_orig.telemetry_orig.flight_state; - - /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ - rssi = (int16_t) (recv_orig.rssi >> 1) - 74; - memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN); - if (state > ao_flight_invalid) - state = ao_flight_invalid; - if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) { - - /* General header fields */ - printf(AO_TELEM_VERSION " %d " - AO_TELEM_CALL " %s " - AO_TELEM_SERIAL " %d " - AO_TELEM_FLIGHT " %d " - AO_TELEM_RSSI " %d " - AO_TELEM_STATE " %s " - AO_TELEM_TICK " %d ", - AO_TELEMETRY_VERSION, - callsign, - recv_orig.telemetry_orig.serial, - recv_orig.telemetry_orig.flight, - rssi, - ao_state_names[state], - recv_orig.telemetry_orig.adc.tick); - - /* Raw sensor values */ - printf(AO_TELEM_RAW_ACCEL " %d " - AO_TELEM_RAW_BARO " %d " - AO_TELEM_RAW_THERMO " %d " - AO_TELEM_RAW_BATT " %d " - AO_TELEM_RAW_DROGUE " %d " - AO_TELEM_RAW_MAIN " %d ", - recv_orig.telemetry_orig.adc.accel, - recv_orig.telemetry_orig.adc.pres, - recv_orig.telemetry_orig.adc.temp, - recv_orig.telemetry_orig.adc.v_batt, - recv_orig.telemetry_orig.adc.sense_d, - recv_orig.telemetry_orig.adc.sense_m); - - /* Sensor calibration values */ - printf(AO_TELEM_CAL_ACCEL_GROUND " %d " - AO_TELEM_CAL_BARO_GROUND " %d " - AO_TELEM_CAL_ACCEL_PLUS " %d " - AO_TELEM_CAL_ACCEL_MINUS " %d ", - recv_orig.telemetry_orig.ground_accel, - recv_orig.telemetry_orig.ground_pres, - recv_orig.telemetry_orig.accel_plus_g, - recv_orig.telemetry_orig.accel_minus_g); - - if (recv_orig.telemetry_orig.u.k.unused == 0x8000) { - /* Kalman state values */ - printf(AO_TELEM_KALMAN_HEIGHT " %d " - AO_TELEM_KALMAN_SPEED " %d " - AO_TELEM_KALMAN_ACCEL " %d ", - recv_orig.telemetry_orig.height, - recv_orig.telemetry_orig.u.k.speed, - recv_orig.telemetry_orig.accel); - } else { - /* Ad-hoc flight values */ - printf(AO_TELEM_ADHOC_ACCEL " %d " - AO_TELEM_ADHOC_SPEED " %ld " - AO_TELEM_ADHOC_BARO " %d ", - recv_orig.telemetry_orig.accel, - recv_orig.telemetry_orig.u.flight_vel, - recv_orig.telemetry_orig.height); - } - ao_gps_print(&recv_orig.telemetry_orig.gps); - ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking); - putchar('\n'); - ao_rssi_set(rssi); - } else { - printf("CRC INVALID RSSI %3d\n", rssi); - } - break; - case AO_MONITORING_TINY: - state = recv_tiny.telemetry_tiny.flight_state; - - /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ - rssi = (int16_t) (recv_tiny.rssi >> 1) - 74; - memcpy(callsign, recv_tiny.telemetry_tiny.callsign, AO_MAX_CALLSIGN); - if (state > ao_flight_invalid) - state = ao_flight_invalid; - if (recv_tiny.status & PKT_APPEND_STATUS_1_CRC_OK) { - /* General header fields */ - printf(AO_TELEM_VERSION " %d " - AO_TELEM_CALL " %s " - AO_TELEM_SERIAL " %d " - AO_TELEM_FLIGHT " %d " - AO_TELEM_RSSI " %d " - AO_TELEM_STATE " %s " - AO_TELEM_TICK " %d ", - AO_TELEMETRY_VERSION, - callsign, - recv_tiny.telemetry_tiny.serial, - recv_tiny.telemetry_tiny.flight, - rssi, - ao_state_names[state], - recv_tiny.telemetry_tiny.adc.tick); - - /* Raw sensor values */ - printf(AO_TELEM_RAW_BARO " %d " - AO_TELEM_RAW_THERMO " %d " - AO_TELEM_RAW_BATT " %d " - AO_TELEM_RAW_DROGUE " %d " - AO_TELEM_RAW_MAIN " %d ", - recv_tiny.telemetry_tiny.adc.pres, - recv_tiny.telemetry_tiny.adc.temp, - recv_tiny.telemetry_tiny.adc.v_batt, - recv_tiny.telemetry_tiny.adc.sense_d, - recv_tiny.telemetry_tiny.adc.sense_m); - - /* Sensor calibration values */ - printf(AO_TELEM_CAL_BARO_GROUND " %d ", - recv_tiny.telemetry_tiny.ground_pres); - -#if 1 - /* Kalman state values */ - printf(AO_TELEM_KALMAN_HEIGHT " %d " - AO_TELEM_KALMAN_SPEED " %d " - AO_TELEM_KALMAN_ACCEL " %d\n", - recv_tiny.telemetry_tiny.height, - recv_tiny.telemetry_tiny.speed, - recv_tiny.telemetry_tiny.accel); -#else - /* Ad-hoc flight values */ - printf(AO_TELEM_ADHOC_ACCEL " %d " - AO_TELEM_ADHOC_SPEED " %ld " - AO_TELEM_ADHOC_BARO " %d\n", - recv_tiny.telemetry_tiny.flight_accel, - recv_tiny.telemetry_tiny.flight_vel, - recv_tiny.telemetry_tiny.flight_pres); -#endif - ao_rssi_set(rssi); - } else { - printf("CRC INVALID RSSI %3d\n", rssi); - } - break; - default: - printf ("TELEM %02x", ao_monitoring + 2); - sum = 0x5a; - for (state = 0; state < ao_monitoring + 2; state++) { - byte = recv_raw.packet[state]; - sum += byte; - printf("%02x", byte); - } - printf("%02x\n", sum); - break; - } - ao_usb_flush(); - } -} - -__xdata struct ao_task ao_monitor_get_task; -__xdata struct ao_task ao_monitor_put_task; - -void -ao_set_monitor(uint8_t monitoring) -{ - if (ao_monitoring) - ao_radio_recv_abort(); - ao_monitoring = monitoring; - ao_wakeup(&ao_monitoring); -} - -static void -set_monitor(void) -{ - ao_cmd_hex(); - ao_set_monitor(ao_cmd_lex_i); -} - -__code struct ao_cmds ao_monitor_cmds[] = { - { set_monitor, "m <0 off, 1 full, 2 tiny>\0Enable/disable radio monitoring" }, - { 0, NULL }, -}; - -void -ao_monitor_init(uint8_t monitor_led, uint8_t monitoring) __reentrant -{ - ao_monitor_led = monitor_led; - ao_monitoring = monitoring; - ao_cmd_register(&ao_monitor_cmds[0]); - ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get"); - ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put"); -} diff --git a/src/ao_mutex.c b/src/ao_mutex.c deleted file mode 100644 index c82a7d57..00000000 --- a/src/ao_mutex.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -void -ao_mutex_get(__xdata uint8_t *mutex) __reentrant -{ - if (*mutex == ao_cur_task->task_id) - ao_panic(AO_PANIC_MUTEX); - __critical { - while (*mutex) - ao_sleep(mutex); - *mutex = ao_cur_task->task_id; - } -} - -void -ao_mutex_put(__xdata uint8_t *mutex) __reentrant -{ - if (*mutex != ao_cur_task->task_id) - ao_panic(AO_PANIC_MUTEX); - __critical { - *mutex = 0; - ao_wakeup(mutex); - } -} diff --git a/src/ao_packet.c b/src/ao_packet.c deleted file mode 100644 index f627e02b..00000000 --- a/src/ao_packet.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -__xdata struct ao_packet_recv ao_rx_packet; -__xdata struct ao_packet ao_tx_packet; -__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; - -static __xdata char tx_data[AO_PACKET_MAX]; -static __xdata char rx_data[AO_PACKET_MAX]; -static __pdata uint8_t rx_seq; - -__xdata struct ao_task ao_packet_task; -__xdata uint8_t ao_packet_enable; -__xdata uint8_t ao_packet_master_sleeping; - -void -ao_packet_send(void) -{ - ao_led_on(AO_LED_RED); - /* If any tx data is pending then copy it into the tx packet */ - if (ao_packet_tx_used && ao_tx_packet.len == 0) { - memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); - ao_tx_packet.len = ao_packet_tx_used; - ao_tx_packet.seq++; - ao_packet_tx_used = 0; - ao_wakeup(&tx_data); - } - ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet)); - ao_led_off(AO_LED_RED); -} - -uint8_t -ao_packet_recv(void) -{ - uint8_t dma_done; - -#ifdef AO_LED_GREEN - ao_led_on(AO_LED_GREEN); -#endif - dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv)); -#ifdef AO_LED_GREEN - ao_led_off(AO_LED_GREEN); -#endif - - /* Check to see if we got a valid packet */ - if (!dma_done) - return 0; - if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) - return 0; - - /* SYN packets carry no data */ - if (ao_rx_packet.packet.len == AO_PACKET_SYN) { - rx_seq = ao_rx_packet.packet.seq; - ao_tx_packet.seq = ao_rx_packet.packet.ack; - ao_tx_packet.ack = rx_seq; - } else if (ao_rx_packet.packet.len) { - - /* Check for incoming data at the next sequence and - * for an empty data buffer - */ - if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && - ao_packet_rx_used == ao_packet_rx_len) { - - /* Copy data to the receive data buffer and set up the - * offsets - */ - memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); - ao_packet_rx_used = 0; - ao_packet_rx_len = ao_rx_packet.packet.len; - - /* Mark the sequence that we've received to - * let the sender know when we return a packet - */ - rx_seq = ao_rx_packet.packet.seq; - ao_tx_packet.ack = rx_seq; - - /* Poke anyone looking for received data */ - ao_wakeup(&ao_stdin_ready); - } - } - - /* If the other side has seen the latest data we queued, - * wake up any task waiting to send data and let them go again - */ - if (ao_rx_packet.packet.ack == ao_tx_packet.seq) { - ao_tx_packet.len = 0; - ao_wakeup(&ao_tx_packet); - } - return 1; -} - -#ifndef PACKET_HAS_MASTER -#define PACKET_HAS_MASTER 1 -#endif - -#if PACKET_HAS_MASTER -void -ao_packet_flush(void) -{ - /* If there is data to send, and this is the master, - * then poke the master to send all queued data - */ - if (ao_packet_tx_used && ao_packet_master_sleeping) - ao_wakeup(&ao_packet_master_sleeping); -} -#endif /* PACKET_HAS_MASTER */ - -void -ao_packet_putchar(char c) __reentrant -{ - while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) { -#if PACKET_HAS_MASTER - ao_packet_flush(); -#endif - ao_sleep(&tx_data); - } - - if (ao_packet_enable) - tx_data[ao_packet_tx_used++] = c; -} - -char -ao_packet_pollchar(void) __critical -{ - if (!ao_packet_enable) - return AO_READ_AGAIN; - - if (ao_packet_rx_used == ao_packet_rx_len) - return AO_READ_AGAIN; - - return rx_data[ao_packet_rx_used++]; -} diff --git a/src/ao_packet_master.c b/src/ao_packet_master.c deleted file mode 100644 index b0fdf5a8..00000000 --- a/src/ao_packet_master.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -static char -ao_packet_getchar(void) __critical -{ - char c; - while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) { - if (!ao_packet_enable) - break; - if (ao_packet_master_sleeping) - ao_wakeup(&ao_packet_master_sleeping); - flush(); - ao_sleep(&ao_stdin_ready); - } - return c; -} - -static void -ao_packet_echo(void) __reentrant -{ - char c; - while (ao_packet_enable) { - c = ao_packet_getchar(); - if (c != AO_READ_AGAIN) - putchar(c); - } - ao_exit(); -} - -static __xdata struct ao_task ao_packet_echo_task; -static __xdata uint16_t ao_packet_master_delay; -static __xdata uint16_t ao_packet_master_time; - -#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100) -#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000) -#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000) - -static void -ao_packet_master_busy(void) -{ - ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; - ao_packet_master_time = ao_time(); -} - -static void -ao_packet_master_check_busy(void) -{ - int16_t idle; - if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT) - return; - idle = (int16_t) (ao_time() - ao_packet_master_time); - - if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT) - ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG; -} - -void -ao_packet_master(void) -{ - ao_config_get(); - ao_tx_packet.addr = ao_serial_number; - ao_tx_packet.len = AO_PACKET_SYN; - ao_packet_master_time = ao_time(); - ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; - while (ao_packet_enable) { - memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); - ao_packet_send(); - if (ao_tx_packet.len) - ao_packet_master_busy(); - ao_packet_master_check_busy(); - ao_alarm(ao_packet_master_delay); - if (ao_packet_recv()) { - /* if we can transmit data, do so */ - if (ao_packet_tx_used && ao_tx_packet.len == 0) - continue; - if (ao_rx_packet.packet.len) - ao_packet_master_busy(); - ao_packet_master_sleeping = 1; - ao_alarm(ao_packet_master_delay); - ao_sleep(&ao_packet_master_sleeping); - ao_packet_master_sleeping = 0; - } - } - ao_exit(); -} - -static void -ao_packet_forward(void) __reentrant -{ - char c; - ao_packet_enable = 1; - ao_cmd_white(); - - flush(); -#if HAS_MONITOR - ao_set_monitor(0); -#endif - ao_add_task(&ao_packet_task, ao_packet_master, "master"); - ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo"); - while ((c = getchar()) != '~') { - if (c == '\r') c = '\n'; - ao_packet_putchar(c); - } - - /* Wait for a second if there is any pending data */ - for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++) - ao_delay(AO_MS_TO_TICKS(100)); - ao_packet_enable = 0; - while (ao_packet_echo_task.wchan || ao_packet_task.wchan) { - ao_radio_recv_abort(); - ao_wakeup(&ao_stdin_ready); - ao_delay(AO_MS_TO_TICKS(10)); - } -} - - - -__code struct ao_cmds ao_packet_master_cmds[] = { - { ao_packet_forward, "p\0Remote packet link." }, - { 0, NULL }, -}; - -void -ao_packet_master_init(void) -{ - ao_cmd_register(&ao_packet_master_cmds[0]); -} diff --git a/src/ao_packet_slave.c b/src/ao_packet_slave.c deleted file mode 100644 index 9f14052a..00000000 --- a/src/ao_packet_slave.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -void -ao_packet_slave(void) -{ - ao_tx_packet.addr = ao_serial_number; - ao_tx_packet.len = AO_PACKET_SYN; - while (ao_packet_enable) { - if (ao_packet_recv()) { - memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); -#if HAS_FLIGHT - ao_flight_force_idle = TRUE; -#endif - ao_packet_send(); - } - } - ao_exit(); -} - -void -ao_packet_slave_start(void) -{ - ao_packet_enable = 1; - ao_add_task(&ao_packet_task, ao_packet_slave, "slave"); -} - -void -ao_packet_slave_stop(void) -{ - if (ao_packet_enable) { - ao_packet_enable = 0; - while (ao_packet_task.wchan) { - ao_radio_recv_abort(); - ao_delay(AO_MS_TO_TICKS(10)); - } - } -} - -void -ao_packet_slave_init(uint8_t enable) -{ - ao_add_stdio(ao_packet_pollchar, - ao_packet_putchar, - NULL); - if (enable) - ao_packet_slave_start(); -} diff --git a/src/ao_panic.c b/src/ao_panic.c deleted file mode 100644 index fdada201..00000000 --- a/src/ao_panic.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -#ifndef HAS_BEEP -#error Please define HAS_BEEP -#endif - -#if !HAS_BEEP -#define ao_beep(x) -#endif - -static void -ao_panic_delay(uint8_t n) -{ - uint8_t i = 0, j = 0; - - while (n--) - while (--j) - while (--i) - _asm nop _endasm; -} - -void -ao_panic(uint8_t reason) -{ - uint8_t n; - - __critical for (;;) { - ao_panic_delay(20); - for (n = 0; n < 5; n++) { - ao_led_on(AO_LED_RED); - ao_beep(AO_BEEP_HIGH); - ao_panic_delay(1); - ao_led_off(AO_LED_RED); - ao_beep(AO_BEEP_LOW); - ao_panic_delay(1); - } - ao_beep(AO_BEEP_OFF); - ao_panic_delay(2); -#pragma disable_warning 126 - for (n = 0; n < reason; n++) { - ao_led_on(AO_LED_RED); - ao_beep(AO_BEEP_MID); - ao_panic_delay(10); - ao_led_off(AO_LED_RED); - ao_beep(AO_BEEP_OFF); - ao_panic_delay(10); - } - } -} diff --git a/src/ao_pins.h b/src/ao_pins.h deleted file mode 100644 index e1f5459f..00000000 --- a/src/ao_pins.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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. - */ - -#ifndef _AO_PINS_H_ -#define _AO_PINS_H_ - -#if defined(TELEMETRUM_V_1_0) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define HAS_ADC 1 - #define USE_SERIAL_STDIN 0 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_DBG 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define HAS_COMPANION 1 - #define COMPANION_CS_ON_P1 1 - #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ - #define COMPANION_CS P1_2 - - #define AO_LED_RED 1 - #define LEDS_AVAILABLE (AO_LED_RED) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL_REF 0 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEMETRUM_V_1_1) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_DBG 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define HAS_COMPANION 1 - #define COMPANION_CS_ON_P1 1 - #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ - #define COMPANION_CS P1_2 - - #define AO_LED_RED 1 - #define LEDS_AVAILABLE (AO_LED_RED) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL_REF 1 - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ - #define M25_MAX_CHIPS 1 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEDONGLE_V_0_2) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 1 - #define AO_LED_GREEN 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEMINI_V_1_0) - #define HAS_FLIGHT 1 - #define HAS_USB 0 - #define HAS_BEEP 0 - #define HAS_GPS 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 1 - #define HAS_DBG 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 1 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - #define USE_FAST_ASCENT_LOG 1 - - #define AO_LED_GREEN 1 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL 0 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELENANO_V_0_1) - #define HAS_FLIGHT 1 - #define HAS_USB 0 - #define HAS_BEEP 0 - #define HAS_GPS 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 1 - #define HAS_DBG 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 1 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - - #define AO_LED_GREEN 1 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 0 - #define HAS_ACCEL 0 - #define HAS_IGNITE 0 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEMETRUM_V_0_1) - #define HAS_FLIGHT 1 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_GPS 1 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 1 - #define HAS_DBG 0 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 1 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 0 - #define PACKET_HAS_SLAVE 1 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define HAS_EXTERNAL_TEMP 1 - #define HAS_ACCEL_REF 0 - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_ACCEL 1 - #define HAS_IGNITE 1 - #define HAS_MONITOR 0 -#endif - -#if defined(TELEDONGLE_V_0_1) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 0 - #define HAS_EEPROM 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 0 - #define SPI_CS_ON_P0 1 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TIDONGLE) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define LEDS_AVAILABLE (AO_LED_RED) - #define SPI_CS_ON_P1 0 - #define SPI_CS_ON_P0 1 - #define HAS_IGNITE 0 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEBT_V_0_0) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 0 - #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 1 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 0 - #define HAS_BTM 1 - #define DBG_ON_P1 0 - #define DBG_ON_P0 1 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 2 - #define AO_LED_GREEN 1 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define HAS_IGNITE 0 - #define BT_LINK_ON_P2 1 - #define BT_LINK_ON_P1 0 - #define BT_LINK_PIN_INDEX 7 - #define BT_LINK_PIN P2_1 - #define HAS_MONITOR 1 -#endif - -#if defined(TELEBT_V_0_1) - #define HAS_FLIGHT 0 - #define HAS_USB 1 - #define HAS_BEEP 1 - #define HAS_SERIAL_1 1 - #define HAS_SERIAL_1_ALT_1 1 - #define HAS_SERIAL_1_ALT_2 0 - #define HAS_SERIAL_1_HW_FLOW 1 - #define USE_SERIAL_STDIN 1 - #define HAS_ADC 0 - #define HAS_DBG 1 - #define HAS_EEPROM 1 - #define USE_INTERNAL_FLASH 0 - #define HAS_BTM 1 - #define DBG_ON_P1 1 - #define DBG_ON_P0 0 - #define IGNITE_ON_P2 0 - #define IGNITE_ON_P0 0 - #define PACKET_HAS_MASTER 1 - #define PACKET_HAS_SLAVE 0 - #define AO_LED_RED 1 - #define AO_LED_GREEN 2 - #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) - #define SPI_CS_ON_P1 1 - #define SPI_CS_ON_P0 0 - #define M25_CS_MASK 0x04 /* CS0 is P1_2 */ - #define M25_MAX_CHIPS 1 - #define HAS_ACCEL 0 - #define HAS_IGNITE 0 - #define BT_LINK_ON_P2 0 - #define BT_LINK_ON_P1 1 - #define BT_LINK_PIN_INDEX 7 - #define BT_LINK_PIN P1_7 - #define HAS_MONITOR 1 -#endif - -#if DBG_ON_P1 - - #define DBG_CLOCK (1 << 4) /* mi0 */ - #define DBG_DATA (1 << 5) /* mo0 */ - #define DBG_RESET_N (1 << 3) /* c0 */ - - #define DBG_CLOCK_PIN (P1_4) - #define DBG_DATA_PIN (P1_5) - #define DBG_RESET_N_PIN (P1_3) - - #define DBG_PORT_NUM 1 - #define DBG_PORT P1 - #define DBG_PORT_SEL P1SEL - #define DBG_PORT_INP P1INP - #define DBG_PORT_DIR P1DIR - -#endif /* DBG_ON_P1 */ - -#if DBG_ON_P0 - - #define DBG_CLOCK (1 << 3) - #define DBG_DATA (1 << 4) - #define DBG_RESET_N (1 << 5) - - #define DBG_CLOCK_PIN (P0_3) - #define DBG_DATA_PIN (P0_4) - #define DBG_RESET_N_PIN (P0_5) - - #define DBG_PORT_NUM 0 - #define DBG_PORT P0 - #define DBG_PORT_SEL P0SEL - #define DBG_PORT_INP P0INP - #define DBG_PORT_DIR P0DIR - -#endif /* DBG_ON_P0 */ - -#if COMPANION_CS_ON_P1 - #define COMPANION_CS_PORT P1 - #define COMPANION_CS_SEL P1SEL - #define COMPANION_CS_DIR P1DIR -#endif - -#if SPI_CS_ON_P1 - #define SPI_CS_PORT P1 - #define SPI_CS_SEL P1SEL - #define SPI_CS_DIR P1DIR -#endif - -#if SPI_CS_ON_P0 - #define SPI_CS_PORT P0 - #define SPI_CS_SEL P0SEL - #define SPI_CS_DIR P0DIR -#endif - -#ifndef IGNITE_ON_P2 -#error Please define IGNITE_ON_P2 -#endif - -#ifndef IGNITE_ON_P0 -#error Please define IGNITE_ON_P0 -#endif - -#ifndef HAS_SERIAL_1 -#error Please define HAS_SERIAL_1 -#endif - -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - -#ifndef HAS_ADC -#error Please define HAS_ADC -#endif - -#ifndef HAS_EEPROM -#error Please define HAS_EEPROM -#endif - -#if HAS_EEPROM -#ifndef USE_INTERNAL_FLASH -#error Please define USE_INTERNAL_FLASH -#endif -#endif - -#ifndef HAS_DBG -#error Please define HAS_DBG -#endif - -#ifndef HAS_IGNITE -#error Please define HAS_IGNITE -#endif - -#ifndef PACKET_HAS_MASTER -#error Please define PACKET_HAS_MASTER -#endif - -#ifndef PACKET_HAS_SLAVE -#error Please define PACKET_HAS_SLAVE -#endif - -#ifndef HAS_MONITOR -#error Please define HAS_MONITOR -#endif -#endif /* _AO_PINS_H_ */ diff --git a/src/ao_product.c b/src/ao_product.c deleted file mode 100644 index fb59580b..00000000 --- a/src/ao_product.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "ao_product.h" - -/* Defines which mark this particular AltOS product */ - -const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING; -const char ao_manufacturer[] = AO_iManufacturer_STRING; -const char ao_product[] = AO_iProduct_STRING; - -#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) - -#if HAS_USB -#include "ao_usb.h" -/* USB descriptors in one giant block of bytes */ -__code __at(0x00aa) uint8_t ao_usb_descriptors [] = -{ - /* Device descriptor */ - 0x12, - AO_USB_DESC_DEVICE, - LE_WORD(0x0110), /* bcdUSB */ - 0x02, /* bDeviceClass */ - 0x00, /* bDeviceSubClass */ - 0x00, /* bDeviceProtocol */ - AO_USB_CONTROL_SIZE, /* bMaxPacketSize */ - LE_WORD(0xFFFE), /* idVendor */ - LE_WORD(AO_idProduct_NUMBER), /* idProduct */ - LE_WORD(0x0100), /* bcdDevice */ - 0x01, /* iManufacturer */ - 0x02, /* iProduct */ - 0x03, /* iSerialNumber */ - 0x01, /* bNumConfigurations */ - - /* Configuration descriptor */ - 0x09, - AO_USB_DESC_CONFIGURATION, - LE_WORD(67), /* wTotalLength */ - 0x02, /* bNumInterfaces */ - 0x01, /* bConfigurationValue */ - 0x00, /* iConfiguration */ - 0xC0, /* bmAttributes */ - 0x32, /* bMaxPower */ - - /* Control class interface */ - 0x09, - AO_USB_DESC_INTERFACE, - 0x00, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x01, /* bNumEndPoints */ - 0x02, /* bInterfaceClass */ - 0x02, /* bInterfaceSubClass */ - 0x01, /* bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */ - 0x00, /* iInterface */ - - /* Header functional descriptor */ - 0x05, - CS_INTERFACE, - 0x00, /* bDescriptor SubType Header */ - LE_WORD(0x0110), /* CDC version 1.1 */ - - /* Call management functional descriptor */ - 0x05, - CS_INTERFACE, - 0x01, /* bDescriptor SubType Call Management */ - 0x01, /* bmCapabilities = device handles call management */ - 0x01, /* bDataInterface call management interface number */ - - /* ACM functional descriptor */ - 0x04, - CS_INTERFACE, - 0x02, /* bDescriptor SubType Abstract Control Management */ - 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */ - - /* Union functional descriptor */ - 0x05, - CS_INTERFACE, - 0x06, /* bDescriptor SubType Union Functional descriptor */ - 0x00, /* bMasterInterface */ - 0x01, /* bSlaveInterface0 */ - - /* Notification EP */ - 0x07, - AO_USB_DESC_ENDPOINT, - AO_USB_INT_EP|0x80, /* bEndpointAddress */ - 0x03, /* bmAttributes = intr */ - LE_WORD(8), /* wMaxPacketSize */ - 0x0A, /* bInterval */ - - /* Data class interface descriptor */ - 0x09, - AO_USB_DESC_INTERFACE, - 0x01, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x02, /* bNumEndPoints */ - 0x0A, /* bInterfaceClass = data */ - 0x00, /* bInterfaceSubClass */ - 0x00, /* bInterfaceProtocol */ - 0x00, /* iInterface */ - - /* Data EP OUT */ - 0x07, - AO_USB_DESC_ENDPOINT, - AO_USB_OUT_EP, /* bEndpointAddress */ - 0x02, /* bmAttributes = bulk */ - LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */ - 0x00, /* bInterval */ - - /* Data EP in */ - 0x07, - AO_USB_DESC_ENDPOINT, - AO_USB_IN_EP|0x80, /* bEndpointAddress */ - 0x02, /* bmAttributes = bulk */ - LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ - 0x00, /* bInterval */ - - /* String descriptors */ - 0x04, - AO_USB_DESC_STRING, - LE_WORD(0x0409), - - /* iManufacturer */ - AO_iManufacturer_LEN, - AO_USB_DESC_STRING, - AO_iManufacturer_UCS2, - - /* iProduct */ - AO_iProduct_LEN, - AO_USB_DESC_STRING, - AO_iProduct_UCS2, - - /* iSerial */ - AO_iSerial_LEN, - AO_USB_DESC_STRING, - AO_iSerial_UCS2, - - /* Terminating zero */ - 0 -}; -#endif diff --git a/src/ao_radio.c b/src/ao_radio.c deleted file mode 100644 index 00816b33..00000000 --- a/src/ao_radio.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -/* Values from SmartRF® Studio for: - * - * Deviation: 20.507812 kHz - * Datarate: 38.360596 kBaud - * Modulation: GFSK - * RF Freq: 434.549927 MHz - * Channel: 99.975586 kHz - * Channel: 0 - * RX filter: 93.75 kHz - */ - -/* - * For IF freq of 140.62kHz, the IF value is: - * - * 140.62e3 / (24e6 / 2**10) = 6 - */ - -#define IF_FREQ_CONTROL 6 - -/* - * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are - * - * BW = 24e6 / (8 * (4 + M) * 2 ** E) - * - * So, M = 0 and E = 3 - */ - -#define CHANBW_M 0 -#define CHANBW_E 3 - -/* - * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are: - * - * R = (256 + M) * 2** E * 24e6 / 2**28 - * - * So M is 163 and E is 10 - */ - -#define DRATE_E 10 -#define DRATE_M 163 - -/* - * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are: - * - * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E - * - * So M is 6 and E is 3 - */ - -#define DEVIATION_M 6 -#define DEVIATION_E 3 - -/* - * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone), - * so the DRATE_E and DRATE_M values are: - * - * M is 94 and E is 6 - * - * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes - */ - -#define RDF_DRATE_E 6 -#define RDF_DRATE_M 94 -#define RDF_PACKET_LEN 50 - -/* - * RDF deviation should match the normal NFM value of 5kHz - * - * M is 6 and E is 1 - * - */ - -#define RDF_DEVIATION_M 6 -#define RDF_DEVIATION_E 1 - -/* This are from the table for 433MHz */ - -#define RF_POWER_M30_DBM 0x12 -#define RF_POWER_M20_DBM 0x0e -#define RF_POWER_M15_DBM 0x1d -#define RF_POWER_M10_DBM 0x34 -#define RF_POWER_M5_DBM 0x2c -#define RF_POWER_0_DBM 0x60 -#define RF_POWER_5_DBM 0x84 -#define RF_POWER_7_DBM 0xc8 -#define RF_POWER_10_DBM 0xc0 - -#define RF_POWER RF_POWER_10_DBM - -static __code uint8_t radio_setup[] = { - RF_PA_TABLE7_OFF, RF_POWER, - RF_PA_TABLE6_OFF, RF_POWER, - RF_PA_TABLE5_OFF, RF_POWER, - RF_PA_TABLE4_OFF, RF_POWER, - RF_PA_TABLE3_OFF, RF_POWER, - RF_PA_TABLE2_OFF, RF_POWER, - RF_PA_TABLE1_OFF, RF_POWER, - RF_PA_TABLE0_OFF, RF_POWER, - - RF_FSCTRL1_OFF, (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT), - RF_FSCTRL0_OFF, (0 << RF_FSCTRL0_FREQOFF_SHIFT), - - RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | - (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | - (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), - RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT), - RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF | - RF_MDMCFG2_MOD_FORMAT_GFSK | - RF_MDMCFG2_SYNC_MODE_15_16_THRES), - RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN | - RF_MDMCFG1_NUM_PREAMBLE_4 | - (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), - RF_MDMCFG0_OFF, (17 << RF_MDMCFG0_CHANSPC_M_SHIFT), - - RF_CHANNR_OFF, 0, - - RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | - (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), - - /* SmartRF says set LODIV_BUF_CURRENT_TX to 0 - * And, we're not using power ramping, so use PA_POWER 0 - */ - RF_FREND0_OFF, ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) | - (0 << RF_FREND0_PA_POWER_SHIFT)), - - RF_FREND1_OFF, ((1 << RF_FREND1_LNA_CURRENT_SHIFT) | - (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) | - (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) | - (2 << RF_FREND1_MIX_CURRENT_SHIFT)), - - RF_FSCAL3_OFF, 0xE9, - RF_FSCAL2_OFF, 0x0A, - RF_FSCAL1_OFF, 0x00, - RF_FSCAL0_OFF, 0x1F, - - RF_TEST2_OFF, 0x88, - RF_TEST1_OFF, 0x31, - RF_TEST0_OFF, 0x09, - - /* default sync values */ - RF_SYNC1_OFF, 0xD3, - RF_SYNC0_OFF, 0x91, - - /* max packet length */ - RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| - PKTCTRL1_APPEND_STATUS| - PKTCTRL1_ADR_CHK_NONE), - RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA| - RF_PKTCTRL0_PKT_FORMAT_NORMAL| - RF_PKTCTRL0_CRC_EN| - RF_PKTCTRL0_LENGTH_CONFIG_FIXED), - RF_ADDR_OFF, 0x00, - RF_MCSM2_OFF, (RF_MCSM2_RX_TIME_END_OF_PACKET), - RF_MCSM1_OFF, (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING| - RF_MCSM1_RXOFF_MODE_IDLE| - RF_MCSM1_TXOFF_MODE_IDLE), - RF_MCSM0_OFF, (RF_MCSM0_FS_AUTOCAL_FROM_IDLE| - RF_MCSM0_MAGIC_3| - RF_MCSM0_CLOSE_IN_RX_0DB), - RF_FOCCFG_OFF, (RF_FOCCFG_FOC_PRE_K_3K, - RF_FOCCFG_FOC_POST_K_PRE_K, - RF_FOCCFG_FOC_LIMIT_BW_OVER_4), - RF_BSCFG_OFF, (RF_BSCFG_BS_PRE_K_2K| - RF_BSCFG_BS_PRE_KP_3KP| - RF_BSCFG_BS_POST_KI_PRE_KI| - RF_BSCFG_BS_POST_KP_PRE_KP| - RF_BSCFG_BS_LIMIT_0), - RF_AGCCTRL2_OFF, 0x43, - RF_AGCCTRL1_OFF, 0x40, - RF_AGCCTRL0_OFF, 0x91, - - RF_IOCFG2_OFF, 0x00, - RF_IOCFG1_OFF, 0x00, - RF_IOCFG0_OFF, 0x00, -}; - -static __code uint8_t rdf_setup[] = { - RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | - (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | - (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), - RF_MDMCFG3_OFF, (RDF_DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT), - RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF | - RF_MDMCFG2_MOD_FORMAT_GFSK | - RF_MDMCFG2_SYNC_MODE_15_16_THRES), - RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_DIS | - RF_MDMCFG1_NUM_PREAMBLE_2 | - (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), - - RF_DEVIATN_OFF, ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | - (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), - - /* packet length is set in-line */ - RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| - PKTCTRL1_ADR_CHK_NONE), - RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL| - RF_PKTCTRL0_LENGTH_CONFIG_FIXED), -}; - -static __code uint8_t fixed_pkt_setup[] = { - RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | - (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | - (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), - RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT), - RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF | - RF_MDMCFG2_MOD_FORMAT_GFSK | - RF_MDMCFG2_SYNC_MODE_15_16_THRES), - RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN | - RF_MDMCFG1_NUM_PREAMBLE_4 | - (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), - - RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | - (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), - - /* max packet length -- now set inline */ - RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| - PKTCTRL1_APPEND_STATUS| - PKTCTRL1_ADR_CHK_NONE), - RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA| - RF_PKTCTRL0_PKT_FORMAT_NORMAL| - RF_PKTCTRL0_CRC_EN| - RF_PKTCTRL0_LENGTH_CONFIG_FIXED), -}; - -__xdata uint8_t ao_radio_dma; -__xdata uint8_t ao_radio_dma_done; -__xdata uint8_t ao_radio_done; -__xdata uint8_t ao_radio_abort; -__xdata uint8_t ao_radio_mutex; - -void -ao_radio_general_isr(void) __interrupt 16 -{ - S1CON &= ~0x03; - if (RFIF & RFIF_IM_TIMEOUT) { - ao_radio_recv_abort(); - RFIF &= ~ RFIF_IM_TIMEOUT; - } else if (RFIF & RFIF_IM_DONE) { - ao_radio_done = 1; - ao_wakeup(&ao_radio_done); - RFIF &= ~RFIF_IM_DONE; - } -} - -void -ao_radio_set_packet(void) -{ - uint8_t i; - for (i = 0; i < sizeof (fixed_pkt_setup); i += 2) - RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1]; -} - -void -ao_radio_idle(void) -{ - if (RF_MARCSTATE != RF_MARCSTATE_IDLE) - { - do { - RFST = RFST_SIDLE; - ao_yield(); - } while (RF_MARCSTATE != RF_MARCSTATE_IDLE); - } -} - -void -ao_radio_get(uint8_t len) -{ - ao_config_get(); - ao_mutex_get(&ao_radio_mutex); - ao_radio_idle(); - RF_CHANNR = ao_config.radio_channel; - RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16); - RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8); - RF_FREQ0 = (uint8_t) (ao_config.radio_setting); - RF_PKTLEN = len; -} - - -void -ao_radio_send(__xdata void *packet, uint8_t size) __reentrant -{ - ao_radio_get(size); - ao_radio_done = 0; - ao_dma_set_transfer(ao_radio_dma, - packet, - &RFDXADDR, - size, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_RADIO, - DMA_CFG1_SRCINC_1 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_HIGH); - ao_dma_start(ao_radio_dma); - RFST = RFST_STX; - __critical while (!ao_radio_done) - ao_sleep(&ao_radio_done); - ao_radio_put(); -} - -uint8_t -ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant -{ - ao_radio_abort = 0; - ao_radio_get(size - 2); - ao_dma_set_transfer(ao_radio_dma, - &RFDXADDR, - packet, - size, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_RADIO, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_1 | - DMA_CFG1_PRIORITY_HIGH); - ao_dma_start(ao_radio_dma); - RFST = RFST_SRX; - - /* Wait for DMA to be done, for the radio receive process to - * get aborted or for a receive timeout to fire - */ - __critical while (!ao_radio_dma_done && !ao_radio_abort) - if (ao_sleep(&ao_radio_dma_done)) - break; - - /* If recv was aborted, clean up by stopping the DMA engine - * and idling the radio - */ - if (!ao_radio_dma_done) { - ao_dma_abort(ao_radio_dma); - ao_radio_idle(); - } - ao_radio_put(); - return ao_radio_dma_done; -} - -/* - * Wake up a task waiting to receive a radio packet - * and tell them to abort the transfer - */ - -void -ao_radio_recv_abort(void) -{ - ao_radio_abort = 1; - ao_wakeup(&ao_radio_dma_done); -} - -__xdata ao_radio_rdf_value = 0x55; - -void -ao_radio_rdf(int ms) -{ - uint8_t i; - uint8_t pkt_len; - - /* - * Compute the packet length as follows: - * - * 2000 bps (for a 1kHz tone) - * so, for 'ms' milliseconds, we need - * 2 * ms bits, or ms / 4 bytes - */ - if (ms > (255 * 4)) - ms = 255 * 4; - pkt_len = ms >> 2; - - ao_radio_abort = 0; - ao_radio_get(pkt_len); - ao_radio_done = 0; - for (i = 0; i < sizeof (rdf_setup); i += 2) - RF[rdf_setup[i]] = rdf_setup[i+1]; - - ao_dma_set_transfer(ao_radio_dma, - &ao_radio_rdf_value, - &RFDXADDR, - pkt_len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_RADIO, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_HIGH); - ao_dma_start(ao_radio_dma); - RFST = RFST_STX; - __critical while (!ao_radio_done && !ao_radio_abort) - ao_sleep(&ao_radio_done); - if (!ao_radio_done) { - ao_dma_abort(ao_radio_dma); - ao_radio_idle(); - } - ao_radio_set_packet(); - ao_radio_put(); -} - -void -ao_radio_rdf_abort(void) -{ - ao_radio_abort = 1; - ao_wakeup(&ao_radio_done); -} - - -/* Output carrier */ -void -ao_radio_test(void) -{ - uint8_t mode = 2; - static __xdata radio_on; - ao_cmd_white(); - if (ao_cmd_lex_c != '\n') { - ao_cmd_decimal(); - mode = (uint8_t) ao_cmd_lex_u32; - } - mode++; - if ((mode & 2) && !radio_on) { -#if HAS_MONITOR - ao_set_monitor(0); -#endif -#if PACKET_HAS_SLAVE - ao_packet_slave_stop(); -#endif - ao_radio_get(0xff); - RFST = RFST_STX; - radio_on = 1; - } - if (mode == 3) { - printf ("Hit a character to stop..."); flush(); - getchar(); - putchar('\n'); - } - if ((mode & 1) && radio_on) { - ao_radio_idle(); - ao_radio_put(); - radio_on = 0; - } -} - -__code struct ao_cmds ao_radio_cmds[] = { - { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" }, - { 0, NULL }, -}; - -void -ao_radio_init(void) -{ - uint8_t i; - for (i = 0; i < sizeof (radio_setup); i += 2) - RF[radio_setup[i]] = radio_setup[i+1]; - ao_radio_set_packet(); - ao_radio_dma_done = 1; - ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done); - RFIF = 0; - RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE; - IEN2 |= IEN2_RFIE; - ao_cmd_register(&ao_radio_cmds[0]); -} diff --git a/src/ao_reboot.c b/src/ao_reboot.c deleted file mode 100644 index 8c47b893..00000000 --- a/src/ao_reboot.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -/* Use the watchdog timer to force a complete reboot - */ -void -ao_reboot(void) -{ - WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_32768; - ao_delay(AO_SEC_TO_TICKS(2)); - ao_panic(AO_PANIC_REBOOT); -} diff --git a/src/ao_report.c b/src/ao_report.c deleted file mode 100644 index 3cf558e1..00000000 --- a/src/ao_report.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -#define BIT(i,x) ((x) ? (1 << (i)) : 0) -#define MORSE1(a) (1 | BIT(3,a)) -#define MORSE2(a,b) (2 | BIT(3,a) | BIT(4,b)) -#define MORSE3(a,b,c) (3 | BIT(3,a) | BIT(4,b) | BIT(5,c)) -#define MORSE4(a,b,c,d) (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d)) -#define MORSE5(a,b,c,d,e) (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e)) - -static const uint8_t flight_reports[] = { - MORSE3(0,0,0), /* startup, 'S' */ - MORSE2(0,0), /* idle 'I' */ - MORSE4(0,1,1,0), /* pad 'P' */ - MORSE4(1,0,0,0), /* boost 'B' */ - MORSE4(0,0,1,0), /* fast 'F' */ - MORSE4(1,0,1,0), /* coast 'C' */ - MORSE3(1,0,0), /* drogue 'D' */ - MORSE2(1,1), /* main 'M' */ - MORSE4(0,1,0,0), /* landed 'L' */ - MORSE4(1,0,0,1), /* invalid 'X' */ -}; - -#if HAS_BEEP -#define low(time) ao_beep_for(AO_BEEP_LOW, time) -#define mid(time) ao_beep_for(AO_BEEP_MID, time) -#define high(time) ao_beep_for(AO_BEEP_HIGH, time) -#else -#define low(time) ao_led_for(AO_LED_GREEN, time) -#define mid(time) ao_led_for(AO_LED_RED, time) -#define high(time) ao_led_for(AO_LED_GREEN|AO_LED_RED, time) -#endif -#define pause(time) ao_delay(time) - -static __pdata enum ao_flight_state ao_report_state; - -static void -ao_report_beep(void) __reentrant -{ - uint8_t r = flight_reports[ao_flight_state]; - uint8_t l = r & 7; - - if (!r) - return; - while (l--) { - if (r & 8) - mid(AO_MS_TO_TICKS(600)); - else - mid(AO_MS_TO_TICKS(200)); - pause(AO_MS_TO_TICKS(200)); - r >>= 1; - } - pause(AO_MS_TO_TICKS(400)); -} - -static void -ao_report_digit(uint8_t digit) __reentrant -{ - if (!digit) { - mid(AO_MS_TO_TICKS(500)); - pause(AO_MS_TO_TICKS(200)); - } else { - while (digit--) { - mid(AO_MS_TO_TICKS(200)); - pause(AO_MS_TO_TICKS(200)); - } - } - pause(AO_MS_TO_TICKS(300)); -} - -static void -ao_report_altitude(void) -{ - __pdata int16_t agl = ao_max_height; - __xdata uint8_t digits[10]; - __pdata uint8_t ndigits, i; - - if (agl < 0) - agl = 0; - ndigits = 0; - do { - digits[ndigits++] = agl % 10; - agl /= 10; - } while (agl); - - for (;;) { - ao_report_beep(); - i = ndigits; - do - ao_report_digit(digits[--i]); - while (i != 0); - pause(AO_SEC_TO_TICKS(5)); - } -} - -#if HAS_IGNITE -static uint8_t -ao_report_igniter_ready(enum ao_igniter igniter) -{ - return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0; -} - -static void -ao_report_continuity(void) __reentrant -{ - uint8_t c = (ao_report_igniter_ready(ao_igniter_drogue) | - (ao_report_igniter_ready(ao_igniter_main) << 1)); - if (c) { - while (c--) { - high(AO_MS_TO_TICKS(25)); - pause(AO_MS_TO_TICKS(100)); - } - } else { - c = 10; - while (c--) { - high(AO_MS_TO_TICKS(20)); - low(AO_MS_TO_TICKS(20)); - } - } - if (ao_log_full()) { - pause(AO_MS_TO_TICKS(100)); - c = 2; - while (c--) { - low(AO_MS_TO_TICKS(100)); - mid(AO_MS_TO_TICKS(100)); - high(AO_MS_TO_TICKS(100)); - mid(AO_MS_TO_TICKS(100)); - } - } - c = 50; - while (c-- && ao_flight_state == ao_flight_pad) - pause(AO_MS_TO_TICKS(100)); -} -#endif - -void -ao_report(void) -{ - ao_report_state = ao_flight_state; - for(;;) { - if (ao_flight_state == ao_flight_landed) - ao_report_altitude(); - ao_report_beep(); -#if HAS_IGNITE - if (ao_flight_state == ao_flight_idle) - ao_report_continuity(); - while (ao_flight_state == ao_flight_pad) - ao_report_continuity(); -#endif - __critical { - while (ao_report_state == ao_flight_state) - ao_sleep(DATA_TO_XDATA(&ao_flight_state)); - ao_report_state = ao_flight_state; - } - } -} - -static __xdata struct ao_task ao_report_task; - -void -ao_report_init(void) -{ - ao_add_task(&ao_report_task, ao_report, "report"); -} diff --git a/src/ao_romconfig.c b/src/ao_romconfig.c deleted file mode 100644 index f3fe61b1..00000000 --- a/src/ao_romconfig.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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 "ao.h" - -__code __at (0x00a0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION; -__code __at (0x00a2) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION; -__code __at (0x00a4) uint16_t ao_serial_number = 0; -/* - * For 434.550MHz, the frequency value is: - * - * 434.550e6 / (24e6 / 2**16) = 1186611.2 - * - * This value is stored in a const variable so that - * ao-load can change it during programming for - * devices that have no eeprom for config data. - */ -__code __at (0x00a6) uint32_t ao_radio_cal = 1186611; diff --git a/src/ao_rssi.c b/src/ao_rssi.c deleted file mode 100644 index e3964d2d..00000000 --- a/src/ao_rssi.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -static __xdata volatile uint16_t ao_rssi_time; -static __pdata volatile uint16_t ao_rssi_delay; -static __pdata uint8_t ao_rssi_led; - -void -ao_rssi(void) -{ - for (;;) { - while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3)) - ao_sleep(&ao_rssi_time); - ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100)); - ao_delay(ao_rssi_delay); - } -} - -void -ao_rssi_set(int rssi_value) -{ - if (rssi_value > 0) - rssi_value = 0; - ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5); - ao_rssi_time = ao_time(); - ao_wakeup(&ao_rssi_time); -} - -__xdata struct ao_task ao_rssi_task; - -void -ao_rssi_init(uint8_t rssi_led) -{ - ao_rssi_led = rssi_led; - ao_rssi_delay = 0; - ao_add_task(&ao_rssi_task, ao_rssi, "rssi"); -} diff --git a/src/ao_sample.c b/src/ao_sample.c deleted file mode 100644 index b2b8e9f6..00000000 --- a/src/ao_sample.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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. - */ - -#ifndef AO_FLIGHT_TEST -#include "ao.h" -#endif - -/* - * Current sensor values - */ - -__pdata uint16_t ao_sample_tick; /* time of last data */ -__pdata int16_t ao_sample_pres; -__pdata int16_t ao_sample_alt; -__pdata int16_t ao_sample_height; -#if HAS_ACCEL -__pdata int16_t ao_sample_accel; -#endif - -__data uint8_t ao_sample_adc; - -/* - * Sensor calibration values - */ - -__pdata int16_t ao_ground_pres; /* startup pressure */ -__pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ - -#if HAS_ACCEL -__pdata int16_t ao_ground_accel; /* startup acceleration */ -__pdata int16_t ao_accel_2g; /* factory accel calibration */ -__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ -#endif - -static __pdata uint8_t ao_preflight; /* in preflight mode */ - -static __pdata uint16_t nsamples; -__pdata int32_t ao_sample_pres_sum; -#if HAS_ACCEL -__pdata int32_t ao_sample_accel_sum; -#endif - -static void -ao_sample_preflight(void) -{ - /* startup state: - * - * Collect 512 samples of acceleration and pressure - * data and average them to find the resting values - */ - if (nsamples < 512) { -#if HAS_ACCEL - ao_sample_accel_sum += ao_sample_accel; -#endif - ao_sample_pres_sum += ao_sample_pres; - ++nsamples; - } else { - ao_config_get(); -#if HAS_ACCEL - ao_ground_accel = ao_sample_accel_sum >> 9; - ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; - ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; -#endif - ao_ground_pres = ao_sample_pres_sum >> 9; - ao_ground_height = ao_pres_to_altitude(ao_ground_pres); - ao_preflight = FALSE; - } -} - -uint8_t -ao_sample(void) -{ - ao_wakeup(DATA_TO_XDATA(&ao_sample_adc)); - ao_sleep(DATA_TO_XDATA(&ao_adc_head)); - while (ao_sample_adc != ao_adc_head) { - __xdata struct ao_adc *ao_adc; - - /* Capture a sample */ - ao_adc = &ao_adc_ring[ao_sample_adc]; - ao_sample_tick = ao_adc->tick; - ao_sample_pres = ao_adc->pres; - ao_sample_alt = ao_pres_to_altitude(ao_sample_pres); - ao_sample_height = ao_sample_alt - ao_ground_height; -#if HAS_ACCEL - ao_sample_accel = ao_adc->accel; -#if HAS_ACCEL_REF - /* - * Ok, the math here is a bit tricky. - * - * ao_sample_accel: ADC output for acceleration - * ao_accel_ref: ADC output for the 5V reference. - * ao_cook_accel: Corrected acceleration value - * Vcc: 3.3V supply to the CC1111 - * Vac: 5V supply to the accelerometer - * accel: input voltage to accelerometer ADC pin - * ref: input voltage to 5V reference ADC pin - * - * - * Measured acceleration is ratiometric to Vcc: - * - * ao_sample_accel accel - * ------------ = ----- - * 32767 Vcc - * - * Measured 5v reference is also ratiometric to Vcc: - * - * ao_accel_ref ref - * ------------ = ----- - * 32767 Vcc - * - * - * ao_accel_ref = 32767 * (ref / Vcc) - * - * Acceleration is measured ratiometric to the 5V supply, - * so what we want is: - * - * ao_cook_accel accel - * ------------- = ----- - * 32767 ref - * - * - * accel Vcc - * = ----- * --- - * Vcc ref - * - * ao_sample_accel 32767 - * = ------------ * ------------ - * 32767 ao_accel_ref - * - * Multiply through by 32767: - * - * ao_sample_accel * 32767 - * ao_cook_accel = -------------------- - * ao_accel_ref - * - * Now, the tricky part. Getting this to compile efficiently - * and keeping all of the values in-range. - * - * First off, we need to use a shift of 16 instead of * 32767 as SDCC - * does the obvious optimizations for byte-granularity shifts: - * - * ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref - * - * Next, lets check our input ranges: - * - * 0 <= ao_sample_accel <= 0x7fff (singled ended ADC conversion) - * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) - * - * Plugging in our input ranges, we get an output range of 0 - 0x12490, - * which is 17 bits. That won't work. If we take the accel ref and shift - * by a bit, we'll change its range: - * - * 0xe000 <= ao_accel_ref<<1 <= 0xfffe - * - * ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1) - * - * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It - * is, however, one bit too large for our signed computations. So, we - * take the result and shift that by a bit: - * - * ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1 - * - * This finally creates an output range of 0 - 0x4924. As the ADC only - * provides 11 bits of data, we haven't actually lost any precision, - * just dropped a bit of noise off the low end. - */ - ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1; - if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) - ao_sample_accel = 0x7fff - ao_sample_accel; - ao_adc->accel = ao_sample_accel; -#endif -#endif - - if (ao_preflight) - ao_sample_preflight(); - else - ao_kalman(); - ao_sample_adc = ao_adc_ring_next(ao_sample_adc); - } - return !ao_preflight; -} - -void -ao_sample_init(void) -{ - nsamples = 0; - ao_sample_pres_sum = 0; - ao_sample_pres = 0; -#if HAS_ACCEL - ao_sample_accel_sum = 0; - ao_sample_accel = 0; -#endif - ao_sample_adc = ao_adc_head; - ao_preflight = TRUE; -} diff --git a/src/ao_serial.c b/src/ao_serial.c deleted file mode 100644 index 82370c64..00000000 --- a/src/ao_serial.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -volatile __xdata struct ao_fifo ao_usart1_rx_fifo; -volatile __xdata struct ao_fifo ao_usart1_tx_fifo; - -void -ao_serial_rx1_isr(void) __interrupt 3 -{ - if (!ao_fifo_full(ao_usart1_rx_fifo)) - ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF); - ao_wakeup(&ao_usart1_rx_fifo); -#if USE_SERIAL_STDIN - ao_wakeup(&ao_stdin_ready); -#endif -} - -static __xdata uint8_t ao_serial_tx1_started; - -static void -ao_serial_tx1_start(void) -{ - if (!ao_fifo_empty(ao_usart1_tx_fifo) && - !ao_serial_tx1_started) - { - ao_serial_tx1_started = 1; - ao_fifo_remove(ao_usart1_tx_fifo, U1DBUF); - } -} - -void -ao_serial_tx1_isr(void) __interrupt 14 -{ - UTX1IF = 0; - ao_serial_tx1_started = 0; - ao_serial_tx1_start(); - ao_wakeup(&ao_usart1_tx_fifo); -} - -char -ao_serial_getchar(void) __critical -{ - char c; - while (ao_fifo_empty(ao_usart1_rx_fifo)) - ao_sleep(&ao_usart1_rx_fifo); - ao_fifo_remove(ao_usart1_rx_fifo, c); - return c; -} - -#if USE_SERIAL_STDIN -char -ao_serial_pollchar(void) __critical -{ - char c; - if (ao_fifo_empty(ao_usart1_rx_fifo)) - return AO_READ_AGAIN; - ao_fifo_remove(ao_usart1_rx_fifo,c); - return c; -} -#endif - -void -ao_serial_putchar(char c) __critical -{ - while (ao_fifo_full(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); - ao_fifo_insert(ao_usart1_tx_fifo, c); - ao_serial_tx1_start(); -} - -void -ao_serial_drain(void) __critical -{ - while (!ao_fifo_empty(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); -} - -static __code struct { - uint8_t baud; - uint8_t gcr; -} ao_serial_speeds[] = { - /* [AO_SERIAL_SPEED_4800] = */ { - /* .baud = */ 163, - /* .gcr = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, - /* [AO_SERIAL_SPEED_9600] = */ { - /* .baud = */ 163, - /* .gcr = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, - /* [AO_SERIAL_SPEED_19200] = */ { - /* .baud = */ 163, - /* .gcr = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, - /* [AO_SERIAL_SPEED_57600] = */ { - /* .baud = */ 59, - /* .gcr = */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB - }, -}; - -void -ao_serial_set_speed(uint8_t speed) -{ - ao_serial_drain(); - if (speed > AO_SERIAL_SPEED_57600) - return; - U1UCR |= UxUCR_FLUSH; - U1BAUD = ao_serial_speeds[speed].baud; - U1GCR = ao_serial_speeds[speed].gcr; -} - -void -ao_serial_init(void) -{ -#if HAS_SERIAL_1_ALT_1 - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1; - - P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0; - - /* Make the USART pins be controlled by the USART */ - P0SEL |= (1 << 5) | (1 << 4); -#if HAS_SERIAL_1_HW_FLOW - P0SEL |= (1 << 3) | (1 << 2); -#endif -#else - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2; - - P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) | - (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1); - - /* Make the USART pins be controlled by the USART */ - P1SEL |= (1 << 6) | (1 << 7); - P1SEL |= (1 << 5) | (1 << 4); -#endif - - /* UART mode with receiver enabled */ - U1CSR = (UxCSR_MODE_UART | UxCSR_RE); - - /* Pick a 4800 baud rate */ - ao_serial_set_speed(AO_SERIAL_SPEED_4800); - - /* Reasonable serial parameters */ - U1UCR = (UxUCR_FLUSH | -#if HAS_SERIAL_1_HW_FLOW - UxUCR_FLOW_ENABLE | -#else - UxUCR_FLOW_DISABLE | -#endif - UxUCR_D9_EVEN_PARITY | - UxUCR_BIT9_8_BITS | - UxUCR_PARITY_DISABLE | - UxUCR_SPB_1_STOP_BIT | - UxUCR_STOP_HIGH | - UxUCR_START_LOW); - - IEN0 |= IEN0_URX1IE; - IEN2 |= IEN2_UTX1IE; -} diff --git a/src/ao_spi.c b/src/ao_spi.c deleted file mode 100644 index fbe613c7..00000000 --- a/src/ao_spi.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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 "ao.h" - -/* Shared mutex to protect SPI bus, must cover the entire - * operation, from CS low to CS high. This means that any SPI - * user must protect the SPI bus with this mutex - */ -__xdata uint8_t ao_spi_mutex; -__xdata uint8_t ao_spi_dma_in_done; -__xdata uint8_t ao_spi_dma_out_done; - -uint8_t ao_spi_dma_out_id; -uint8_t ao_spi_dma_in_id; - -static __xdata uint8_t ao_spi_const = 0xff; - -/* Send bytes over SPI. - * - * This sets up two DMA engines, one writing the data and another reading - * bytes coming back. We use the bytes coming back to tell when the transfer - * is complete, as the transmit register is double buffered and hence signals - * completion one byte before the transfer is actually complete - */ -void -ao_spi_send(void __xdata *block, uint16_t len) __reentrant -{ - ao_dma_set_transfer(ao_spi_dma_in_id, - &U0DBUFXADDR, - &ao_spi_const, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_URX0, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_set_transfer(ao_spi_dma_out_id, - block, - &U0DBUFXADDR, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_UTX0, - DMA_CFG1_SRCINC_1 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_start(ao_spi_dma_in_id); - ao_dma_start(ao_spi_dma_out_id); - ao_dma_trigger(ao_spi_dma_out_id); - __critical while (!ao_spi_dma_in_done) - ao_sleep(&ao_spi_dma_in_done); -} - -/* Receive bytes over SPI. - * - * This sets up tow DMA engines, one reading the data and another - * writing constant values to the SPI transmitter as that is what - * clocks the data coming in. - */ -void -ao_spi_recv(void __xdata *block, uint16_t len) __reentrant -{ - ao_dma_set_transfer(ao_spi_dma_in_id, - &U0DBUFXADDR, - block, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_URX0, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_1 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_set_transfer(ao_spi_dma_out_id, - &ao_spi_const, - &U0DBUFXADDR, - len, - DMA_CFG0_WORDSIZE_8 | - DMA_CFG0_TMODE_SINGLE | - DMA_CFG0_TRIGGER_UTX0, - DMA_CFG1_SRCINC_0 | - DMA_CFG1_DESTINC_0 | - DMA_CFG1_PRIORITY_NORMAL); - - ao_dma_start(ao_spi_dma_in_id); - ao_dma_start(ao_spi_dma_out_id); - ao_dma_trigger(ao_spi_dma_out_id); - __critical while (!ao_spi_dma_in_done) - ao_sleep(&ao_spi_dma_in_done); -} - -/* - * Initialize USART0 for SPI using config alt 2 - * - * MO P1_5 - * MI P1_4 - * CLK P1_3 - * - * Chip select is the responsibility of the caller - */ - -void -ao_spi_init(void) -{ - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2; - - /* Ensure that USART0 takes precidence over USART1 for pins that - * they share - */ - P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | P2SEL_PRI3P1_USART0; - - /* Make the SPI pins be controlled by the USART peripheral */ - P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3)); - - /* Set up OUT DMA */ - ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done); - - /* Set up IN DMA */ - ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done); - - /* Set up the USART. - * - * SPI master mode - */ - U0CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_MASTER); - - /* Set the baud rate and signal parameters - * - * The cc1111 is limited to a 24/8 MHz SPI clock. - * Every peripheral I've ever seen goes faster than that, - * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0) - */ - U0BAUD = 0; - U0GCR = (UxGCR_CPOL_NEGATIVE | - UxGCR_CPHA_FIRST_EDGE | - UxGCR_ORDER_MSB | - (17 << UxGCR_BAUD_E_SHIFT)); -} diff --git a/src/ao_state.c b/src/ao_state.c deleted file mode 100644 index ed197aa5..00000000 --- a/src/ao_state.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -const char const * const ao_state_names[] = { - "startup", "idle", "pad", "boost", "fast", - "coast", "drogue", "main", "landed", "invalid" -}; diff --git a/src/ao_stdio.c b/src/ao_stdio.c deleted file mode 100644 index c0138a30..00000000 --- a/src/ao_stdio.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -/* - * Basic I/O functions to support SDCC stdio package - */ - -#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) - -__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; -__pdata int8_t ao_cur_stdio; -__pdata int8_t ao_num_stdios; - -void -putchar(char c) -{ - if (c == '\n') - (*ao_stdios[ao_cur_stdio].putchar)('\r'); - (*ao_stdios[ao_cur_stdio].putchar)(c); -} - -void -flush(void) -{ - if (ao_stdios[ao_cur_stdio].flush) - ao_stdios[ao_cur_stdio].flush(); -} - -__xdata uint8_t ao_stdin_ready; - -char -getchar(void) __reentrant __critical -{ - char c; - int8_t stdio = ao_cur_stdio; - - for (;;) { - c = ao_stdios[stdio].pollchar(); - if (c != AO_READ_AGAIN) - break; - if (++stdio == ao_num_stdios) - stdio = 0; - if (stdio == ao_cur_stdio) - ao_sleep(&ao_stdin_ready); - } - ao_cur_stdio = stdio; - return c; -} - -uint8_t -ao_echo(void) -{ - return ao_stdios[ao_cur_stdio].echo; -} - -int8_t -ao_add_stdio(char (*pollchar)(void), - void (*putchar)(char), - void (*flush)(void)) __reentrant -{ - if (ao_num_stdios == AO_NUM_STDIOS) - ao_panic(AO_PANIC_STDIO); - ao_stdios[ao_num_stdios].pollchar = pollchar; - ao_stdios[ao_num_stdios].putchar = putchar; - ao_stdios[ao_num_stdios].flush = flush; - ao_stdios[ao_num_stdios].echo = 1; - return ao_num_stdios++; -} diff --git a/src/ao_storage.c b/src/ao_storage.c deleted file mode 100644 index 6ffca0e5..00000000 --- a/src/ao_storage.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -uint8_t -ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t this_len; - uint16_t this_off; - - ao_storage_setup(); - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - while (len) { - - /* Compute portion of transfer within - * a single block - */ - this_off = (uint16_t) pos & (ao_storage_unit - 1); - this_len = ao_storage_unit - this_off; - if (this_len > len) - this_len = len; - - if (!ao_storage_device_read(pos, buf, this_len)) - return 0; - - /* See how much is left */ - buf += this_len; - len -= this_len; - pos += this_len; - } - return 1; -} - -uint8_t -ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant -{ - uint16_t this_len; - uint16_t this_off; - - ao_storage_setup(); - if (pos >= ao_storage_total || pos + len > ao_storage_total) - return 0; - while (len) { - - /* Compute portion of transfer within - * a single block - */ - this_off = (uint16_t) pos & (ao_storage_unit - 1); - this_len = ao_storage_unit - this_off; - if (this_len > len) - this_len = len; - - if (!ao_storage_device_write(pos, buf, this_len)) - return 0; - - /* See how much is left */ - buf += this_len; - len -= this_len; - pos += this_len; - } - return 1; -} - -static __xdata uint8_t storage_data[8]; - -static void -ao_storage_dump(void) __reentrant -{ - uint8_t i, j; - - ao_cmd_hex(); - if (ao_cmd_status != ao_cmd_success) - return; - for (i = 0; ; i += 8) { - if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i, - storage_data, - 8)) { - ao_cmd_put16((uint16_t) i); - for (j = 0; j < 8; j++) { - putchar(' '); - ao_cmd_put8(storage_data[j]); - } - putchar ('\n'); - } - if (i == 248) - break; - } -} - -#if 0 - -/* not enough space for this today - */ -static void -ao_storage_store(void) __reentrant -{ - uint16_t block; - uint8_t i; - uint16_t len; - static __xdata uint8_t b; - uint32_t addr; - - ao_cmd_hex(); - block = ao_cmd_lex_i; - ao_cmd_hex(); - i = ao_cmd_lex_i; - addr = ((uint32_t) block << 8) | i; - ao_cmd_hex(); - len = ao_cmd_lex_i; - if (ao_cmd_status != ao_cmd_success) - return; - while (len--) { - ao_cmd_hex(); - if (ao_cmd_status != ao_cmd_success) - return; - b = ao_cmd_lex_i; - ao_storage_write(addr, &b, 1); - addr++; - } -} -#endif - -void -ao_storage_zap(void) __reentrant -{ - ao_cmd_hex(); - if (ao_cmd_status != ao_cmd_success) - return; - ao_storage_erase((uint32_t) ao_cmd_lex_i << 8); -} - -void -ao_storage_zapall(void) __reentrant -{ - uint32_t pos; - - ao_cmd_white(); - if (!ao_match_word("DoIt")) - return; - for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) - ao_storage_erase(pos); -} - -void -ao_storage_info(void) __reentrant -{ - printf("Storage size: %ld\n", ao_storage_total); - printf("Storage erase unit: %ld\n", ao_storage_block); - ao_storage_device_info(); -} - -__code struct ao_cmds ao_storage_cmds[] = { - { ao_storage_info, "f\0Show storage" }, - { ao_storage_dump, "e \0Dump flash" }, -#ifdef HAS_STORAGE_DBG - { ao_storage_store, "w ...\0Write data to flash" }, -#endif - { ao_storage_zap, "z \0Erase " }, - { ao_storage_zapall,"Z \0Erase all. is doit with D&I" }, - { 0, NULL }, -}; - -void -ao_storage_init(void) -{ - ao_storage_device_init(); - ao_cmd_register(&ao_storage_cmds[0]); -} diff --git a/src/ao_task.c b/src/ao_task.c deleted file mode 100644 index f5850fa4..00000000 --- a/src/ao_task.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -#define AO_NO_TASK_INDEX 0xff - -__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS]; -__data uint8_t ao_num_tasks; -__data uint8_t ao_cur_task_index; -__xdata struct ao_task *__data ao_cur_task; - -void -ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant -{ - uint8_t __xdata *stack; - uint8_t task_id; - uint8_t t; - if (ao_num_tasks == AO_NUM_TASKS) - ao_panic(AO_PANIC_NO_TASK); - for (task_id = 1; task_id != 0; task_id++) { - for (t = 0; t < ao_num_tasks; t++) - if (ao_tasks[t]->task_id == task_id) - break; - if (t == ao_num_tasks) - break; - } - ao_tasks[ao_num_tasks++] = task; - task->task_id = task_id; - task->name = name; - /* - * Construct a stack frame so that it will 'return' - * to the start of the task - */ - stack = task->stack; - - *stack++ = ((uint16_t) start); /* 0 */ - *stack++ = ((uint16_t) start) >> 8; /* 1 */ - - /* and the stuff saved by ao_switch */ - *stack++ = 0; /* 2 acc */ - *stack++ = 0x80; /* 3 IE */ - - /* 4 DPL - * 5 DPH - * 6 B - * 7 R2 - * 8 R3 - * 9 R4 - * 10 R5 - * 11 R6 - * 12 R7 - * 13 R0 - * 14 R1 - * 15 PSW - * 16 BP - */ - for (t = 0; t < 13; t++) - *stack++ = 0; - - task->stack_count = 17; - task->wchan = NULL; -} - -/* Task switching function. This must not use any stack variables */ -void -ao_yield(void) __naked -{ - - /* Save current context */ - _asm - /* Push ACC first, as when restoring the context it must be restored - * last (it is used to set the IE register). */ - push ACC - /* Store the IE register then enable interrupts. */ - push _IEN0 - setb _EA - push DPL - push DPH - push b - push ar2 - push ar3 - push ar4 - push ar5 - push ar6 - push ar7 - push ar0 - push ar1 - push PSW - _endasm; - PSW = 0; - _asm - push _bp - _endasm; - - if (ao_cur_task_index == AO_NO_TASK_INDEX) - ao_cur_task_index = ao_num_tasks-1; - else - { - uint8_t stack_len; - __data uint8_t *stack_ptr; - __xdata uint8_t *save_ptr; - /* Save the current stack */ - stack_len = SP - (AO_STACK_START - 1); - ao_cur_task->stack_count = stack_len; - stack_ptr = (uint8_t __data *) AO_STACK_START; - save_ptr = (uint8_t __xdata *) ao_cur_task->stack; - do - *save_ptr++ = *stack_ptr++; - while (--stack_len); - } - - /* Empty the stack; might as well let interrupts have the whole thing */ - SP = AO_STACK_START - 1; - - /* Find a task to run. If there isn't any runnable task, - * this loop will run forever, which is just fine - */ - { - __pdata uint8_t ao_next_task_index = ao_cur_task_index; - for (;;) { - ++ao_next_task_index; - if (ao_next_task_index == ao_num_tasks) - ao_next_task_index = 0; - - ao_cur_task = ao_tasks[ao_next_task_index]; - if (ao_cur_task->wchan == NULL) { - ao_cur_task_index = ao_next_task_index; - break; - } - - /* Check if the alarm is set for a time which has passed */ - if (ao_cur_task->alarm && - (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) { - ao_cur_task_index = ao_next_task_index; - break; - } - - /* Enter lower power mode when there isn't anything to do */ - if (ao_next_task_index == ao_cur_task_index) - PCON = PCON_IDLE; - } - } - - { - uint8_t stack_len; - __data uint8_t *stack_ptr; - __xdata uint8_t *save_ptr; - - /* Restore the old stack */ - stack_len = ao_cur_task->stack_count; - SP = AO_STACK_START - 1 + stack_len; - - stack_ptr = (uint8_t __data *) AO_STACK_START; - save_ptr = (uint8_t __xdata *) ao_cur_task->stack; - do - *stack_ptr++ = *save_ptr++; - while (--stack_len); - } - - _asm - pop _bp - pop PSW - pop ar1 - pop ar0 - pop ar7 - pop ar6 - pop ar5 - pop ar4 - pop ar3 - pop ar2 - pop b - pop DPH - pop DPL - /* The next byte of the stack is the IE register. Only the global - enable bit forms part of the task context. Pop off the IE then set - the global enable bit to match that of the stored IE register. */ - pop ACC - JB ACC.7,0098$ - CLR _EA - LJMP 0099$ - 0098$: - SETB _EA - 0099$: - /* Finally pop off the ACC, which was the first register saved. */ - pop ACC - ret - _endasm; -} - -uint8_t -ao_sleep(__xdata void *wchan) -{ - __critical { - ao_cur_task->wchan = wchan; - } - ao_yield(); - ao_cur_task->alarm = 0; - if (ao_cur_task->wchan) { - ao_cur_task->wchan = NULL; - return 1; - } - return 0; -} - -void -ao_wakeup(__xdata void *wchan) -{ - uint8_t i; - - for (i = 0; i < ao_num_tasks; i++) - if (ao_tasks[i]->wchan == wchan) - ao_tasks[i]->wchan = NULL; -} - -void -ao_alarm(uint16_t delay) -{ - /* Make sure we sleep *at least* delay ticks, which means adding - * one to account for the fact that we may be close to the next tick - */ - if (!(ao_cur_task->alarm = ao_time() + delay + 1)) - ao_cur_task->alarm = 1; -} - -void -ao_exit(void) __critical -{ - uint8_t i; - ao_num_tasks--; - for (i = ao_cur_task_index; i < ao_num_tasks; i++) - ao_tasks[i] = ao_tasks[i+1]; - ao_cur_task_index = AO_NO_TASK_INDEX; - ao_yield(); - /* we'll never get back here */ -} - -void -ao_task_info(void) -{ - uint8_t i; - uint8_t pc_loc; - __xdata struct ao_task *task; - - for (i = 0; i < ao_num_tasks; i++) { - task = ao_tasks[i]; - pc_loc = task->stack_count - 17; - printf("%12s: wchan %04x pc %04x\n", - task->name, - (int16_t) task->wchan, - (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8)); - } -} - -void -ao_start_scheduler(void) -{ - ao_cur_task_index = AO_NO_TASK_INDEX; - ao_cur_task = NULL; - ao_yield(); -} diff --git a/src/ao_telebt.c b/src/ao_telebt.c deleted file mode 100644 index 85565172..00000000 --- a/src/ao_telebt.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" - -__code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - ao_timer_init(); -#if HAS_BEEP - ao_beep_init(); -#endif - ao_cmd_init(); -#if HAS_EEPROM - ao_spi_init(); - ao_storage_init(); -#endif - ao_usb_init(); - ao_monitor_init(AO_LED_GREEN, TRUE); - ao_rssi_init(AO_LED_RED); - ao_radio_init(); - ao_packet_master_init(); - ao_btm_init(); -#if HAS_DBG - ao_dbg_init(); -#endif - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_teledongle.c b/src/ao_teledongle.c deleted file mode 100644 index 008b200a..00000000 --- a/src/ao_teledongle.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - ao_timer_init(); - ao_cmd_init(); - ao_usb_init(); - ao_monitor_init(AO_LED_GREEN, TRUE); - ao_rssi_init(AO_LED_RED); - ao_radio_init(); - ao_packet_master_init(); -#if HAS_DBG - ao_dbg_init(); -#endif - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_telem.h b/src/ao_telem.h deleted file mode 100644 index 1a8da291..00000000 --- a/src/ao_telem.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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. - */ - -#ifndef _AO_TELEM_H_ -#define _AO_TELEM_H_ - -#define AO_TELEMETRY_VERSION 4 - -/* - * Telemetry version 4 and higher format: - * - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - */ - -#define AO_TELEM_VERSION "VERSION" -#define AO_TELEM_CALL "c" -#define AO_TELEM_SERIAL "n" -#define AO_TELEM_FLIGHT "f" -#define AO_TELEM_RSSI "r" -#define AO_TELEM_STATE "s" -#define AO_TELEM_TICK "t" - -/* - * Raw sensor values - * - * Name Value - * r_a Accelerometer reading (integer) - * r_b Barometer reading (integer) - * r_t Thermometer reading (integer) - * r_v Battery reading (integer) - * r_d Drogue continuity (integer) - * r_m Main continuity (integer) - */ - -#define AO_TELEM_RAW_ACCEL "r_a" -#define AO_TELEM_RAW_BARO "r_b" -#define AO_TELEM_RAW_THERMO "r_t" -#define AO_TELEM_RAW_BATT "r_v" -#define AO_TELEM_RAW_DROGUE "r_d" -#define AO_TELEM_RAW_MAIN "r_m" - -/* - * Sensor calibration values - * - * Name Value - * c_a Ground accelerometer reading (integer) - * c_b Ground barometer reading (integer) - * c_p Accelerometer reading for +1g - * c_m Accelerometer reading for -1g - */ - -#define AO_TELEM_CAL_ACCEL_GROUND "c_a" -#define AO_TELEM_CAL_BARO_GROUND "c_b" -#define AO_TELEM_CAL_ACCEL_PLUS "c_p" -#define AO_TELEM_CAL_ACCEL_MINUS "c_m" - -/* - * Kalman state values - * - * Name Value - * k_h Height above pad (integer, meters) - * k_s Vertical speeed (integer, m/s * 16) - * k_a Vertical acceleration (integer, m/s² * 16) - */ - -#define AO_TELEM_KALMAN_HEIGHT "k_h" -#define AO_TELEM_KALMAN_SPEED "k_s" -#define AO_TELEM_KALMAN_ACCEL "k_a" - -/* - * Ad-hoc flight values - * - * Name Value - * a_a Acceleration (integer, sensor units) - * a_s Speed (integer, integrated acceleration value) - * a_b Barometer reading (integer, sensor units) - */ - -#define AO_TELEM_ADHOC_ACCEL "a_a" -#define AO_TELEM_ADHOC_SPEED "a_s" -#define AO_TELEM_ADHOC_BARO "a_b" - -/* - * GPS values - * - * Name Value - * g GPS state (string): - * l locked - * u unlocked - * e error (missing or broken) - * g_n Number of sats used in solution - * g_ns Latitude (degrees * 10e7) - * g_ew Longitude (degrees * 10e7) - * g_a Altitude (integer meters) - * g_Y GPS year (integer) - * g_M GPS month (integer - 1-12) - * g_D GPS day (integer - 1-31) - * g_h GPS hour (integer - 0-23) - * g_m GPS minute (integer - 0-59) - * g_s GPS second (integer - 0-59) - * g_v GPS vertical speed (integer, cm/sec) - * g_g GPS horizontal speed (integer, cm/sec) - * g_c GPS course (integer, 0-359) - * g_hd GPS hdop (integer * 10) - * g_vd GPS vdop (integer * 10) - * g_he GPS h error (integer) - * g_ve GPS v error (integer) - */ - -#define AO_TELEM_GPS_STATE "g" -#define AO_TELEM_GPS_STATE_LOCKED 'l' -#define AO_TELEM_GPS_STATE_UNLOCKED 'u' -#define AO_TELEM_GPS_STATE_ERROR 'e' -#define AO_TELEM_GPS_NUM_SAT "g_n" -#define AO_TELEM_GPS_LATITUDE "g_ns" -#define AO_TELEM_GPS_LONGITUDE "g_ew" -#define AO_TELEM_GPS_ALTITUDE "g_a" -#define AO_TELEM_GPS_YEAR "g_Y" -#define AO_TELEM_GPS_MONTH "g_M" -#define AO_TELEM_GPS_DAY "g_D" -#define AO_TELEM_GPS_HOUR "g_h" -#define AO_TELEM_GPS_MINUTE "g_m" -#define AO_TELEM_GPS_SECOND "g_s" -#define AO_TELEM_GPS_VERTICAL_SPEED "g_v" -#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_g" -#define AO_TELEM_GPS_COURSE "g_c" -#define AO_TELEM_GPS_HDOP "g_hd" -#define AO_TELEM_GPS_VDOP "g_vd" -#define AO_TELEM_GPS_HERROR "g_he" -#define AO_TELEM_GPS_VERROR "g_ve" - -/* - * GPS satellite values - * - * Name Value - * s_n Number of satellites reported (integer) - * s_v0 Space vehicle ID (integer) for report 0 - * s_c0 C/N0 number (integer) for report 0 - * s_v1 Space vehicle ID (integer) for report 1 - * s_c1 C/N0 number (integer) for report 1 - * ... - */ - -#define AO_TELEM_SAT_NUM "s_n" -#define AO_TELEM_SAT_SVID "s_v" -#define AO_TELEM_SAT_C_N_0 "s_c" - -#endif /* _AO_TELEM_H_ */ diff --git a/src/ao_telemetrum.c b/src/ao_telemetrum.c deleted file mode 100644 index f560740a..00000000 --- a/src/ao_telemetrum.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "ao_pins.h" - -void -main(void) -{ - /* - * Reduce the transient on the ignite pins at startup by - * pulling the pins low as soon as possible at power up - */ - ao_ignite_set_pins(); - - ao_clock_init(); - - /* Turn on the red LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - - /* A hack -- look at the SPI clock pin, if it's sitting at - * ground, then we force the computer to idle mode instead of - * flight mode - */ - if (P1_3 == 0) { - ao_flight_force_idle = 1; - while (P1_3 == 0) - ; - } - ao_timer_init(); - ao_adc_init(); - ao_beep_init(); - ao_cmd_init(); - ao_spi_init(); - ao_storage_init(); - ao_flight_init(); - ao_log_init(); - ao_report_init(); - ao_usb_init(); - ao_serial_init(); - ao_gps_init(); - ao_gps_report_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_packet_slave_init(TRUE); - ao_igniter_init(); -#if HAS_DBG - ao_dbg_init(); -#endif -#if HAS_COMPANION - ao_companion_init(); -#endif - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c deleted file mode 100644 index c7338a58..00000000 --- a/src/ao_telemetry.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" -#include "ao_product.h" - -static __pdata uint16_t ao_telemetry_interval; -static __pdata int8_t ao_telemetry_config_max; -static __pdata int8_t ao_telemetry_config_cur; -#if HAS_GPS -static __pdata int8_t ao_telemetry_loc_cur; -static __pdata int8_t ao_telemetry_sat_cur; -#endif -#if HAS_COMPANION -static __pdata int8_t ao_telemetry_companion_max; -static __pdata int8_t ao_telemetry_companion_cur; -#endif -static __pdata uint8_t ao_rdf = 0; -static __pdata uint16_t ao_rdf_time; - -#define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5) -#define AO_RDF_LENGTH_MS 500 - -#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) -#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM -#endif - -#if defined(TELEMINI_V_1_0) -#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMINI -#endif - -#if defined(TELENANO_V_0_1) -#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELENANO -#endif - -static __xdata union ao_telemetry_all telemetry; - -/* Send sensor packet */ -static void -ao_send_sensor(void) -{ - uint8_t sample; - sample = ao_sample_adc; - - telemetry.generic.tick = ao_adc_ring[sample].tick; - telemetry.generic.type = AO_TELEMETRY_SENSOR; - - telemetry.sensor.state = ao_flight_state; -#if HAS_ACCEL - telemetry.sensor.accel = ao_adc_ring[sample].accel; -#else - telemetry.sensor.accel = 0; -#endif - telemetry.sensor.pres = ao_adc_ring[sample].pres; - telemetry.sensor.temp = ao_adc_ring[sample].temp; - telemetry.sensor.v_batt = ao_adc_ring[sample].v_batt; -#if HAS_IGNITE - telemetry.sensor.sense_d = ao_adc_ring[sample].sense_d; - telemetry.sensor.sense_m = ao_adc_ring[sample].sense_m; -#else - telemetry.sensor.sense_d = 0; - telemetry.sensor.sense_m = 0; -#endif - - telemetry.sensor.acceleration = ao_accel; - telemetry.sensor.speed = ao_speed; - telemetry.sensor.height = ao_height; - - telemetry.sensor.ground_pres = ao_ground_pres; -#if HAS_ACCEL - telemetry.sensor.ground_accel = ao_ground_accel; - telemetry.sensor.accel_plus_g = ao_config.accel_plus_g; - telemetry.sensor.accel_minus_g = ao_config.accel_minus_g; -#else - telemetry.sensor.ground_accel = 0; - telemetry.sensor.accel_plus_g = 0; - telemetry.sensor.accel_minus_g = 0; -#endif - - ao_radio_send(&telemetry, sizeof (telemetry)); -} - -static void -ao_send_configuration(void) -{ - if (--ao_telemetry_config_cur <= 0) - { - telemetry.generic.type = AO_TELEMETRY_CONFIGURATION; - telemetry.configuration.device = AO_idProduct_NUMBER; - telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number; - telemetry.configuration.config_major = AO_CONFIG_MAJOR; - telemetry.configuration.config_minor = AO_CONFIG_MINOR; - telemetry.configuration.apogee_delay = ao_config.apogee_delay; - telemetry.configuration.main_deploy = ao_config.main_deploy; - telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10; - memcpy (telemetry.configuration.callsign, - ao_config.callsign, - AO_MAX_CALLSIGN); - memcpy (telemetry.configuration.version, - ao_version, - AO_MAX_VERSION); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_config_cur = ao_telemetry_config_max; - } -} - -#if HAS_GPS -static void -ao_send_location(void) -{ - if (--ao_telemetry_loc_cur <= 0) - { - telemetry.generic.type = AO_TELEMETRY_LOCATION; - ao_mutex_get(&ao_gps_mutex); - memcpy(&telemetry.location.flags, - &ao_gps_data.flags, - 26); - ao_mutex_put(&ao_gps_mutex); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_loc_cur = ao_telemetry_config_max; - } -} - -static void -ao_send_satellite(void) -{ - if (--ao_telemetry_sat_cur <= 0) - { - telemetry.generic.type = AO_TELEMETRY_SATELLITE; - ao_mutex_get(&ao_gps_mutex); - telemetry.satellite.channels = ao_gps_tracking_data.channels; - memcpy(&telemetry.satellite.sats, - &ao_gps_tracking_data.sats, - AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info)); - ao_mutex_put(&ao_gps_mutex); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_sat_cur = ao_telemetry_config_max; - } -} -#endif - -#if HAS_COMPANION -static void -ao_send_companion(void) -{ - if (--ao_telemetry_companion_cur <= 0) { - telemetry.generic.type = AO_TELEMETRY_COMPANION; - telemetry.companion.board_id = ao_companion_setup.board_id; - telemetry.companion.update_period = ao_companion_setup.update_period; - telemetry.companion.channels = ao_companion_setup.channels; - ao_mutex_get(&ao_companion_mutex); - memcpy(&telemetry.companion.companion_data, - ao_companion_data, - ao_companion_setup.channels * 2); - ao_mutex_put(&ao_companion_mutex); - ao_radio_send(&telemetry, sizeof (telemetry)); - ao_telemetry_companion_cur = ao_telemetry_companion_max; - } -} -#endif - -void -ao_telemetry(void) -{ - uint16_t time; - int16_t delay; - - ao_config_get(); - if (!ao_config.radio_enable) - ao_exit(); - while (!ao_flight_number) - ao_sleep(&ao_flight_number); - - telemetry.generic.serial = ao_serial_number; - for (;;) { - while (ao_telemetry_interval == 0) - ao_sleep(&telemetry); - time = ao_rdf_time = ao_time(); - while (ao_telemetry_interval) { - - - ao_send_sensor(); -#if HAS_COMPANION - if (ao_companion_running) - ao_send_companion(); -#endif - ao_send_configuration(); -#if HAS_GPS - ao_send_location(); - ao_send_satellite(); -#endif - if (ao_rdf && - (int16_t) (ao_time() - ao_rdf_time) >= 0) - { - ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS; - ao_radio_rdf(AO_RDF_LENGTH_MS); - } - time += ao_telemetry_interval; - delay = time - ao_time(); - if (delay > 0) - ao_delay(delay); - else - time = ao_time(); - } - } -} - -void -ao_telemetry_set_interval(uint16_t interval) -{ - ao_telemetry_interval = interval; - -#if HAS_COMPANION - if (!ao_companion_setup.update_period) - ao_companion_setup.update_period = AO_SEC_TO_TICKS(1); - ao_telemetry_companion_max = ao_companion_setup.update_period / interval; - ao_telemetry_companion_cur = 1; -#endif - - ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval; -#if HAS_COMPANION - ao_telemetry_config_cur = ao_telemetry_companion_cur; - if (ao_telemetry_config_max > ao_telemetry_config_cur) - ao_telemetry_config_cur++; -#else - ao_telemetry_config_cur = 1; -#endif - -#if HAS_GPS - ao_telemetry_loc_cur = ao_telemetry_config_cur; - if (ao_telemetry_config_max > ao_telemetry_loc_cur) - ao_telemetry_loc_cur++; - ao_telemetry_sat_cur = ao_telemetry_loc_cur; - if (ao_telemetry_config_max > ao_telemetry_sat_cur) - ao_telemetry_sat_cur++; -#endif - ao_wakeup(&telemetry); -} - -void -ao_rdf_set(uint8_t rdf) -{ - ao_rdf = rdf; - if (rdf == 0) - ao_radio_rdf_abort(); - else - ao_rdf_time = ao_time(); -} - -__xdata struct ao_task ao_telemetry_task; - -void -ao_telemetry_init() -{ - ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry"); -} diff --git a/src/ao_telemini.c b/src/ao_telemini.c deleted file mode 100644 index fa23de01..00000000 --- a/src/ao_telemini.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" -#include "ao_pins.h" - -void -main(void) -{ - /* - * Reduce the transient on the ignite pins at startup by - * pulling the pins low as soon as possible at power up - */ - ao_ignite_set_pins(); - - ao_clock_init(); - - /* Turn on the red LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - - ao_timer_init(); - ao_adc_init(); - ao_cmd_init(); - ao_storage_init(); - ao_flight_init(); - ao_log_init(); - ao_report_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_packet_slave_init(TRUE); - ao_igniter_init(); - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_telenano.c b/src/ao_telenano.c deleted file mode 100644 index d91983d0..00000000 --- a/src/ao_telenano.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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 "ao.h" -#include "ao_pins.h" - -void -main(void) -{ - ao_clock_init(); - - - /* Turn on the red LED until the system is stable */ - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_RED); - - ao_timer_init(); - ao_adc_init(); - ao_cmd_init(); - ao_storage_init(); - ao_flight_nano_init(); - ao_log_init(); - ao_report_init(); - ao_telemetry_init(); - ao_radio_init(); - ao_packet_slave_init(TRUE); - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_teleterra.c b/src/ao_teleterra.c deleted file mode 100644 index d696b914..00000000 --- a/src/ao_teleterra.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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_NO_ADC_ISR 1 -#include "ao.h" - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the red LED until the system is stable */ - ao_led_init(AO_LED_RED|AO_LED_GREEN); - ao_led_on(AO_LED_RED); - ao_timer_init(); - ao_beep_init(); - ao_cmd_init(); - ao_usb_init(); - ao_serial_init(); - ao_monitor_init(AO_LED_GREEN, TRUE); - ao_radio_init(); - ao_config_init(); - ao_start_scheduler(); -} diff --git a/src/ao_test.c b/src/ao_test.c deleted file mode 100644 index 14c2eb75..00000000 --- a/src/ao_test.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -struct ao_task __xdata blink_0_task; -struct ao_task __xdata blink_1_task; -struct ao_task __xdata wakeup_task; -struct ao_task __xdata beep_task; -struct ao_task __xdata echo_task; - -void delay(int n) __reentrant -{ - uint8_t j = 0; - while (--n) - while (--j) - ao_yield(); -} - -static __xdata uint8_t blink_chan; - -void -blink_0(void) -{ - uint8_t b = 0; - for (;;) { - b = 1 - b; - if (b) - ao_led_on(AO_LED_GREEN); - else - ao_led_off(AO_LED_GREEN); - ao_sleep(&blink_chan); - } -} - -void -blink_1(void) -{ - static __xdata struct ao_adc adc; - - for (;;) { - ao_sleep(&ao_adc_head); - ao_adc_get(&adc); - if (adc.accel < 15900) - ao_led_on(AO_LED_RED); - else - ao_led_off(AO_LED_RED); - } -} - -void -wakeup(void) -{ - for (;;) { - ao_delay(AO_MS_TO_TICKS(100)); - ao_wakeup(&blink_chan); - } -} - -void -beep(void) -{ - static __xdata struct ao_adc adc; - - for (;;) { - ao_delay(AO_SEC_TO_TICKS(1)); - ao_adc_get(&adc); - if (adc.temp > 7400) - ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(50)); - } -} - -void -echo(void) -{ - char c; - for (;;) { - ao_usb_flush(); - c = ao_usb_getchar(); - ao_usb_putchar(c); - if (c == '\r') - ao_usb_putchar('\n'); - } -} - -void -main(void) -{ - ao_clock_init(); - -// ao_add_task(&blink_0_task, blink_0); -// ao_add_task(&blink_1_task, blink_1); -// ao_add_task(&wakeup_task, wakeup); -// ao_add_task(&beep_task, beep); - ao_add_task(&echo_task, echo); - ao_timer_init(); - ao_adc_init(); - ao_beep_init(); - ao_led_init(); - ao_usb_init(); - - ao_start_scheduler(); -} diff --git a/src/ao_tidongle.c b/src/ao_tidongle.c deleted file mode 100644 index 3b7c2733..00000000 --- a/src/ao_tidongle.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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_NO_SERIAL_ISR 1 -#define AO_NO_ADC_ISR 1 -#include "ao.h" - -void -main(void) -{ - ao_clock_init(); - - /* Turn on the LED until the system is stable */ - ao_led_init(AO_LED_RED); - ao_led_on(AO_LED_RED); - ao_timer_init(); - ao_cmd_init(); - ao_usb_init(); - ao_monitor_init(AO_LED_RED, TRUE); - ao_rssi_init(AO_LED_RED); - ao_radio_init(); - ao_dbg_init(); - ao_config_init(); - /* Bring up the USB link */ - P1DIR |= 1; - P1 |= 1; - ao_start_scheduler(); -} diff --git a/src/ao_timer.c b/src/ao_timer.c deleted file mode 100644 index c977fbc8..00000000 --- a/src/ao_timer.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -static volatile __data uint16_t ao_tick_count; - -uint16_t ao_time(void) __critical -{ - return ao_tick_count; -} - -static __xdata uint8_t ao_forever; - -void -ao_delay(uint16_t ticks) -{ - ao_alarm(ticks); - ao_sleep(&ao_forever); -} - -#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ -#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ - -#if HAS_ADC -volatile __data uint8_t ao_adc_interval = 1; -volatile __data uint8_t ao_adc_count; -#endif - -void ao_timer_isr(void) __interrupt 9 -{ - ++ao_tick_count; -#if HAS_ADC - if (++ao_adc_count == ao_adc_interval) { - ao_adc_count = 0; - ao_adc_poll(); - } -#endif -} - -#if HAS_ADC -void -ao_timer_set_adc_interval(uint8_t interval) __critical -{ - ao_adc_interval = interval; - ao_adc_count = 0; -} -#endif - -void -ao_timer_init(void) -{ - /* NOTE: This uses a timer only present on cc1111 architecture. */ - - /* disable timer 1 */ - T1CTL = 0; - - /* set the sample rate */ - T1CC0H = T1_SAMPLE_TIME >> 8; - T1CC0L = (uint8_t) T1_SAMPLE_TIME; - - T1CCTL0 = T1CCTL_MODE_COMPARE; - T1CCTL1 = 0; - T1CCTL2 = 0; - - /* clear timer value */ - T1CNTL = 0; - - /* enable overflow interrupt */ - OVFIM = 1; - /* enable timer 1 interrupt */ - T1IE = 1; - - /* enable timer 1 in module mode, dividing by 8 */ - T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8; -} - -/* - * AltOS always cranks the clock to the max frequency - */ -void -ao_clock_init(void) -{ - /* Switch system clock to crystal oscilator */ - CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL); - - while (!(SLEEP & SLEEP_XOSC_STB)) - ; - - /* Crank up the timer tick and system clock speed */ - CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) | - (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)); - - while ((CLKCON & (CLKCON_TICKSPD_MASK|CLKCON_CLKSPD_MASK)) != - (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)) - ; -} diff --git a/src/ao_usb.c b/src/ao_usb.c deleted file mode 100644 index 08cb7390..00000000 --- a/src/ao_usb.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" -#include "ao_usb.h" - -struct ao_task __xdata ao_usb_task; - -static __xdata uint16_t ao_usb_in_bytes; -static __pdata uint16_t ao_usb_in_bytes_last; -static __xdata uint16_t ao_usb_out_bytes; -static __pdata uint8_t ao_usb_iif; -static __pdata uint8_t ao_usb_running; - -static void -ao_usb_set_interrupts(void) -{ - /* IN interrupts on the control an IN endpoints */ - USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP); - - /* OUT interrupts on the OUT endpoint */ - USBOIE = (1 << AO_USB_OUT_EP); - - /* Only care about reset */ - USBCIE = USBCIE_RSTIE; -} - -/* This interrupt is shared with port 2, - * so when we hook that up, fix this - */ -void -ao_usb_isr(void) __interrupt 6 -{ - USBIF = 0; - ao_usb_iif |= USBIIF; - if (ao_usb_iif & 1) - ao_wakeup(&ao_usb_task); - if (ao_usb_iif & (1 << AO_USB_IN_EP)) - ao_wakeup(&ao_usb_in_bytes); - - if (USBOIF & (1 << AO_USB_OUT_EP)) - ao_wakeup(&ao_stdin_ready); - - if (USBCIF & USBCIF_RSTIF) - ao_usb_set_interrupts(); -#if HAS_BTM -#if BT_LINK_ON_P2 - ao_btm_isr(); -#endif -#endif -} - -struct ao_usb_setup { - uint8_t dir_type_recip; - uint8_t request; - uint16_t value; - uint16_t index; - uint16_t length; -} __xdata ao_usb_setup; - -__pdata uint8_t ao_usb_ep0_state; -uint8_t * __pdata ao_usb_ep0_in_data; -__pdata uint8_t ao_usb_ep0_in_len; -__pdata uint8_t ao_usb_ep0_in_buf[2]; -__pdata uint8_t ao_usb_ep0_out_len; -__xdata uint8_t *__pdata ao_usb_ep0_out_data; -__pdata uint8_t ao_usb_configuration; - -/* Send an IN data packet */ -static void -ao_usb_ep0_flush(void) -{ - __pdata uint8_t this_len; - __pdata uint8_t cs0; - - /* If the IN packet hasn't been picked up, just return */ - USBINDEX = 0; - cs0 = USBCS0; - if (cs0 & USBCS0_INPKT_RDY) - return; - - this_len = ao_usb_ep0_in_len; - if (this_len > AO_USB_CONTROL_SIZE) - this_len = AO_USB_CONTROL_SIZE; - cs0 = USBCS0_INPKT_RDY; - if (this_len != AO_USB_CONTROL_SIZE) { - cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END; - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } - ao_usb_ep0_in_len -= this_len; - while (this_len--) - USBFIFO[0] = *ao_usb_ep0_in_data++; - USBINDEX = 0; - USBCS0 = cs0; -} - -__xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; - -/* Walk through the list of descriptors and find a match - */ -static void -ao_usb_get_descriptor(uint16_t value) -{ - __code uint8_t *__pdata descriptor; - __pdata uint8_t type = value >> 8; - __pdata uint8_t index = value; - - descriptor = ao_usb_descriptors; - while (descriptor[0] != 0) { - if (descriptor[1] == type && index-- == 0) { - if (type == AO_USB_DESC_CONFIGURATION) - ao_usb_ep0_in_len = descriptor[2]; - else - ao_usb_ep0_in_len = descriptor[0]; - ao_usb_ep0_in_data = descriptor; - break; - } - descriptor += descriptor[0]; - } -} - -/* Read data from the ep0 OUT fifo - */ -static void -ao_usb_ep0_fill(void) -{ - __pdata uint8_t len; - - USBINDEX = 0; - len = USBCNT0; - if (len > ao_usb_ep0_out_len) - len = ao_usb_ep0_out_len; - ao_usb_ep0_out_len -= len; - while (len--) - *ao_usb_ep0_out_data++ = USBFIFO[0]; -} - -void -ao_usb_ep0_queue_byte(uint8_t a) -{ - ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; -} - -void -ao_usb_set_address(uint8_t address) -{ - ao_usb_running = 1; - USBADDR = address | 0x80; - while (USBADDR & 0x80) - ; -} - -static void -ao_usb_set_configuration(void) -{ - /* Set the IN max packet size, double buffered */ - USBINDEX = AO_USB_IN_EP; - USBMAXI = AO_USB_IN_SIZE >> 3; - USBCSIH |= USBCSIH_IN_DBL_BUF; - - /* Set the OUT max packet size, double buffered */ - USBINDEX = AO_USB_OUT_EP; - USBMAXO = AO_USB_OUT_SIZE >> 3; - USBCSOH = USBCSOH_OUT_DBL_BUF; -} - -static void -ao_usb_ep0_setup(void) -{ - /* Pull the setup packet out of the fifo */ - ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup; - ao_usb_ep0_out_len = 8; - ao_usb_ep0_fill(); - if (ao_usb_ep0_out_len != 0) - return; - - /* Figure out how to ACK the setup packet */ - if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) { - if (ao_usb_setup.length) - ao_usb_ep0_state = AO_USB_EP0_DATA_IN; - else - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } else { - if (ao_usb_setup.length) - ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; - else - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } - USBINDEX = 0; - if (ao_usb_ep0_state == AO_USB_EP0_IDLE) - USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; - else - USBCS0 = USBCS0_CLR_OUTPKT_RDY; - - ao_usb_ep0_in_data = ao_usb_ep0_in_buf; - ao_usb_ep0_in_len = 0; - switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { - case AO_USB_TYPE_STANDARD: - switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) { - case AO_USB_RECIP_DEVICE: - switch(ao_usb_setup.request) { - case AO_USB_REQ_GET_STATUS: - ao_usb_ep0_queue_byte(0); - ao_usb_ep0_queue_byte(0); - break; - case AO_USB_REQ_SET_ADDRESS: - ao_usb_set_address(ao_usb_setup.value); - break; - case AO_USB_REQ_GET_DESCRIPTOR: - ao_usb_get_descriptor(ao_usb_setup.value); - break; - case AO_USB_REQ_GET_CONFIGURATION: - ao_usb_ep0_queue_byte(ao_usb_configuration); - break; - case AO_USB_REQ_SET_CONFIGURATION: - ao_usb_configuration = ao_usb_setup.value; - ao_usb_set_configuration(); - break; - } - break; - case AO_USB_RECIP_INTERFACE: - #pragma disable_warning 110 - switch(ao_usb_setup.request) { - case AO_USB_REQ_GET_STATUS: - ao_usb_ep0_queue_byte(0); - ao_usb_ep0_queue_byte(0); - break; - case AO_USB_REQ_GET_INTERFACE: - ao_usb_ep0_queue_byte(0); - break; - case AO_USB_REQ_SET_INTERFACE: - break; - } - break; - case AO_USB_RECIP_ENDPOINT: - switch(ao_usb_setup.request) { - case AO_USB_REQ_GET_STATUS: - ao_usb_ep0_queue_byte(0); - ao_usb_ep0_queue_byte(0); - break; - } - break; - } - break; - case AO_USB_TYPE_CLASS: - switch (ao_usb_setup.request) { - case SET_LINE_CODING: - ao_usb_ep0_out_len = 7; - ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; - break; - case GET_LINE_CODING: - ao_usb_ep0_in_len = 7; - ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; - break; - case SET_CONTROL_LINE_STATE: - break; - } - break; - } - if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) { - if (ao_usb_setup.length < ao_usb_ep0_in_len) - ao_usb_ep0_in_len = ao_usb_setup.length; - ao_usb_ep0_flush(); - } -} - -/* End point 0 receives all of the control messages. */ -static void -ao_usb_ep0(void) -{ - __pdata uint8_t cs0; - - ao_usb_ep0_state = AO_USB_EP0_IDLE; - for (;;) { - __critical for (;;) { - if (ao_usb_iif & 1) { - ao_usb_iif &= ~1; - break; - } - ao_sleep(&ao_usb_task); - } - USBINDEX = 0; - cs0 = USBCS0; - if (cs0 & USBCS0_SETUP_END) { - ao_usb_ep0_state = AO_USB_EP0_IDLE; - USBCS0 = USBCS0_CLR_SETUP_END; - } - if (cs0 & USBCS0_SENT_STALL) { - ao_usb_ep0_state = AO_USB_EP0_IDLE; - USBCS0 &= ~USBCS0_SENT_STALL; - } - if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN && - (cs0 & USBCS0_INPKT_RDY) == 0) - { - ao_usb_ep0_flush(); - } - if (cs0 & USBCS0_OUTPKT_RDY) { - switch (ao_usb_ep0_state) { - case AO_USB_EP0_IDLE: - ao_usb_ep0_setup(); - break; - case AO_USB_EP0_DATA_OUT: - ao_usb_ep0_fill(); - if (ao_usb_ep0_out_len == 0) - ao_usb_ep0_state = AO_USB_EP0_IDLE; - USBINDEX = 0; - if (ao_usb_ep0_state == AO_USB_EP0_IDLE) - USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; - else - USBCS0 = USBCS0_CLR_OUTPKT_RDY; - break; - } - } - } -} - -/* Wait for a free IN buffer */ -static void -ao_usb_in_wait(void) -{ - for (;;) { - USBINDEX = AO_USB_IN_EP; - if ((USBCSIL & USBCSIL_INPKT_RDY) == 0) - break; - ao_sleep(&ao_usb_in_bytes); - } -} - -/* Send the current IN packet */ -static void -ao_usb_in_send(void) -{ - USBINDEX = AO_USB_IN_EP; - USBCSIL |= USBCSIL_INPKT_RDY; - ao_usb_in_bytes_last = ao_usb_in_bytes; - ao_usb_in_bytes = 0; -} - -void -ao_usb_flush(void) __critical -{ - if (!ao_usb_running) - return; - - /* If there are pending bytes, or if the last packet was full, - * send another IN packet - */ - if (ao_usb_in_bytes || (ao_usb_in_bytes_last == AO_USB_IN_SIZE)) { - ao_usb_in_wait(); - ao_usb_in_send(); - } -} - -void -ao_usb_putchar(char c) __critical __reentrant -{ - if (!ao_usb_running) - return; - - ao_usb_in_wait(); - - /* Queue a byte, sending the packet when full */ - USBFIFO[AO_USB_IN_EP << 1] = c; - if (++ao_usb_in_bytes == AO_USB_IN_SIZE) - ao_usb_in_send(); -} - -char -ao_usb_pollchar(void) __critical -{ - char c; - if (ao_usb_out_bytes == 0) { - USBINDEX = AO_USB_OUT_EP; - if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) - return AO_READ_AGAIN; - ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL; - if (ao_usb_out_bytes == 0) { - USBINDEX = AO_USB_OUT_EP; - USBCSOL &= ~USBCSOL_OUTPKT_RDY; - return AO_READ_AGAIN; - } - } - --ao_usb_out_bytes; - c = USBFIFO[AO_USB_OUT_EP << 1]; - if (ao_usb_out_bytes == 0) { - USBINDEX = AO_USB_OUT_EP; - USBCSOL &= ~USBCSOL_OUTPKT_RDY; - } - return c; -} - -char -ao_usb_getchar(void) __critical -{ - char c; - - while ((c = ao_usb_pollchar()) == AO_READ_AGAIN) - ao_sleep(&ao_stdin_ready); - return c; -} - -void -ao_usb_enable(void) -{ - /* Turn on the USB controller */ - SLEEP |= SLEEP_USB_EN; - - ao_usb_set_configuration(); - - ao_usb_set_interrupts(); - - /* enable USB interrupts */ - IEN2 |= IEN2_USBIE; - - /* Clear any pending interrupts */ - USBCIF = 0; - USBOIF = 0; - USBIIF = 0; -} - -void -ao_usb_disable(void) -{ - /* Disable USB interrupts */ - USBIIE = 0; - USBOIE = 0; - USBCIE = 0; - IEN2 &= ~IEN2_USBIE; - - /* Clear any pending interrupts */ - USBCIF = 0; - USBOIF = 0; - USBIIF = 0; - - /* Turn off the USB controller */ - SLEEP &= ~SLEEP_USB_EN; -} - -void -ao_usb_init(void) -{ - ao_usb_enable(); - - ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); - ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); -} diff --git a/src/ao_usb.h b/src/ao_usb.h deleted file mode 100644 index 6633dafc..00000000 --- a/src/ao_usb.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef _AO_USB_H_ -#define _AO_USB_H_ - -#define AO_USB_SETUP_DIR_MASK (0x01 << 7) -#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) -#define AO_USB_SETUP_RECIP_MASK (0x1f) - -#define AO_USB_DIR_OUT 0 -#define AO_USB_DIR_IN (1 << 7) - -#define AO_USB_TYPE_STANDARD 0 -#define AO_USB_TYPE_CLASS (1 << 5) -#define AO_USB_TYPE_VENDOR (2 << 5) -#define AO_USB_TYPE_RESERVED (3 << 5) - -#define AO_USB_RECIP_DEVICE 0 -#define AO_USB_RECIP_INTERFACE 1 -#define AO_USB_RECIP_ENDPOINT 2 -#define AO_USB_RECIP_OTHER 3 - -/* standard requests */ -#define AO_USB_REQ_GET_STATUS 0x00 -#define AO_USB_REQ_CLEAR_FEATURE 0x01 -#define AO_USB_REQ_SET_FEATURE 0x03 -#define AO_USB_REQ_SET_ADDRESS 0x05 -#define AO_USB_REQ_GET_DESCRIPTOR 0x06 -#define AO_USB_REQ_SET_DESCRIPTOR 0x07 -#define AO_USB_REQ_GET_CONFIGURATION 0x08 -#define AO_USB_REQ_SET_CONFIGURATION 0x09 -#define AO_USB_REQ_GET_INTERFACE 0x0A -#define AO_USB_REQ_SET_INTERFACE 0x0B -#define AO_USB_REQ_SYNCH_FRAME 0x0C - -#define AO_USB_DESC_DEVICE 1 -#define AO_USB_DESC_CONFIGURATION 2 -#define AO_USB_DESC_STRING 3 -#define AO_USB_DESC_INTERFACE 4 -#define AO_USB_DESC_ENDPOINT 5 -#define AO_USB_DESC_DEVICE_QUALIFIER 6 -#define AO_USB_DESC_OTHER_SPEED 7 -#define AO_USB_DESC_INTERFACE_POWER 8 - -#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) -#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) - -#define AO_USB_CONTROL_EP 0 -#define AO_USB_INT_EP 1 -#define AO_USB_OUT_EP 4 -#define AO_USB_IN_EP 5 -#define AO_USB_CONTROL_SIZE 32 -/* - * Double buffer IN and OUT EPs, so each - * gets half of the available space - * - * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 - * byte sizes, so we'll use 64 for everything - */ -#define AO_USB_IN_SIZE 64 -#define AO_USB_OUT_SIZE 64 - -#define AO_USB_EP0_IDLE 0 -#define AO_USB_EP0_DATA_IN 1 -#define AO_USB_EP0_DATA_OUT 2 - -#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) - -/* CDC definitions */ -#define CS_INTERFACE 0x24 -#define CS_ENDPOINT 0x25 - -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_CONTROL_LINE_STATE 0x22 - -/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ -struct ao_usb_line_coding { - uint32_t rate; - uint8_t char_format; - uint8_t parity; - uint8_t data_bits; -} ; - -#endif /* _AO_USB_H_ */ diff --git a/src/at45db161d.h b/src/at45db161d.h deleted file mode 100644 index 9ee6f1b6..00000000 --- a/src/at45db161d.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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. - */ - -/* Defines for the Atmel AT45DB161D 16Mbit SPI Bus DataFlash® */ - -#ifndef _AT45DB161D_H_ -#define _AT45DB161D_H_ - -/* - * We reserve the last block on the device for - * configuration space. Writes and reads in this - * area return errors. - */ - - -#define FLASH_READ 0x03 -#define FLASH_WRITE 0x82 -#define FLASH_PAGE_ERASE 0x81 -#define FLASH_READ_STATUS 0xd7 -#define FLASH_SET_CONFIG 0x3d - -#define FLASH_SET_512_BYTE_0 0x2a -#define FLASH_SET_512_BYTE_1 0x80 -#define FLASH_SET_512_BYTE_2 0xa6 - -#define FLASH_STATUS_RDY (1 << 7) -#define FLASH_STATUS_COMP (1 << 6) -#define FLASH_STATUS_PROTECT (1 << 1) -#define FLASH_STATUS_PAGESIZE_512 (1 << 0) - -#endif /* _AT45DB161D_H_ */ diff --git a/src/cc1111.h b/src/cc1111.h deleted file mode 100644 index e52aa79f..00000000 --- a/src/cc1111.h +++ /dev/null @@ -1,1306 +0,0 @@ -/*------------------------------------------------------------------------- - Register Declarations for the ChipCon CC1111 Processor Range - - Copyright © 2008 Keith Packard - - 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. - - Adapted from the Cygnal C8051F12x config file which is: - - Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --------------------------------------------------------------------------*/ - -#ifndef _CC1111_H_ -#define _CC1111_H_ -#include -#include - -__sfr __at 0xA8 IEN0; /* Interrupt Enable 0 Register */ - -sbit __at 0xA8 RFTXRXIE; /* RF TX/RX done interrupt enable */ -sbit __at 0xA9 ADCIE; /* ADC interrupt enable */ -sbit __at 0xAA URX0IE; /* USART0 RX interrupt enable */ -sbit __at 0xAB URX1IE; /* USART1 RX interrupt enable (shared with I2S RX) */ -sbit __at 0xAB I2SRXIE; /* I2S RX interrupt enable (shared with USART1 RX) */ -sbit __at 0xAC ENCIE; /* AES encryption/decryption interrupt enable */ -sbit __at 0xAD STIE; /* Sleep Timer interrupt enable */ -sbit __at 0xAF EA; /* Enable All */ - -#define IEN0_EA (1 << 7) -#define IEN0_STIE (1 << 5) -#define IEN0_ENCIE (1 << 4) -#define IEN0_URX1IE (1 << 3) -#define IEN0_I2SRXIE (1 << 3) -#define IEN0_URX0IE (1 << 2) -#define IEN0_ADCIE (1 << 1) -#define IEN0_RFTXRXIE (1 << 0) - -__sfr __at 0xB8 IEN1; /* Interrupt Enable 1 Register */ - -#define IEN1_P0IE (1 << 5) /* Port 0 interrupt enable */ -#define IEN1_T4IE (1 << 4) /* Timer 4 interrupt enable */ -#define IEN1_T3IE (1 << 3) /* Timer 3 interrupt enable */ -#define IEN1_T2IE (1 << 2) /* Timer 2 interrupt enable */ -#define IEN1_T1IE (1 << 1) /* Timer 1 interrupt enable */ -#define IEN1_DMAIE (1 << 0) /* DMA transfer interrupt enable */ - -/* IEN2 */ -__sfr __at 0x9A IEN2; /* Interrupt Enable 2 Register */ - -#define IEN2_WDTIE (1 << 5) /* Watchdog timer interrupt enable */ -#define IEN2_P1IE (1 << 4) /* Port 1 interrupt enable */ -#define IEN2_UTX1IE (1 << 3) /* USART1 TX interrupt enable */ -#define IEN2_I2STXIE (1 << 3) /* I2S TX interrupt enable */ -#define IEN2_UTX0IE (1 << 2) /* USART0 TX interrupt enable */ -#define IEN2_P2IE (1 << 1) /* Port 2 interrupt enable */ -#define IEN2_USBIE (1 << 1) /* USB interrupt enable */ -#define IEN2_RFIE (1 << 0) /* RF general interrupt enable */ - -/* CLKCON 0xC6 */ -__sfr __at 0xC6 CLKCON; /* Clock Control */ - -#define CLKCON_OSC32K_RC (1 << 7) -#define CLKCON_OSC32K_XTAL (0 << 7) -#define CLKCON_OSC32K_MASK (1 << 7) -#define CLKCON_OSC_RC (1 << 6) -#define CLKCON_OSC_XTAL (0 << 6) -#define CLKCON_OSC_MASK (1 << 6) -#define CLKCON_TICKSPD_MASK (7 << 3) -# define CLKCON_TICKSPD_1 (0 << 3) -# define CLKCON_TICKSPD_1_2 (1 << 3) -# define CLKCON_TICKSPD_1_4 (2 << 3) -# define CLKCON_TICKSPD_1_8 (3 << 3) -# define CLKCON_TICKSPD_1_16 (4 << 3) -# define CLKCON_TICKSPD_1_32 (5 << 3) -# define CLKCON_TICKSPD_1_64 (6 << 3) -# define CLKCON_TICKSPD_1_128 (7 << 3) - -#define CLKCON_CLKSPD_MASK (7 << 0) -# define CLKCON_CLKSPD_1 (0 << 0) -# define CLKCON_CLKSPD_1_2 (1 << 0) -# define CLKCON_CLKSPD_1_4 (2 << 0) -# define CLKCON_CLKSPD_1_8 (3 << 0) -# define CLKCON_CLKSPD_1_16 (4 << 0) -# define CLKCON_CLKSPD_1_32 (5 << 0) -# define CLKCON_CLKSPD_1_64 (6 << 0) -# define CLKCON_CLKSPD_1_128 (7 << 0) - -/* SLEEP 0xBE */ -#define SLEEP_USB_EN (1 << 7) -#define SLEEP_XOSC_STB (1 << 6) -#define SLEEP_HFRC_STB (1 << 5) -#define SLEEP_RST_POWER (0 << 3) -#define SLEEP_RST_EXTERNAL (1 << 3) -#define SLEEP_RST_WATCHDOG (2 << 3) -#define SLEEP_RST_MASK (3 << 3) -#define SLEEP_OSC_PD (1 << 2) -#define SLEEP_MODE_PM0 (0 << 0) -#define SLEEP_MODE_PM1 (1 << 0) -#define SLEEP_MODE_PM2 (2 << 0) -#define SLEEP_MODE_PM3 (3 << 0) -#define SLEEP_MODE_MASK (3 << 0) - -/* PCON 0x87 */ -__sfr __at 0x87 PCON; /* Power Mode Control Register */ - -#define PCON_IDLE (1 << 0) - -/* - * TCON - */ -__sfr __at 0x88 TCON; /* CPU Interrupt Flag 1 */ - -sbit __at 0x8F URX1IF; /* USART1 RX interrupt flag. Automatically cleared */ -sbit __at 0x8F I2SRXIF; /* I2S RX interrupt flag. Automatically cleared */ -sbit __at 0x8D ADCIF; /* ADC interrupt flag. Automatically cleared */ -sbit __at 0x8B URX0IF; /* USART0 RX interrupt flag. Automatically cleared */ -sbit __at 0x89 RFTXRXIF; /* RF TX/RX complete interrupt flag. Automatically cleared */ - -#define TCON_URX1IF (1 << 7) -#define TCON_I2SRXIF (1 << 7) -#define TCON_ADCIF (1 << 5) -#define TCON_URX0IF (1 << 3) -#define TCON_RFTXRXIF (1 << 1) - -/* - * S0CON - */ -__sfr __at 0x98 S0CON; /* CPU Interrupt Flag 2 */ - -sbit __at 0x98 ENCIF_0; /* AES interrupt 0. */ -sbit __at 0x99 ENCIF_1; /* AES interrupt 1. */ - -#define S0CON_ENCIF_1 (1 << 1) -#define S0CON_ENCIF_0 (1 << 0) - -/* - * S1CON - */ -__sfr __at 0x9B S1CON; /* CPU Interrupt Flag 3 */ - -#define S1CON_RFIF_1 (1 << 1) -#define S1CON_RFIF_0 (1 << 0) - -/* - * IRCON - */ -__sfr __at 0xC0 IRCON; /* CPU Interrupt Flag 4 */ - -sbit __at 0xC0 DMAIF; /* DMA complete interrupt flag */ -sbit __at 0xC1 T1IF; /* Timer 1 interrupt flag. Automatically cleared */ -sbit __at 0xC2 T2IF; /* Timer 2 interrupt flag. Automatically cleared */ -sbit __at 0xC3 T3IF; /* Timer 3 interrupt flag. Automatically cleared */ -sbit __at 0xC4 T4IF; /* Timer 4 interrupt flag. Automatically cleared */ -sbit __at 0xC5 P0IF; /* Port0 interrupt flag */ -sbit __at 0xC7 STIF; /* Sleep Timer interrupt flag */ - -#define IRCON_DMAIF (1 << 0) /* DMA complete interrupt flag */ -#define IRCON_T1IF (1 << 1) /* Timer 1 interrupt flag. Automatically cleared */ -#define IRCON_T2IF (1 << 2) /* Timer 2 interrupt flag. Automatically cleared */ -#define IRCON_T3IF (1 << 3) /* Timer 3 interrupt flag. Automatically cleared */ -#define IRCON_T4IF (1 << 4) /* Timer 4 interrupt flag. Automatically cleared */ -#define IRCON_P0IF (1 << 5) /* Port0 interrupt flag */ -#define IRCON_STIF (1 << 7) /* Sleep Timer interrupt flag */ - -/* - * IRCON2 - */ -__sfr __at 0xE8 IRCON2; /* CPU Interrupt Flag 5 */ - -sbit __at 0xE8 USBIF; /* USB interrupt flag (shared with Port2) */ -sbit __at 0xE8 P2IF; /* Port2 interrupt flag (shared with USB) */ -sbit __at 0xE9 UTX0IF; /* USART0 TX interrupt flag */ -sbit __at 0xEA UTX1IF; /* USART1 TX interrupt flag (shared with I2S TX) */ -sbit __at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */ -sbit __at 0xEB P1IF; /* Port1 interrupt flag */ -sbit __at 0xEC WDTIF; /* Watchdog timer interrupt flag */ - -#define IRCON2_USBIF (1 << 0) /* USB interrupt flag (shared with Port2) */ -#define IRCON2_P2IF (1 << 0) /* Port2 interrupt flag (shared with USB) */ -#define IRCON2_UTX0IF (1 << 1) /* USART0 TX interrupt flag */ -#define IRCON2_UTX1IF (1 << 2) /* USART1 TX interrupt flag (shared with I2S TX) */ -#define IRCON2_I2STXIF (1 << 2) /* I2S TX interrupt flag (shared with USART1 TX) */ -#define IRCON2_P1IF (1 << 3) /* Port1 interrupt flag */ -#define IRCON2_WDTIF (1 << 4) /* Watchdog timer interrupt flag */ - -/* - * IP1 - Interrupt Priority 1 - */ - -/* - * Interrupt priority groups: - * - * IPG0 RFTXRX RF DMA - * IPG1 ADC T1 P2INT/USB - * IPG2 URX0 T2 UTX0 - * IPG3 URX1/I2SRX T3 UTX1 / I2STX - * IPG4 ENC T4 P1INT - * IPG5 ST P0INT WDT - * - * Priority = (IP1 << 1) | IP0. Higher priority interrupts served first - */ - -__sfr __at 0xB9 IP1; /* Interrupt Priority 1 */ -__sfr __at 0xA9 IP0; /* Interrupt Priority 0 */ - -#define IP1_IPG5 (1 << 5) -#define IP1_IPG4 (1 << 4) -#define IP1_IPG3 (1 << 3) -#define IP1_IPG2 (1 << 2) -#define IP1_IPG1 (1 << 1) -#define IP1_IPG0 (1 << 0) - -#define IP0_IPG5 (1 << 5) -#define IP0_IPG4 (1 << 4) -#define IP0_IPG3 (1 << 3) -#define IP0_IPG2 (1 << 2) -#define IP0_IPG1 (1 << 1) -#define IP0_IPG0 (1 << 0) - -/* - * Timer 1 - */ -#define T1CTL_MODE_SUSPENDED (0 << 0) -#define T1CTL_MODE_FREE (1 << 0) -#define T1CTL_MODE_MODULO (2 << 0) -#define T1CTL_MODE_UP_DOWN (3 << 0) -#define T1CTL_MODE_MASK (3 << 0) -#define T1CTL_DIV_1 (0 << 2) -#define T1CTL_DIV_8 (1 << 2) -#define T1CTL_DIV_32 (2 << 2) -#define T1CTL_DIV_128 (3 << 2) -#define T1CTL_DIV_MASK (3 << 2) -#define T1CTL_OVFIF (1 << 4) -#define T1CTL_CH0IF (1 << 5) -#define T1CTL_CH1IF (1 << 6) -#define T1CTL_CH2IF (1 << 7) - -#define T1CCTL_NO_CAPTURE (0 << 0) -#define T1CCTL_CAPTURE_RISING (1 << 0) -#define T1CCTL_CAPTURE_FALLING (2 << 0) -#define T1CCTL_CAPTURE_BOTH (3 << 0) -#define T1CCTL_CAPTURE_MASK (3 << 0) - -#define T1CCTL_MODE_CAPTURE (0 << 2) -#define T1CCTL_MODE_COMPARE (1 << 2) - -#define T1CTL_CMP_SET (0 << 3) -#define T1CTL_CMP_CLEAR (1 << 3) -#define T1CTL_CMP_TOGGLE (2 << 3) -#define T1CTL_CMP_SET_CLEAR (3 << 3) -#define T1CTL_CMP_CLEAR_SET (4 << 3) - -#define T1CTL_IM_DISABLED (0 << 6) -#define T1CTL_IM_ENABLED (1 << 6) - -#define T1CTL_CPSEL_NORMAL (0 << 7) -#define T1CTL_CPSEL_RF (1 << 7) - -/* - * Timer 3 and Timer 4 - */ - -/* Timer count */ -__sfr __at 0xCA T3CNT; -__sfr __at 0xEA T4CNT; - -/* Timer control */ - -__sfr __at 0xCB T3CTL; -__sfr __at 0xEB T4CTL; - -#define TxCTL_DIV_1 (0 << 5) -#define TxCTL_DIV_2 (1 << 5) -#define TxCTL_DIV_4 (2 << 5) -#define TxCTL_DIV_8 (3 << 5) -#define TxCTL_DIV_16 (4 << 5) -#define TxCTL_DIV_32 (5 << 5) -#define TxCTL_DIV_64 (6 << 5) -#define TxCTL_DIV_128 (7 << 5) -#define TxCTL_START (1 << 4) -#define TxCTL_OVFIM (1 << 3) -#define TxCTL_CLR (1 << 2) -#define TxCTL_MODE_FREE (0 << 0) -#define TxCTL_MODE_DOWN (1 << 0) -#define TxCTL_MODE_MODULO (2 << 0) -#define TxCTL_MODE_UP_DOWN (3 << 0) - -/* Timer 4 channel 0 compare control */ - -__sfr __at 0xCC T3CCTL0; -__sfr __at 0xCE T3CCTL1; -__sfr __at 0xEC T4CCTL0; -__sfr __at 0xEE T4CCTL1; - -#define TxCCTLy_IM (1 << 6) -#define TxCCTLy_CMP_SET (0 << 3) -#define TxCCTLy_CMP_CLEAR (1 << 3) -#define TxCCTLy_CMP_TOGGLE (2 << 3) -#define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3) -#define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3) -#define TxCCTLy_CMP_SET_CLEAR_FF (5 << 3) -#define TxCCTLy_CMP_CLEAR_SET_00 (6 << 3) -#define TxCCTLy_CMP_MODE_ENABLE (1 << 2) - -/* Timer compare value */ -__sfr __at 0xCD T3CC0; -__sfr __at 0xCF T3CC1; -__sfr __at 0xED T4CC0; -__sfr __at 0xEF T4CC1; - -/* - * Peripheral control - */ - -__sfr __at 0xf1 PERCFG; -#define PERCFG_T1CFG_ALT_1 (0 << 6) -#define PERCFG_T1CFG_ALT_2 (1 << 6) -#define PERCFG_T1CFG_ALT_MASK (1 << 6) - -#define PERCFG_T3CFG_ALT_1 (0 << 5) -#define PERCFG_T3CFG_ALT_2 (1 << 5) -#define PERCFG_T3CFG_ALT_MASK (1 << 5) - -#define PERCFG_T4CFG_ALT_1 (0 << 4) -#define PERCFG_T4CFG_ALT_2 (1 << 4) -#define PERCFG_T4CFG_ALT_MASK (1 << 4) - -#define PERCFG_U1CFG_ALT_1 (0 << 1) -#define PERCFG_U1CFG_ALT_2 (1 << 1) -#define PERCFG_U1CFG_ALT_MASK (1 << 1) - -#define PERCFG_U0CFG_ALT_1 (0 << 0) -#define PERCFG_U0CFG_ALT_2 (1 << 0) -#define PERCFG_U0CFG_ALT_MASK (1 << 0) - -/* directly addressed USB registers */ -__xdata __at (0xde00) volatile uint8_t USBADDR; -__xdata __at (0xde01) volatile uint8_t USBPOW; -__xdata __at (0xde02) volatile uint8_t USBIIF; - -__xdata __at (0xde04) volatile uint8_t USBOIF; - -__xdata __at (0xde06) volatile uint8_t USBCIF; - -# define USBCIF_SOFIF (1 << 3) -# define USBCIF_RSTIF (1 << 2) -# define USBCIF_RESUMEIF (1 << 1) -# define USBCIF_SUSPENDIF (1 << 0) - -__xdata __at (0xde07) volatile uint8_t USBIIE; - -__xdata __at (0xde09) volatile uint8_t USBOIE; - -__xdata __at (0xde0b) volatile uint8_t USBCIE; - -# define USBCIE_SOFIE (1 << 3) -# define USBCIE_RSTIE (1 << 2) -# define USBCIE_RESUMEIE (1 << 1) -# define USBCIE_SUSPENDIE (1 << 0) - -__xdata __at (0xde0c) volatile uint8_t USBFRML; -__xdata __at (0xde0d) volatile uint8_t USBFRMH; -__xdata __at (0xde0e) volatile uint8_t USBINDEX; - -/* indexed USB registers, must set USBINDEX to 0-5 */ -__xdata __at (0xde10) volatile uint8_t USBMAXI; -__xdata __at (0xde11) volatile uint8_t USBCS0; - -# define USBCS0_CLR_SETUP_END (1 << 7) -# define USBCS0_CLR_OUTPKT_RDY (1 << 6) -# define USBCS0_SEND_STALL (1 << 5) -# define USBCS0_SETUP_END (1 << 4) -# define USBCS0_DATA_END (1 << 3) -# define USBCS0_SENT_STALL (1 << 2) -# define USBCS0_INPKT_RDY (1 << 1) -# define USBCS0_OUTPKT_RDY (1 << 0) - -__xdata __at (0xde11) volatile uint8_t USBCSIL; - -# define USBCSIL_CLR_DATA_TOG (1 << 6) -# define USBCSIL_SENT_STALL (1 << 5) -# define USBCSIL_SEND_STALL (1 << 4) -# define USBCSIL_FLUSH_PACKET (1 << 3) -# define USBCSIL_UNDERRUN (1 << 2) -# define USBCSIL_PKT_PRESENT (1 << 1) -# define USBCSIL_INPKT_RDY (1 << 0) - -__xdata __at (0xde12) volatile uint8_t USBCSIH; - -# define USBCSIH_AUTOSET (1 << 7) -# define USBCSIH_ISO (1 << 6) -# define USBCSIH_FORCE_DATA_TOG (1 << 3) -# define USBCSIH_IN_DBL_BUF (1 << 0) - -__xdata __at (0xde13) volatile uint8_t USBMAXO; -__xdata __at (0xde14) volatile uint8_t USBCSOL; - -# define USBCSOL_CLR_DATA_TOG (1 << 7) -# define USBCSOL_SENT_STALL (1 << 6) -# define USBCSOL_SEND_STALL (1 << 5) -# define USBCSOL_FLUSH_PACKET (1 << 4) -# define USBCSOL_DATA_ERROR (1 << 3) -# define USBCSOL_OVERRUN (1 << 2) -# define USBCSOL_FIFO_FULL (1 << 1) -# define USBCSOL_OUTPKT_RDY (1 << 0) - -__xdata __at (0xde15) volatile uint8_t USBCSOH; - -# define USBCSOH_AUTOCLEAR (1 << 7) -# define USBCSOH_ISO (1 << 6) -# define USBCSOH_OUT_DBL_BUF (1 << 0) - -__xdata __at (0xde16) volatile uint8_t USBCNT0; -__xdata __at (0xde16) volatile uint8_t USBCNTL; -__xdata __at (0xde17) volatile uint8_t USBCNTH; - -__xdata __at (0xde20) volatile uint8_t USBFIFO[12]; - -/* ADC Data register, low and high */ -__sfr at 0xBA ADCL; -__sfr at 0xBB ADCH; -__xdata __at (0xDFBA) volatile uint16_t ADCXDATA; - -/* ADC Control Register 1 */ -__sfr at 0xB4 ADCCON1; - -# define ADCCON1_EOC (1 << 7) /* conversion complete */ -# define ADCCON1_ST (1 << 6) /* start conversion */ - -# define ADCCON1_STSEL_MASK (3 << 4) /* start select */ -# define ADCCON1_STSEL_EXTERNAL (0 << 4) /* P2_0 pin triggers */ -# define ADCCON1_STSEL_FULLSPEED (1 << 4) /* full speed, no waiting */ -# define ADCCON1_STSEL_TIMER1 (2 << 4) /* timer 1 channel 0 */ -# define ADCCON1_STSEL_START (3 << 4) /* set start bit */ - -# define ADCCON1_RCTRL_MASK (3 << 2) /* random number control */ -# define ADCCON1_RCTRL_COMPLETE (0 << 2) /* operation completed */ -# define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2) /* Clock the LFSR once */ - -/* ADC Control Register 2 */ -__sfr at 0xB5 ADCCON2; - -# define ADCCON2_SREF_MASK (3 << 6) /* reference voltage */ -# define ADCCON2_SREF_1_25V (0 << 6) /* internal 1.25V */ -# define ADCCON2_SREF_EXTERNAL (1 << 6) /* external on AIN7 cc1110 */ -# define ADCCON2_SREF_VDD (2 << 6) /* VDD on the AVDD pin */ -# define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6) /* external on AIN6-7 cc1110 */ - -# define ADCCON2_SDIV_MASK (3 << 4) /* decimation rate */ -# define ADCCON2_SDIV_64 (0 << 4) /* 7 bits */ -# define ADCCON2_SDIV_128 (1 << 4) /* 9 bits */ -# define ADCCON2_SDIV_256 (2 << 4) /* 10 bits */ -# define ADCCON2_SDIV_512 (3 << 4) /* 12 bits */ - -# define ADCCON2_SCH_MASK (0xf << 0) /* Sequence channel select */ -# define ADCCON2_SCH_SHIFT 0 -# define ADCCON2_SCH_AIN0 (0 << 0) -# define ADCCON2_SCH_AIN1 (1 << 0) -# define ADCCON2_SCH_AIN2 (2 << 0) -# define ADCCON2_SCH_AIN3 (3 << 0) -# define ADCCON2_SCH_AIN4 (4 << 0) -# define ADCCON2_SCH_AIN5 (5 << 0) -# define ADCCON2_SCH_AIN6 (6 << 0) -# define ADCCON2_SCH_AIN7 (7 << 0) -# define ADCCON2_SCH_AIN0_AIN1 (8 << 0) -# define ADCCON2_SCH_AIN2_AIN3 (9 << 0) -# define ADCCON2_SCH_AIN4_AIN5 (0xa << 0) -# define ADCCON2_SCH_AIN6_AIN7 (0xb << 0) -# define ADCCON2_SCH_GND (0xc << 0) -# define ADCCON2_SCH_VREF (0xd << 0) -# define ADCCON2_SCH_TEMP (0xe << 0) -# define ADCCON2_SCH_VDD_3 (0xf << 0) - - -/* ADC Control Register 3 */ -__sfr at 0xB6 ADCCON3; - -# define ADCCON3_EREF_MASK (3 << 6) /* extra conversion reference */ -# define ADCCON3_EREF_1_25 (0 << 6) /* internal 1.25V */ -# define ADCCON3_EREF_EXTERNAL (1 << 6) /* external AIN7 cc1110 */ -# define ADCCON3_EREF_VDD (2 << 6) /* VDD on the AVDD pin */ -# define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6) /* external AIN6-7 cc1110 */ -# define ADCCON3_EDIV_MASK (3 << 4) /* extral decimation */ -# define ADCCON3_EDIV_64 (0 << 4) /* 7 bits */ -# define ADCCON3_EDIV_128 (1 << 4) /* 9 bits */ -# define ADCCON3_EDIV_256 (2 << 4) /* 10 bits */ -# define ADCCON3_EDIV_512 (3 << 4) /* 12 bits */ -# define ADCCON3_ECH_MASK (0xf << 0) /* Sequence channel select */ -# define ADCCON3_ECH_SHIFT 0 -# define ADCCON3_ECH_AIN0 (0 << 0) -# define ADCCON3_ECH_AIN1 (1 << 0) -# define ADCCON3_ECH_AIN2 (2 << 0) -# define ADCCON3_ECH_AIN3 (3 << 0) -# define ADCCON3_ECH_AIN4 (4 << 0) -# define ADCCON3_ECH_AIN5 (5 << 0) -# define ADCCON3_ECH_AIN6 (6 << 0) -# define ADCCON3_ECH_AIN7 (7 << 0) -# define ADCCON3_ECH_AIN0_AIN1 (8 << 0) -# define ADCCON3_ECH_AIN2_AIN3 (9 << 0) -# define ADCCON3_ECH_AIN4_AIN5 (0xa << 0) -# define ADCCON3_ECH_AIN6_AIN7 (0xb << 0) -# define ADCCON3_ECH_GND (0xc << 0) -# define ADCCON3_ECH_VREF (0xd << 0) -# define ADCCON3_ECH_TEMP (0xe << 0) -# define ADCCON3_ECH_VDD_3 (0xf << 0) - -/* - * ADC configuration register, this selects which - * GPIO pins are to be used as ADC inputs - */ -__sfr at 0xF2 ADCCFG; - -/* - * Watchdog timer - */ - -__sfr at 0xc9 WDCTL; - -#define WDCTL_CLEAR_FIRST (0xa << 4) -#define WDCTL_CLEAR_SECOND (0x5 << 4) -#define WDCTL_EN (1 << 3) -#define WDCTL_MODE_WATCHDOG (0 << 2) -#define WDCTL_MODE_TIMER (1 << 2) -#define WDCTL_MODE_MASK (1 << 2) -#define WDCTL_INT_32768 (0 << 0) -#define WDCTL_INT_8192 (1 << 0) -#define WDCTL_INT_512 (2 << 0) -#define WDCTL_INT_64 (3 << 0) - -/* - * Pin selectors, these set which pins are - * using their peripheral function - */ -__sfr at 0xF3 P0SEL; -__sfr at 0xF4 P1SEL; -__sfr at 0xF5 P2SEL; - -#define P2SEL_PRI3P1_USART0 (0 << 6) -#define P2SEL_PRI3P1_USART1 (1 << 6) -#define P2SEL_PRI3P1_MASK (1 << 6) -#define P2SEL_PRI2P1_USART1 (0 << 5) -#define P2SEL_PRI2P1_TIMER3 (1 << 5) -#define P2SEL_PRI2P1_MASK (1 << 5) -#define P2SEL_PRI1P1_TIMER1 (0 << 4) -#define P2SEL_PRI1P1_TIMER4 (1 << 4) -#define P2SEL_PRI1P1_MASK (1 << 4) -#define P2SEL_PRI0P1_USART0 (0 << 3) -#define P2SEL_PRI0P1_TIMER1 (1 << 3) -#define P2SEL_PRI0P1_MASK (1 << 3) -#define P2SEL_SELP2_4_GPIO (0 << 2) -#define P2SEL_SELP2_4_PERIPHERAL (1 << 2) -#define P2SEL_SELP2_4_MASK (1 << 2) -#define P2SEL_SELP2_3_GPIO (0 << 1) -#define P2SEL_SELP2_3_PERIPHERAL (1 << 1) -#define P2SEL_SELP2_3_MASK (1 << 1) -#define P2SEL_SELP2_0_GPIO (0 << 0) -#define P2SEL_SELP2_0_PERIPHERAL (1 << 0) -#define P2SEL_SELP2_0_MASK (1 << 0) - -/* - * For pins used as GPIOs, these set which are used as outputs - */ -__sfr at 0xFD P0DIR; -__sfr at 0xFE P1DIR; -__sfr at 0xFF P2DIR; - -#define P2DIR_PRIP0_USART0_USART1 (0 << 6) -#define P2DIR_PRIP0_USART1_USART0 (1 << 6) -#define P2DIR_PRIP0_TIMER1_01_USART1 (2 << 6) -#define P2DIR_PRIP0_TIMER1_2_USART0 (3 << 6) -#define P2DIR_PRIP0_MASK (3 << 6) - -__sfr at 0x8F P0INP; - -/* Select between tri-state and pull up/down - * for pins P0_0 - P0_7. - */ -#define P0INP_MDP0_7_PULL (0 << 7) -#define P0INP_MDP0_7_TRISTATE (1 << 7) -#define P0INP_MDP0_6_PULL (0 << 6) -#define P0INP_MDP0_6_TRISTATE (1 << 6) -#define P0INP_MDP0_5_PULL (0 << 5) -#define P0INP_MDP0_5_TRISTATE (1 << 5) -#define P0INP_MDP0_4_PULL (0 << 4) -#define P0INP_MDP0_4_TRISTATE (1 << 4) -#define P0INP_MDP0_3_PULL (0 << 3) -#define P0INP_MDP0_3_TRISTATE (1 << 3) -#define P0INP_MDP0_2_PULL (0 << 2) -#define P0INP_MDP0_2_TRISTATE (1 << 2) -#define P0INP_MDP0_1_PULL (0 << 1) -#define P0INP_MDP0_1_TRISTATE (1 << 1) -#define P0INP_MDP0_0_PULL (0 << 0) -#define P0INP_MDP0_0_TRISTATE (1 << 0) - -__sfr at 0xF6 P1INP; - -/* Select between tri-state and pull up/down - * for pins P1_2 - P1_7. Pins P1_0 and P1_1 are - * always tri-stated - */ -#define P1INP_MDP1_7_PULL (0 << 7) -#define P1INP_MDP1_7_TRISTATE (1 << 7) -#define P1INP_MDP1_6_PULL (0 << 6) -#define P1INP_MDP1_6_TRISTATE (1 << 6) -#define P1INP_MDP1_5_PULL (0 << 5) -#define P1INP_MDP1_5_TRISTATE (1 << 5) -#define P1INP_MDP1_4_PULL (0 << 4) -#define P1INP_MDP1_4_TRISTATE (1 << 4) -#define P1INP_MDP1_3_PULL (0 << 3) -#define P1INP_MDP1_3_TRISTATE (1 << 3) -#define P1INP_MDP1_2_PULL (0 << 2) -#define P1INP_MDP1_2_TRISTATE (1 << 2) - -__sfr at 0xF7 P2INP; -/* P2INP has three extra bits which are used to choose - * between pull-up and pull-down when they are not tri-stated - */ -#define P2INP_PDUP2_PULL_UP (0 << 7) -#define P2INP_PDUP2_PULL_DOWN (1 << 7) -#define P2INP_PDUP1_PULL_UP (0 << 6) -#define P2INP_PDUP1_PULL_DOWN (1 << 6) -#define P2INP_PDUP0_PULL_UP (0 << 5) -#define P2INP_PDUP0_PULL_DOWN (1 << 5) - -/* For the P2 pins, choose between tri-state and pull up/down - * mode - */ -#define P2INP_MDP2_4_PULL (0 << 4) -#define P2INP_MDP2_4_TRISTATE (1 << 4) -#define P2INP_MDP2_3_PULL (0 << 3) -#define P2INP_MDP2_3_TRISTATE (1 << 3) -#define P2INP_MDP2_2_PULL (0 << 2) -#define P2INP_MDP2_2_TRISTATE (1 << 2) -#define P2INP_MDP2_1_PULL (0 << 1) -#define P2INP_MDP2_1_TRISTATE (1 << 1) -#define P2INP_MDP2_0_PULL (0 << 0) -#define P2INP_MDP2_0_TRISTATE (1 << 0) - -/* GPIO interrupt status flags */ -__sfr at 0x89 P0IFG; -__sfr at 0x8A P1IFG; -__sfr at 0x8B P2IFG; - -#define P0IFG_USB_RESUME (1 << 7) - -__sfr at 0x8C PICTL; -#define PICTL_P2IEN (1 << 5) -#define PICTL_P0IENH (1 << 4) -#define PICTL_P0IENL (1 << 3) -#define PICTL_P2ICON (1 << 2) -#define PICTL_P1ICON (1 << 1) -#define PICTL_P0ICON (1 << 0) - -/* GPIO pins */ -__sfr at 0x80 P0; - -sbit at 0x80 P0_0; -sbit at 0x81 P0_1; -sbit at 0x82 P0_2; -sbit at 0x83 P0_3; -sbit at 0x84 P0_4; -sbit at 0x85 P0_5; -sbit at 0x86 P0_6; -sbit at 0x87 P0_7; - -__sfr at 0x90 P1; - -sbit at 0x90 P1_0; -sbit at 0x91 P1_1; -sbit at 0x92 P1_2; -sbit at 0x93 P1_3; -sbit at 0x94 P1_4; -sbit at 0x95 P1_5; -sbit at 0x96 P1_6; -sbit at 0x97 P1_7; - -__sfr at 0xa0 P2; - -sbit at 0xa0 P2_0; -sbit at 0xa1 P2_1; -sbit at 0xa2 P2_2; -sbit at 0xa3 P2_3; -sbit at 0xa4 P2_4; - -/* DMA controller */ -struct cc_dma_channel { - uint8_t src_high; - uint8_t src_low; - uint8_t dst_high; - uint8_t dst_low; - uint8_t len_high; - uint8_t len_low; - uint8_t cfg0; - uint8_t cfg1; -}; - -# define DMA_LEN_HIGH_VLEN_MASK (7 << 5) -# define DMA_LEN_HIGH_VLEN_LEN (0 << 5) -# define DMA_LEN_HIGH_VLEN_PLUS_1 (1 << 5) -# define DMA_LEN_HIGH_VLEN (2 << 5) -# define DMA_LEN_HIGH_VLEN_PLUS_2 (3 << 5) -# define DMA_LEN_HIGH_VLEN_PLUS_3 (4 << 5) -# define DMA_LEN_HIGH_MASK (0x1f) - -# define DMA_CFG0_WORDSIZE_8 (0 << 7) -# define DMA_CFG0_WORDSIZE_16 (1 << 7) -# define DMA_CFG0_TMODE_MASK (3 << 5) -# define DMA_CFG0_TMODE_SINGLE (0 << 5) -# define DMA_CFG0_TMODE_BLOCK (1 << 5) -# define DMA_CFG0_TMODE_REPEATED_SINGLE (2 << 5) -# define DMA_CFG0_TMODE_REPEATED_BLOCK (3 << 5) - -/* - * DMA triggers - */ -# define DMA_CFG0_TRIGGER_NONE 0 -# define DMA_CFG0_TRIGGER_PREV 1 -# define DMA_CFG0_TRIGGER_T1_CH0 2 -# define DMA_CFG0_TRIGGER_T1_CH1 3 -# define DMA_CFG0_TRIGGER_T1_CH2 4 -# define DMA_CFG0_TRIGGER_T2_OVFL 6 -# define DMA_CFG0_TRIGGER_T3_CH0 7 -# define DMA_CFG0_TRIGGER_T3_CH1 8 -# define DMA_CFG0_TRIGGER_T4_CH0 9 -# define DMA_CFG0_TRIGGER_T4_CH1 10 -# define DMA_CFG0_TRIGGER_IOC_0 12 -# define DMA_CFG0_TRIGGER_IOC_1 13 -# define DMA_CFG0_TRIGGER_URX0 14 -# define DMA_CFG0_TRIGGER_UTX0 15 -# define DMA_CFG0_TRIGGER_URX1 16 -# define DMA_CFG0_TRIGGER_UTX1 17 -# define DMA_CFG0_TRIGGER_FLASH 18 -# define DMA_CFG0_TRIGGER_RADIO 19 -# define DMA_CFG0_TRIGGER_ADC_CHALL 20 -# define DMA_CFG0_TRIGGER_ADC_CH0 21 -# define DMA_CFG0_TRIGGER_ADC_CH1 22 -# define DMA_CFG0_TRIGGER_ADC_CH2 23 -# define DMA_CFG0_TRIGGER_ADC_CH3 24 -# define DMA_CFG0_TRIGGER_ADC_CH4 25 -# define DMA_CFG0_TRIGGER_ADC_CH5 26 -# define DMA_CFG0_TRIGGER_ADC_CH6 27 -# define DMA_CFG0_TRIGGER_I2SRX 27 -# define DMA_CFG0_TRIGGER_ADC_CH7 28 -# define DMA_CFG0_TRIGGER_I2STX 28 -# define DMA_CFG0_TRIGGER_ENC_DW 29 -# define DMA_CFG0_TRIGGER_DNC_UP 30 - -# define DMA_CFG1_SRCINC_MASK (3 << 6) -# define DMA_CFG1_SRCINC_0 (0 << 6) -# define DMA_CFG1_SRCINC_1 (1 << 6) -# define DMA_CFG1_SRCINC_2 (2 << 6) -# define DMA_CFG1_SRCINC_MINUS_1 (3 << 6) - -# define DMA_CFG1_DESTINC_MASK (3 << 4) -# define DMA_CFG1_DESTINC_0 (0 << 4) -# define DMA_CFG1_DESTINC_1 (1 << 4) -# define DMA_CFG1_DESTINC_2 (2 << 4) -# define DMA_CFG1_DESTINC_MINUS_1 (3 << 4) - -# define DMA_CFG1_IRQMASK (1 << 3) -# define DMA_CFG1_M8 (1 << 2) - -# define DMA_CFG1_PRIORITY_MASK (3 << 0) -# define DMA_CFG1_PRIORITY_LOW (0 << 0) -# define DMA_CFG1_PRIORITY_NORMAL (1 << 0) -# define DMA_CFG1_PRIORITY_HIGH (2 << 0) - -/* - * DMAARM - DMA Channel Arm - */ - -__sfr at 0xD6 DMAARM; - -# define DMAARM_ABORT (1 << 7) -# define DMAARM_DMAARM4 (1 << 4) -# define DMAARM_DMAARM3 (1 << 3) -# define DMAARM_DMAARM2 (1 << 2) -# define DMAARM_DMAARM1 (1 << 1) -# define DMAARM_DMAARM0 (1 << 0) - -/* - * DMAREQ - DMA Channel Start Request and Status - */ - -__sfr at 0xD7 DMAREQ; - -# define DMAREQ_DMAREQ4 (1 << 4) -# define DMAREQ_DMAREQ3 (1 << 3) -# define DMAREQ_DMAREQ2 (1 << 2) -# define DMAREQ_DMAREQ1 (1 << 1) -# define DMAREQ_DMAREQ0 (1 << 0) - -/* - * DMA configuration 0 address - */ - -__sfr at 0xD5 DMA0CFGH; -__sfr at 0xD4 DMA0CFGL; - -/* - * DMA configuration 1-4 address - */ - -__sfr at 0xD3 DMA1CFGH; -__sfr at 0xD2 DMA1CFGL; - -/* - * DMAIRQ - DMA Interrupt Flag - */ - -__sfr at 0xD1 DMAIRQ; - -# define DMAIRQ_DMAIF4 (1 << 4) -# define DMAIRQ_DMAIF3 (1 << 3) -# define DMAIRQ_DMAIF2 (1 << 2) -# define DMAIRQ_DMAIF1 (1 << 1) -# define DMAIRQ_DMAIF0 (1 << 0) - -/* - * UART registers - */ - -/* USART config/status registers */ -__sfr at 0x86 U0CSR; -__sfr at 0xF8 U1CSR; - -# define UxCSR_MODE_UART (1 << 7) -# define UxCSR_MODE_SPI (0 << 7) -# define UxCSR_RE (1 << 6) -# define UxCSR_SLAVE (1 << 5) -# define UxCSR_MASTER (0 << 5) -# define UxCSR_FE (1 << 4) -# define UxCSR_ERR (1 << 3) -# define UxCSR_RX_BYTE (1 << 2) -# define UxCSR_TX_BYTE (1 << 1) -# define UxCSR_ACTIVE (1 << 0) - -/* UART configuration registers */ -__sfr at 0xc4 U0UCR; -__sfr at 0xfb U1UCR; - -# define UxUCR_FLUSH (1 << 7) -# define UxUCR_FLOW_DISABLE (0 << 6) -# define UxUCR_FLOW_ENABLE (1 << 6) -# define UxUCR_D9_EVEN_PARITY (0 << 5) -# define UxUCR_D9_ODD_PARITY (1 << 5) -# define UxUCR_BIT9_8_BITS (0 << 4) -# define UxUCR_BIT9_9_BITS (1 << 4) -# define UxUCR_PARITY_DISABLE (0 << 3) -# define UxUCR_PARITY_ENABLE (1 << 3) -# define UxUCR_SPB_1_STOP_BIT (0 << 2) -# define UxUCR_SPB_2_STOP_BITS (1 << 2) -# define UxUCR_STOP_LOW (0 << 1) -# define UxUCR_STOP_HIGH (1 << 1) -# define UxUCR_START_LOW (0 << 0) -# define UxUCR_START_HIGH (1 << 0) - -/* USART General configuration registers (mostly SPI) */ -__sfr at 0xc5 U0GCR; -__sfr at 0xfc U1GCR; - -# define UxGCR_CPOL_NEGATIVE (0 << 7) -# define UxGCR_CPOL_POSITIVE (1 << 7) -# define UxGCR_CPHA_FIRST_EDGE (0 << 6) -# define UxGCR_CPHA_SECOND_EDGE (1 << 6) -# define UxGCR_ORDER_LSB (0 << 5) -# define UxGCR_ORDER_MSB (1 << 5) -# define UxGCR_BAUD_E_MASK (0x1f) -# define UxGCR_BAUD_E_SHIFT 0 - -/* USART data registers */ -__sfr at 0xc1 U0DBUF; -__xdata __at (0xDFC1) volatile uint8_t U0DBUFXADDR; -__sfr at 0xf9 U1DBUF; -__xdata __at (0xDFF9) volatile uint8_t U1DBUFXADDR; - -/* USART baud rate registers, M value */ -__sfr at 0xc2 U0BAUD; -__sfr at 0xfa U1BAUD; - -/* Flash controller */ - -__sfr at 0xAE FCTL; -#define FCTL_BUSY (1 << 7) -#define FCTL_SWBSY (1 << 6) -#define FCTL_CONTRD_ENABLE (1 << 4) -#define FCTL_WRITE (1 << 1) -#define FCTL_ERASE (1 << 0) - -/* Flash write data. Write two bytes here */ -__sfr at 0xAF FWDATA; -__xdata __at (0xDFAF) volatile uint8_t FWDATAXADDR; - -/* Flash write/erase address */ -__sfr at 0xAD FADDRH; -__sfr at 0xAC FADDRL; - -/* Flash timing */ -__sfr at 0xAB FWT; - -/* Radio */ - -__sfr at 0xD9 RFD; -__xdata at (0xDFD9) volatile uint8_t RFDXADDR; - -__sfr at 0xE9 RFIF; -#define RFIF_IM_TXUNF (1 << 7) -#define RFIF_IM_RXOVF (1 << 6) -#define RFIF_IM_TIMEOUT (1 << 5) -#define RFIF_IM_DONE (1 << 4) -#define RFIF_IM_CS (1 << 3) -#define RFIF_IM_PQT (1 << 2) -#define RFIF_IM_CCA (1 << 1) -#define RFIF_IM_SFD (1 << 0) - -__sfr at 0x91 RFIM; -#define RFIM_IM_TXUNF (1 << 7) -#define RFIM_IM_RXOVF (1 << 6) -#define RFIM_IM_TIMEOUT (1 << 5) -#define RFIM_IM_DONE (1 << 4) -#define RFIM_IM_CS (1 << 3) -#define RFIM_IM_PQT (1 << 2) -#define RFIM_IM_CCA (1 << 1) -#define RFIM_IM_SFD (1 << 0) - -__sfr at 0xE1 RFST; - -#define RFST_SFSTXON 0x00 -#define RFST_SCAL 0x01 -#define RFST_SRX 0x02 -#define RFST_STX 0x03 -#define RFST_SIDLE 0x04 - -__xdata __at (0xdf00) uint8_t RF[0x3c]; - -__xdata __at (0xdf2f) uint8_t RF_IOCFG2; -#define RF_IOCFG2_OFF 0x2f - -__xdata __at (0xdf30) uint8_t RF_IOCFG1; -#define RF_IOCFG1_OFF 0x30 - -__xdata __at (0xdf31) uint8_t RF_IOCFG0; -#define RF_IOCFG0_OFF 0x31 - -__xdata __at (0xdf00) uint8_t RF_SYNC1; -#define RF_SYNC1_OFF 0x00 - -__xdata __at (0xdf01) uint8_t RF_SYNC0; -#define RF_SYNC0_OFF 0x01 - -__xdata __at (0xdf02) uint8_t RF_PKTLEN; -#define RF_PKTLEN_OFF 0x02 - -__xdata __at (0xdf03) uint8_t RF_PKTCTRL1; -#define RF_PKTCTRL1_OFF 0x03 -#define PKTCTRL1_PQT_MASK (0x7 << 5) -#define PKTCTRL1_PQT_SHIFT 5 -#define PKTCTRL1_APPEND_STATUS (1 << 2) -#define PKTCTRL1_ADR_CHK_NONE (0 << 0) -#define PKTCTRL1_ADR_CHK_NO_BROADCAST (1 << 0) -#define PKTCTRL1_ADR_CHK_00_BROADCAST (2 << 0) -#define PKTCTRL1_ADR_CHK_00_FF_BROADCAST (3 << 0) - -/* If APPEND_STATUS is used, two bytes will be added to the packet data */ -#define PKT_APPEND_STATUS_0_RSSI_MASK (0xff) -#define PKT_APPEND_STATUS_0_RSSI_SHIFT 0 -#define PKT_APPEND_STATUS_1_CRC_OK (1 << 7) -#define PKT_APPEND_STATUS_1_LQI_MASK (0x7f) -#define PKT_APPEND_STATUS_1_LQI_SHIFT 0 - -__xdata __at (0xdf04) uint8_t RF_PKTCTRL0; -#define RF_PKTCTRL0_OFF 0x04 -#define RF_PKTCTRL0_WHITE_DATA (1 << 6) -#define RF_PKTCTRL0_PKT_FORMAT_NORMAL (0 << 4) -#define RF_PKTCTRL0_PKT_FORMAT_RANDOM (2 << 4) -#define RF_PKTCTRL0_CRC_EN (1 << 2) -#define RF_PKTCTRL0_LENGTH_CONFIG_FIXED (0 << 0) -#define RF_PKTCTRL0_LENGTH_CONFIG_VARIABLE (1 << 0) - -__xdata __at (0xdf05) uint8_t RF_ADDR; -#define RF_ADDR_OFF 0x05 - -__xdata __at (0xdf06) uint8_t RF_CHANNR; -#define RF_CHANNR_OFF 0x06 - -__xdata __at (0xdf07) uint8_t RF_FSCTRL1; -#define RF_FSCTRL1_OFF 0x07 - -#define RF_FSCTRL1_FREQ_IF_SHIFT (0) - -__xdata __at (0xdf08) uint8_t RF_FSCTRL0; -#define RF_FSCTRL0_OFF 0x08 - -#define RF_FSCTRL0_FREQOFF_SHIFT (0) - -__xdata __at (0xdf09) uint8_t RF_FREQ2; -#define RF_FREQ2_OFF 0x09 - -__xdata __at (0xdf0a) uint8_t RF_FREQ1; -#define RF_FREQ1_OFF 0x0a - -__xdata __at (0xdf0b) uint8_t RF_FREQ0; -#define RF_FREQ0_OFF 0x0b - -__xdata __at (0xdf0c) uint8_t RF_MDMCFG4; -#define RF_MDMCFG4_OFF 0x0c - -#define RF_MDMCFG4_CHANBW_E_SHIFT 6 -#define RF_MDMCFG4_CHANBW_M_SHIFT 4 -#define RF_MDMCFG4_DRATE_E_SHIFT 0 - -__xdata __at (0xdf0d) uint8_t RF_MDMCFG3; -#define RF_MDMCFG3_OFF 0x0d - -#define RF_MDMCFG3_DRATE_M_SHIFT 0 - -__xdata __at (0xdf0e) uint8_t RF_MDMCFG2; -#define RF_MDMCFG2_OFF 0x0e - -#define RF_MDMCFG2_DEM_DCFILT_OFF (1 << 7) -#define RF_MDMCFG2_DEM_DCFILT_ON (0 << 7) - -#define RF_MDMCFG2_MOD_FORMAT_MASK (7 << 4) -#define RF_MDMCFG2_MOD_FORMAT_2_FSK (0 << 4) -#define RF_MDMCFG2_MOD_FORMAT_GFSK (1 << 4) -#define RF_MDMCFG2_MOD_FORMAT_ASK_OOK (3 << 4) -#define RF_MDMCFG2_MOD_FORMAT_MSK (7 << 4) - -#define RF_MDMCFG2_MANCHESTER_EN (1 << 3) - -#define RF_MDMCFG2_SYNC_MODE_MASK (0x7 << 0) -#define RF_MDMCFG2_SYNC_MODE_NONE (0x0 << 0) -#define RF_MDMCFG2_SYNC_MODE_15_16 (0x1 << 0) -#define RF_MDMCFG2_SYNC_MODE_16_16 (0x2 << 0) -#define RF_MDMCFG2_SYNC_MODE_30_32 (0x3 << 0) -#define RF_MDMCFG2_SYNC_MODE_NONE_THRES (0x4 << 0) -#define RF_MDMCFG2_SYNC_MODE_15_16_THRES (0x5 << 0) -#define RF_MDMCFG2_SYNC_MODE_16_16_THRES (0x6 << 0) -#define RF_MDMCFG2_SYNC_MODE_30_32_THRES (0x7 << 0) - -__xdata __at (0xdf0f) uint8_t RF_MDMCFG1; -#define RF_MDMCFG1_OFF 0x0f - -#define RF_MDMCFG1_FEC_EN (1 << 7) -#define RF_MDMCFG1_FEC_DIS (0 << 7) - -#define RF_MDMCFG1_NUM_PREAMBLE_MASK (7 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_2 (0 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_3 (1 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_4 (2 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_6 (3 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_8 (4 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_12 (5 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_16 (6 << 4) -#define RF_MDMCFG1_NUM_PREAMBLE_24 (7 << 4) - -#define RF_MDMCFG1_CHANSPC_E_MASK (3 << 0) -#define RF_MDMCFG1_CHANSPC_E_SHIFT (0) - -__xdata __at (0xdf10) uint8_t RF_MDMCFG0; -#define RF_MDMCFG0_OFF 0x10 - -#define RF_MDMCFG0_CHANSPC_M_SHIFT (0) - -__xdata __at (0xdf11) uint8_t RF_DEVIATN; -#define RF_DEVIATN_OFF 0x11 - -#define RF_DEVIATN_DEVIATION_E_SHIFT 4 -#define RF_DEVIATN_DEVIATION_M_SHIFT 0 - -__xdata __at (0xdf12) uint8_t RF_MCSM2; -#define RF_MCSM2_OFF 0x12 -#define RF_MCSM2_RX_TIME_RSSI (1 << 4) -#define RF_MCSM2_RX_TIME_QUAL (1 << 3) -#define RF_MCSM2_RX_TIME_MASK (0x7) -#define RF_MCSM2_RX_TIME_SHIFT 0 -#define RF_MCSM2_RX_TIME_END_OF_PACKET (7) - -__xdata __at (0xdf13) uint8_t RF_MCSM1; -#define RF_MCSM1_OFF 0x13 -#define RF_MCSM1_CCA_MODE_ALWAYS (0 << 4) -#define RF_MCSM1_CCA_MODE_RSSI_BELOW (1 << 4) -#define RF_MCSM1_CCA_MODE_UNLESS_RECEIVING (2 << 4) -#define RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING (3 << 4) -#define RF_MCSM1_RXOFF_MODE_IDLE (0 << 2) -#define RF_MCSM1_RXOFF_MODE_FSTXON (1 << 2) -#define RF_MCSM1_RXOFF_MODE_TX (2 << 2) -#define RF_MCSM1_RXOFF_MODE_RX (3 << 2) -#define RF_MCSM1_TXOFF_MODE_IDLE (0 << 0) -#define RF_MCSM1_TXOFF_MODE_FSTXON (1 << 0) -#define RF_MCSM1_TXOFF_MODE_TX (2 << 0) -#define RF_MCSM1_TXOFF_MODE_RX (3 << 0) - -__xdata __at (0xdf14) uint8_t RF_MCSM0; -#define RF_MCSM0_OFF 0x14 -#define RF_MCSM0_FS_AUTOCAL_NEVER (0 << 4) -#define RF_MCSM0_FS_AUTOCAL_FROM_IDLE (1 << 4) -#define RF_MCSM0_FS_AUTOCAL_TO_IDLE (2 << 4) -#define RF_MCSM0_FS_AUTOCAL_TO_IDLE_EVERY_4 (3 << 4) -#define RF_MCSM0_MAGIC_3 (1 << 3) -#define RF_MCSM0_MAGIC_2 (1 << 2) -#define RF_MCSM0_CLOSE_IN_RX_0DB (0 << 0) -#define RF_MCSM0_CLOSE_IN_RX_6DB (1 << 0) -#define RF_MCSM0_CLOSE_IN_RX_12DB (2 << 0) -#define RF_MCSM0_CLOSE_IN_RX_18DB (3 << 0) - -__xdata __at (0xdf15) uint8_t RF_FOCCFG; -#define RF_FOCCFG_OFF 0x15 -#define RF_FOCCFG_FOC_BS_CS_GATE (1 << 5) -#define RF_FOCCFG_FOC_PRE_K_1K (0 << 3) -#define RF_FOCCFG_FOC_PRE_K_2K (1 << 3) -#define RF_FOCCFG_FOC_PRE_K_3K (2 << 3) -#define RF_FOCCFG_FOC_PRE_K_4K (3 << 3) -#define RF_FOCCFG_FOC_POST_K_PRE_K (0 << 2) -#define RF_FOCCFG_FOC_POST_K_PRE_K_OVER_2 (1 << 2) -#define RF_FOCCFG_FOC_LIMIT_0 (0 << 0) -#define RF_FOCCFG_FOC_LIMIT_BW_OVER_8 (1 << 0) -#define RF_FOCCFG_FOC_LIMIT_BW_OVER_4 (2 << 0) -#define RF_FOCCFG_FOC_LIMIT_BW_OVER_2 (3 << 0) - -__xdata __at (0xdf16) uint8_t RF_BSCFG; -#define RF_BSCFG_OFF 0x16 -#define RF_BSCFG_BS_PRE_K_1K (0 << 6) -#define RF_BSCFG_BS_PRE_K_2K (1 << 6) -#define RF_BSCFG_BS_PRE_K_3K (2 << 6) -#define RF_BSCFG_BS_PRE_K_4K (3 << 6) -#define RF_BSCFG_BS_PRE_KP_1KP (0 << 4) -#define RF_BSCFG_BS_PRE_KP_2KP (1 << 4) -#define RF_BSCFG_BS_PRE_KP_3KP (2 << 4) -#define RF_BSCFG_BS_PRE_KP_4KP (3 << 4) -#define RF_BSCFG_BS_POST_KI_PRE_KI (0 << 3) -#define RF_BSCFG_BS_POST_KI_PRE_KI_OVER_2 (1 << 3) -#define RF_BSCFG_BS_POST_KP_PRE_KP (0 << 2) -#define RF_BSCFG_BS_POST_KP_PRE_KP_OVER_2 (1 << 2) -#define RF_BSCFG_BS_LIMIT_0 (0 << 0) -#define RF_BSCFG_BS_LIMIT_3_125 (1 << 0) -#define RF_BSCFG_BS_LIMIT_6_25 (2 << 0) -#define RF_BSCFG_BS_LIMIT_12_5 (3 << 0) - -__xdata __at (0xdf17) uint8_t RF_AGCCTRL2; -#define RF_AGCCTRL2_OFF 0x17 - -__xdata __at (0xdf18) uint8_t RF_AGCCTRL1; -#define RF_AGCCTRL1_OFF 0x18 - -__xdata __at (0xdf19) uint8_t RF_AGCCTRL0; -#define RF_AGCCTRL0_OFF 0x19 - -__xdata __at (0xdf1a) uint8_t RF_FREND1; -#define RF_FREND1_OFF 0x1a - -#define RF_FREND1_LNA_CURRENT_SHIFT 6 -#define RF_FREND1_LNA2MIX_CURRENT_SHIFT 4 -#define RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT 2 -#define RF_FREND1_MIX_CURRENT_SHIFT 0 - -__xdata __at (0xdf1b) uint8_t RF_FREND0; -#define RF_FREND0_OFF 0x1b - -#define RF_FREND0_LODIV_BUF_CURRENT_TX_MASK (0x3 << 4) -#define RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT 4 -#define RF_FREND0_PA_POWER_MASK (0x7) -#define RF_FREND0_PA_POWER_SHIFT 0 - -__xdata __at (0xdf1c) uint8_t RF_FSCAL3; -#define RF_FSCAL3_OFF 0x1c - -__xdata __at (0xdf1d) uint8_t RF_FSCAL2; -#define RF_FSCAL2_OFF 0x1d - -__xdata __at (0xdf1e) uint8_t RF_FSCAL1; -#define RF_FSCAL1_OFF 0x1e - -__xdata __at (0xdf1f) uint8_t RF_FSCAL0; -#define RF_FSCAL0_OFF 0x1f - -__xdata __at (0xdf23) uint8_t RF_TEST2; -#define RF_TEST2_OFF 0x23 - -#define RF_TEST2_NORMAL_MAGIC 0x88 -#define RF_TEST2_RX_LOW_DATA_RATE_MAGIC 0x81 - -__xdata __at (0xdf24) uint8_t RF_TEST1; -#define RF_TEST1_OFF 0x24 - -#define RF_TEST1_TX_MAGIC 0x31 -#define RF_TEST1_RX_LOW_DATA_RATE_MAGIC 0x35 - -__xdata __at (0xdf25) uint8_t RF_TEST0; -#define RF_TEST0_OFF 0x25 - -#define RF_TEST0_7_2_MASK (0xfc) -#define RF_TEST0_VCO_SEL_CAL_EN (1 << 1) -#define RF_TEST0_0_MASK (1) - -/* These are undocumented, and must be computed - * using the provided tool. - */ -__xdata __at (0xdf27) uint8_t RF_PA_TABLE7; -#define RF_PA_TABLE7_OFF 0x27 - -__xdata __at (0xdf28) uint8_t RF_PA_TABLE6; -#define RF_PA_TABLE6_OFF 0x28 - -__xdata __at (0xdf29) uint8_t RF_PA_TABLE5; -#define RF_PA_TABLE5_OFF 0x29 - -__xdata __at (0xdf2a) uint8_t RF_PA_TABLE4; -#define RF_PA_TABLE4_OFF 0x2a - -__xdata __at (0xdf2b) uint8_t RF_PA_TABLE3; -#define RF_PA_TABLE3_OFF 0x2b - -__xdata __at (0xdf2c) uint8_t RF_PA_TABLE2; -#define RF_PA_TABLE2_OFF 0x2c - -__xdata __at (0xdf2d) uint8_t RF_PA_TABLE1; -#define RF_PA_TABLE1_OFF 0x2d - -__xdata __at (0xdf2e) uint8_t RF_PA_TABLE0; -#define RF_PA_TABLE0_OFF 0x2e - -__xdata __at (0xdf36) uint8_t RF_PARTNUM; -#define RF_PARTNUM_OFF 0x36 - -__xdata __at (0xdf37) uint8_t RF_VERSION; -#define RF_VERSION_OFF 0x37 - -__xdata __at (0xdf38) uint8_t RF_FREQEST; -#define RF_FREQEST_OFF 0x38 - -__xdata __at (0xdf39) uint8_t RF_LQI; -#define RF_LQI_OFF 0x39 - -#define RF_LQI_CRC_OK (1 << 7) -#define RF_LQI_LQI_EST_MASK (0x7f) - -__xdata __at (0xdf3a) uint8_t RF_RSSI; -#define RF_RSSI_OFF 0x3a - -__xdata __at (0xdf3b) uint8_t RF_MARCSTATE; -#define RF_MARCSTATE_OFF 0x3b - -#define RF_MARCSTATE_MASK 0x1f -#define RF_MARCSTATE_SLEEP 0x00 -#define RF_MARCSTATE_IDLE 0x01 -#define RF_MARCSTATE_VCOON_MC 0x03 -#define RF_MARCSTATE_REGON_MC 0x04 -#define RF_MARCSTATE_MANCAL 0x05 -#define RF_MARCSTATE_VCOON 0x06 -#define RF_MARCSTATE_REGON 0x07 -#define RF_MARCSTATE_STARTCAL 0x08 -#define RF_MARCSTATE_BWBOOST 0x09 -#define RF_MARCSTATE_FS_LOCK 0x0a -#define RF_MARCSTATE_IFADCON 0x0b -#define RF_MARCSTATE_ENDCAL 0x0c -#define RF_MARCSTATE_RX 0x0d -#define RF_MARCSTATE_RX_END 0x0e -#define RF_MARCSTATE_RX_RST 0x0f -#define RF_MARCSTATE_TXRX_SWITCH 0x10 -#define RF_MARCSTATE_RX_OVERFLOW 0x11 -#define RF_MARCSTATE_FSTXON 0x12 -#define RF_MARCSTATE_TX 0x13 -#define RF_MARCSTATE_TX_END 0x14 -#define RF_MARCSTATE_RXTX_SWITCH 0x15 -#define RF_MARCSTATE_TX_UNDERFLOW 0x16 - - -__xdata __at (0xdf3c) uint8_t RF_PKTSTATUS; -#define RF_PKTSTATUS_OFF 0x3c - -#define RF_PKTSTATUS_CRC_OK (1 << 7) -#define RF_PKTSTATUS_CS (1 << 6) -#define RF_PKTSTATUS_PQT_REACHED (1 << 5) -#define RF_PKTSTATUS_CCA (1 << 4) -#define RF_PKTSTATUS_SFD (1 << 3) - -__xdata __at (0xdf3d) uint8_t RF_VCO_VC_DAC; -#define RF_VCO_VC_DAC_OFF 0x3d - -#endif diff --git a/src/cc1111/Makefile.cc1111 b/src/cc1111/Makefile.cc1111 new file mode 100644 index 00000000..8de4a9b2 --- /dev/null +++ b/src/cc1111/Makefile.cc1111 @@ -0,0 +1,27 @@ +CC=sdcc + +CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE) + +CFLAGS += $(PRODUCT_DEF) -I. -I.. -I../core -I../cc1111 -I../driver -I../product + +CODESIZE ?= 0x8000 + +LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size $(CODESIZE) \ + --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff + +REL=$(SRC:.c=.rel) ao_product.rel +ADB=$(REL:.rel=.adb) +ASM=$(REL:.rel=.asm) +LNK=$(REL:.rel=.lnk) +LST=$(REL:.rel=.lst) +RST=$(REL:.rel=.rst) +SYM=$(REL:.rel=.sym) + +PCDB=$(PROG:.ihx=.cdb) +PLNK=$(PROG:.ihx=.lnk) +PMAP=$(PROG:.ihx=.map) +PMEM=$(PROG:.ihx=.mem) +PAOM=$(PROG:.ihx=) + +%.rel : %.c $(INC) + $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $< diff --git a/src/cc1111/_bp.c b/src/cc1111/_bp.c new file mode 100644 index 00000000..6bf135bc --- /dev/null +++ b/src/cc1111/_bp.c @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + + _bp.c :- just declares bp as a variable + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +__data unsigned char bp ; diff --git a/src/cc1111/ao_adc.c b/src/cc1111/ao_adc.c new file mode 100644 index 00000000..786dfd11 --- /dev/null +++ b/src/cc1111/ao_adc.c @@ -0,0 +1,196 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_pins.h" + +volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; +#if HAS_ACCEL_REF +volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; +#endif +volatile __data uint8_t ao_adc_head; + +void +ao_adc_poll(void) +{ +#if HAS_ACCEL_REF + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; +#else +# ifdef TELENANO_V_0_1 + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; +# else + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0; +# endif +#endif +} + +void +ao_adc_get(__xdata struct ao_adc *packet) +{ + uint8_t i = ao_adc_ring_prev(ao_sample_adc); + memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); +} + +void +ao_adc_isr(void) __interrupt 1 +{ + uint8_t sequence; + uint8_t __xdata *a; + + sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT; +#if IGNITE_ON_P2 + /* TeleMetrum readings */ +#if HAS_ACCEL_REF + if (sequence == 2) { + a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]); + sequence = 0; + } else +#endif + { + if (sequence == ADCCON3_ECH_TEMP) + sequence = 2; + a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence); + sequence++; + } +#define GOT_ADC + a[0] = ADCL; + a[1] = ADCH; + if (sequence < 6) { +#if HAS_EXTERNAL_TEMP == 0 + /* start next channel conversion */ + /* v0.2 replaces external temp sensor with internal one */ + if (sequence == 2) + ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; + else +#endif + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; + } +#endif + +#if IGNITE_ON_P0 + /* TeleMini readings */ + a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].pres); +#ifdef TELEMINI_V_1_0 + switch (sequence) { + case 0: + /* pressure */ + a += 0; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1; + break; + case 1: + /* drogue sense */ + a += 6; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; + break; + case 2: + /* main sense */ + a += 8; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; + break; + case 3: + /* battery */ + a += 4; + sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; + break; + case ADCCON3_ECH_TEMP: + a += 2; + sequence = 0; + break; + } +#define GOT_ADC +#endif +#ifdef TELENANO_V_0_1 + switch (sequence) { + case 1: + /* pressure */ + a += 0; + sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3; + break; + case 3: + /* battery */ + a += 4; + sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; + break; + case ADCCON3_ECH_TEMP: + a += 2; + sequence = 0; + break; + } +#define GOT_ADC +#endif + a[0] = ADCL; + a[1] = ADCH; + if (sequence) { + /* Start next conversion */ + ADCCON3 = sequence; + } +#endif +#ifndef GOT_ADC +#error No known ADC configuration set +#endif + + else { + /* record this conversion series */ + ao_adc_ring[ao_adc_head].tick = ao_time(); + ao_adc_head = ao_adc_ring_next(ao_adc_head); + ao_wakeup(DATA_TO_XDATA(&ao_adc_head)); + } +} + +static void +ao_adc_dump(void) __reentrant +{ + static __xdata struct ao_adc packet; + ao_adc_get(&packet); + printf("tick: %5u accel: %5d pres: %5d temp: %5d batt: %5d drogue: %5d main: %5d\n", + packet.tick, packet.accel, packet.pres, packet.temp, + packet.v_batt, packet.sense_d, packet.sense_m); +} + +__code struct ao_cmds ao_adc_cmds[] = { + { ao_adc_dump, "a\0Current ADC" }, + { 0, NULL }, +}; + +void +ao_adc_init(void) +{ +#if IGNITE_ON_P2 + /* TeleMetrum configuration */ + ADCCFG = ((1 << 0) | /* acceleration */ + (1 << 1) | /* pressure */ +#if HAS_EXTERNAL_TEMP + (1 << 2) | /* v0.1 temperature */ +#endif + (1 << 3) | /* battery voltage */ + (1 << 4) | /* drogue sense */ + (1 << 5)); /* main sense */ +#endif + +#if IGNITE_ON_P0 + /* TeleMini configuration */ + ADCCFG = ((1 << 0) | /* pressure */ + (1 << 1) | /* drogue sense */ + (1 << 2) | /* main sense */ + (1 << 3)); /* battery voltage */ +#endif + + /* enable interrupts */ + ADCIF = 0; + IEN0 |= IEN0_ADCIE; + ao_cmd_register(&ao_adc_cmds[0]); +} diff --git a/src/cc1111/ao_beep.c b/src/cc1111/ao_beep.c new file mode 100644 index 00000000..3642f4c6 --- /dev/null +++ b/src/cc1111/ao_beep.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +void +ao_beep(uint8_t beep) +{ + if (beep == 0) { + P2_0 = 0; + P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; + T4CTL = 0; + } else { + P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_PERIPHERAL; + T4CC0 = beep; + T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO | TxCTL_START; + } +} + +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant +{ + ao_beep(beep); + ao_delay(ticks); + ao_beep(0); +} + +void +ao_beep_init(void) +{ + /* Our beeper is on P2_0, which is hooked to timer 4 using + * configuration alternative 2 + */ + P2_0 = 0; + P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO; + PERCFG = (PERCFG & ~PERCFG_T4CFG_ALT_MASK) | PERCFG_T4CFG_ALT_2; + T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE; +} diff --git a/src/cc1111/ao_dbg.c b/src/cc1111/ao_dbg.c new file mode 100644 index 00000000..d4c9567f --- /dev/null +++ b/src/cc1111/ao_dbg.c @@ -0,0 +1,364 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_pins.h" + +static void +ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant +{ + DBG_PORT = (DBG_PORT & ~msk) | (val & msk); + _asm + nop + nop + _endasm; +} + +void +ao_dbg_send_byte(uint8_t byte) +{ + __pdata uint8_t b, d; + + DBG_PORT |= DBG_DATA; + DBG_PORT_DIR |= DBG_DATA; + for (b = 0; b < 8; b++) { + d = 0; + if (byte & 0x80) + d = DBG_DATA; + byte <<= 1; + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, 0 |d); + } + DBG_PORT_DIR &= ~DBG_DATA; +} + +uint8_t +ao_dbg_recv_byte(void) +{ + __pdata uint8_t byte, b; + + byte = 0; + for (b = 0; b < 8; b++) { + byte = byte << 1; + ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK); + if (DBG_DATA_PIN) + byte |= 1; + ao_dbg_send_bits(DBG_CLOCK, 0); + } + return byte; +} + +/* 8051 instructions + */ +#define NOP 0x00 +#define MOV_direct_data 0x75 +#define LJMP 0x02 +#define MOV_Rn_data(n) (0x78 | (n)) +#define DJNZ_Rn_rel(n) (0xd8 | (n)) +#define MOV_A_direct 0xe5 +#define MOV_direct1_direct2 0x85 +#define MOV_direct_A 0xf5 +#define MOV_DPTR_data16 0x90 +#define MOV_A_data 0x74 +#define MOVX_atDPTR_A 0xf0 +#define MOVX_A_atDPTR 0xe0 +#define INC_DPTR 0xa3 +#define TRAP 0xa5 +#define SJMP 0x80 +#define JB 0x20 + +#define DEBUG_INSTR(l) (0x54 | (l)) + +#define SFR_PSW 0xD0 +#define SFR_DPL0 0x82 +#define SFR_DPH0 0x83 +#define SFR_DPL1 0x84 +#define SFR_DPH1 0x85 + +__pdata uint8_t save_acc; +__pdata uint8_t save_psw; +__pdata uint8_t save_dpl0; +__pdata uint8_t save_dph0; +__pdata uint8_t save_dpl1; +__pdata uint8_t save_dph1; + +static uint8_t +ao_dbg_inst1(uint8_t a) __reentrant +{ + ao_dbg_send_byte(DEBUG_INSTR(1)); + ao_dbg_send_byte(a); + return ao_dbg_recv_byte(); +} + +static uint8_t +ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant +{ + ao_dbg_send_byte(DEBUG_INSTR(2)); + ao_dbg_send_byte(a); + ao_dbg_send_byte(b); + return ao_dbg_recv_byte(); +} + +static uint8_t +ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant +{ + ao_dbg_send_byte(DEBUG_INSTR(3)); + ao_dbg_send_byte(a); + ao_dbg_send_byte(b); + ao_dbg_send_byte(c); + return ao_dbg_recv_byte(); +} + +void +ao_dbg_start_transfer(uint16_t addr) +{ + save_acc = ao_dbg_inst1(NOP); + save_psw = ao_dbg_inst2(MOV_A_direct, SFR_PSW); + save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0); + save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0); + save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1); + save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1); + ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr); +} + +void +ao_dbg_end_transfer(void) +{ + ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0); + ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0); + ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1); + ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1); + ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw); + ao_dbg_inst2(MOV_A_data, save_acc); +} + +void +ao_dbg_write_byte(uint8_t byte) +{ + ao_dbg_inst2(MOV_A_data, byte); + ao_dbg_inst1(MOVX_atDPTR_A); + ao_dbg_inst1(INC_DPTR); +} + +uint8_t +ao_dbg_read_byte(void) +{ + ao_dbg_inst1(MOVX_A_atDPTR); + return ao_dbg_inst1(INC_DPTR); +} + +static void +ao_dbg_set_pins(void) +{ + /* Make the DBG pins GPIOs. On TeleMetrum, this will + * disable the SPI link, so don't expect SPI to work after + * using the debugger. + */ + DBG_PORT_SEL &= ~(DBG_CLOCK|DBG_DATA|DBG_RESET_N); + + /* make DBG_DATA tri-state */ + DBG_PORT_INP |= DBG_DATA; + + /* Raise RESET_N and CLOCK */ + DBG_PORT |= DBG_RESET_N | DBG_CLOCK; + + /* RESET_N and CLOCK are outputs now */ + DBG_PORT_DIR |= DBG_RESET_N | DBG_CLOCK; + DBG_PORT_DIR &= ~DBG_DATA; +} + +static void +ao_dbg_long_delay(void) +{ + uint8_t n; + + for (n = 0; n < 20; n++) + _asm nop _endasm; +} + +#define AO_RESET_LOW_DELAY AO_MS_TO_TICKS(100) +#define AO_RESET_HIGH_DELAY AO_MS_TO_TICKS(100) + +void +ao_dbg_debug_mode(void) +{ + ao_dbg_set_pins(); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); + ao_delay(AO_RESET_LOW_DELAY); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA|DBG_RESET_N); + ao_delay(AO_RESET_HIGH_DELAY); +} + +void +ao_dbg_reset(void) +{ + ao_dbg_set_pins(); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_delay(AO_RESET_LOW_DELAY); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 ); + ao_dbg_long_delay(); + ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); + ao_delay(AO_RESET_HIGH_DELAY); +} + +static void +debug_enable(void) +{ + ao_dbg_debug_mode(); +} + +static void +debug_reset(void) +{ + ao_dbg_reset(); +} + +static void +debug_put(void) +{ + for (;;) { + ao_cmd_white (); + if (ao_cmd_lex_c == '\n') + break; + ao_cmd_hex(); + if (ao_cmd_status != ao_cmd_success) + break; + ao_dbg_send_byte(ao_cmd_lex_i); + } +} + +static void +debug_get(void) +{ + __pdata uint16_t count; + __pdata uint16_t i; + __pdata uint8_t byte; + ao_cmd_hex(); + if (ao_cmd_status != ao_cmd_success) + return; + count = ao_cmd_lex_i; + if (count > 256) { + ao_cmd_status = ao_cmd_syntax_error; + return; + } + for (i = 0; i < count; i++) { + if (i && (i & 7) == 0) + putchar('\n'); + byte = ao_dbg_recv_byte(); + ao_cmd_put8(byte); + putchar(' '); + } + putchar('\n'); +} + +static uint8_t +getnibble(void) +{ + __pdata char c; + + c = getchar(); + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return c - ('a' - 10); + if ('A' <= c && c <= 'F') + return c - ('A' - 10); + ao_cmd_status = ao_cmd_lex_error; + return 0; +} + +static void +debug_input(void) +{ + __pdata uint16_t count; + __pdata uint16_t addr; + __pdata uint8_t b; + __pdata uint8_t i; + + ao_cmd_hex(); + count = ao_cmd_lex_i; + ao_cmd_hex(); + addr = ao_cmd_lex_i; + if (ao_cmd_status != ao_cmd_success) + return; + ao_dbg_start_transfer(addr); + i = 0; + while (count--) { + if (!(i++ & 7)) + putchar('\n'); + b = ao_dbg_read_byte(); + ao_cmd_put8(b); + } + ao_dbg_end_transfer(); + putchar('\n'); +} + +static void +debug_output(void) +{ + __pdata uint16_t count; + __pdata uint16_t addr; + __pdata uint8_t b; + + ao_cmd_hex(); + count = ao_cmd_lex_i; + ao_cmd_hex(); + addr = ao_cmd_lex_i; + if (ao_cmd_status != ao_cmd_success) + return; + ao_dbg_start_transfer(addr); + while (count--) { + b = getnibble() << 4; + b |= getnibble(); + if (ao_cmd_status != ao_cmd_success) + return; + ao_dbg_write_byte(b); + } + ao_dbg_end_transfer(); +} + +__code struct ao_cmds ao_dbg_cmds[7] = { + { debug_enable, "D\0Enable debug" }, + { debug_get, "G \0Get data" }, + { debug_input, "I \0Input at " }, + { debug_output, "O \0Output at " }, + { debug_put, "P ...\0Put data" }, + { debug_reset, "R\0Reset" }, + { 0, NULL }, +}; + +void +ao_dbg_init(void) +{ + ao_cmd_register(&ao_dbg_cmds[0]); +} diff --git a/src/cc1111/ao_dma.c b/src/cc1111/ao_dma.c new file mode 100644 index 00000000..6052964a --- /dev/null +++ b/src/cc1111/ao_dma.c @@ -0,0 +1,131 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +#define NUM_DMA 5 + +/* + * The config address for DMA0 is programmed + * separately from that of DMA1-4, but for simplicity, + * we make them all contiguous. + */ + +static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA]; +static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA]; +static __data uint8_t ao_next_dma; + +uint8_t +ao_dma_alloc(__xdata uint8_t *done) +{ + uint8_t id; + + if (ao_next_dma == NUM_DMA) + ao_panic(AO_PANIC_DMA); + id = ao_next_dma++; + ao_dma_done[id] = done; + + /* When the first dma object is allocated, set up the DMA + * controller + */ + if (id == 0) { + DMAIRQ = 0; + DMAIF = 0; + IEN1 |= IEN1_DMAIE; + } + + return id; +} + +void +ao_dma_set_transfer(uint8_t id, + void __xdata *srcaddr, + void __xdata *dstaddr, + uint16_t count, + uint8_t cfg0, + uint8_t cfg1) +{ + if (DMAARM & (1 << id)) + ao_panic(AO_PANIC_DMA); + ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8; + ao_dma_config[id].src_low = ((uint16_t) srcaddr); + ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8; + ao_dma_config[id].dst_low = ((uint16_t) dstaddr); + ao_dma_config[id].len_high = count >> 8; + ao_dma_config[id].len_low = count; + ao_dma_config[id].cfg0 = cfg0; + ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK; + if (id == 0) { + DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8; + DMA0CFGL = ((uint16_t) (&ao_dma_config[0])); + } else { + DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8; + DMA1CFGL = ((uint16_t) (&ao_dma_config[1])); + } +} + +#define nop() _asm nop _endasm; + +void +ao_dma_start(uint8_t id) +{ + uint8_t mask = (1 << id); + DMAIRQ &= ~mask; + DMAARM = 0x80 | mask; + nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); + *(ao_dma_done[id]) = 0; + DMAARM = mask; + nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); + nop(); +} + +void +ao_dma_trigger(uint8_t id) +{ + DMAREQ |= (1 << id); +} + +void +ao_dma_abort(uint8_t id) +{ + uint8_t mask = (1 << id); + DMAARM = 0x80 | mask; + DMAIRQ &= ~mask; +} + +void +ao_dma_isr(void) __interrupt 8 +{ + uint8_t id, mask; + + /* Find the first DMA channel which is done */ + mask = 1; + for (id = 0; id < ao_next_dma; id++) { + if (DMAIRQ & mask) { + /* Clear CPU interrupt flag */ + DMAIF = 0; + /* Clear the completed ID */ + DMAIRQ = ~mask; + *(ao_dma_done[id]) = 1; + ao_wakeup(ao_dma_done[id]); + break; + } + mask <<= 1; + } +} diff --git a/src/cc1111/ao_ignite.c b/src/cc1111/ao_ignite.c new file mode 100644 index 00000000..5238beb4 --- /dev/null +++ b/src/cc1111/ao_ignite.c @@ -0,0 +1,218 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +#if IGNITE_ON_P2 +#define AO_IGNITER_DROGUE P2_3 +#define AO_IGNITER_MAIN P2_4 +#define AO_IGNITER_DIR P2DIR +#define AO_IGNITER_DROGUE_BIT (1 << 3) +#define AO_IGNITER_MAIN_BIT (1 << 4) +#endif + +#if IGNITE_ON_P0 +#define AO_IGNITER_DROGUE P0_5 +#define AO_IGNITER_MAIN P0_4 +#define AO_IGNITER_DIR P0DIR +#define AO_IGNITER_DROGUE_BIT (1 << 5) +#define AO_IGNITER_MAIN_BIT (1 << 4) +#endif + +/* test these values with real igniters */ +#define AO_IGNITER_OPEN 1000 +#define AO_IGNITER_CLOSED 7000 +#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50) +#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000) + +struct ao_ignition { + uint8_t request; + uint8_t fired; + uint8_t firing; +}; + +__xdata struct ao_ignition ao_ignition[2]; + +void +ao_ignite(enum ao_igniter igniter) __critical +{ + ao_ignition[igniter].request = 1; + ao_wakeup(&ao_ignition); +} + +enum ao_igniter_status +ao_igniter_status(enum ao_igniter igniter) +{ + __xdata struct ao_adc adc; + __pdata int16_t value; + __pdata uint8_t request, firing, fired; + + __critical { + ao_adc_get(&adc); + request = ao_ignition[igniter].request; + fired = ao_ignition[igniter].fired; + firing = ao_ignition[igniter].firing; + } + if (firing || (request && !fired)) + return ao_igniter_active; + + value = (AO_IGNITER_CLOSED>>1); + switch (igniter) { + case ao_igniter_drogue: + value = adc.sense_d; + break; + case ao_igniter_main: + value = adc.sense_m; + break; + } + if (value < AO_IGNITER_OPEN) + return ao_igniter_open; + else if (value > AO_IGNITER_CLOSED) + return ao_igniter_ready; + else + return ao_igniter_unknown; +} + +void +ao_igniter_fire(enum ao_igniter igniter) __critical +{ + ao_ignition[igniter].firing = 1; + switch(ao_config.ignite_mode) { + case AO_IGNITE_MODE_DUAL: + switch (igniter) { + case ao_igniter_drogue: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + break; + case ao_igniter_main: + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } + break; + case AO_IGNITE_MODE_APOGEE: + switch (igniter) { + case ao_igniter_drogue: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + ao_delay(AO_IGNITER_CHARGE_TIME); + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } + break; + case AO_IGNITE_MODE_MAIN: + switch (igniter) { + case ao_igniter_main: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + ao_delay(AO_IGNITER_CHARGE_TIME); + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } + break; + } + ao_ignition[igniter].firing = 0; +} + +void +ao_igniter(void) +{ + __xdata enum ao_ignter igniter; + + ao_config_get(); + for (;;) { + ao_sleep(&ao_ignition); + for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) { + if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) { + if (igniter == ao_igniter_drogue && ao_config.apogee_delay) + ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay)); + + ao_igniter_fire(igniter); + ao_delay(AO_IGNITER_CHARGE_TIME); + ao_ignition[igniter].fired = 1; + } + } + } +} + +void +ao_ignite_manual(void) +{ + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + ao_cmd_white(); + if (ao_cmd_lex_c == 'm') { + if(ao_match_word("main")) + ao_igniter_fire(ao_igniter_main); + } else { + if(ao_match_word("drogue")) + ao_igniter_fire(ao_igniter_drogue); + } +} + +static __code char * __code igniter_status_names[] = { + "unknown", "ready", "active", "open" +}; + +void +ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant +{ + enum ao_igniter_status status = ao_igniter_status(igniter); + printf("Igniter: %6s Status: %s\n", + name, + igniter_status_names[status]); +} + +void +ao_ignite_test(void) +{ + ao_ignite_print_status(ao_igniter_drogue, "drogue"); + ao_ignite_print_status(ao_igniter_main, "main"); +} + +__code struct ao_cmds ao_ignite_cmds[] = { + { ao_ignite_manual, "i {main|drogue}\0Fire igniter. is doit with D&I" }, + { ao_ignite_test, "t\0Test igniter" }, + { 0, NULL }, +}; + +__xdata struct ao_task ao_igniter_task; + +void +ao_ignite_set_pins(void) +{ + AO_IGNITER_DROGUE = 0; + AO_IGNITER_MAIN = 0; + AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT; +} + +void +ao_igniter_init(void) +{ + ao_ignite_set_pins(); + ao_cmd_register(&ao_ignite_cmds[0]); + ao_add_task(&ao_igniter_task, ao_igniter, "igniter"); +} diff --git a/src/cc1111/ao_intflash.c b/src/cc1111/ao_intflash.c new file mode 100644 index 00000000..d76d954e --- /dev/null +++ b/src/cc1111/ao_intflash.c @@ -0,0 +1,209 @@ +/* + * Copyright © 2011 Anthony Towns + * + * 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 "ao.h" +#include "cc1111.h" + +#define ENDOFCODE (CODESIZE) +#define AO_INTFLASH_BLOCK 1024 +#define AO_INTFLASH_BLOCKS ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK) +#define AO_INTFLASH_SIZE (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS) +#define AO_INTFLASH_LOCATION (0x8000 - AO_INTFLASH_SIZE) + +/* + * 21000 * 24e6 + * FWT = ------------ + * 16e9 + * + * = 31.5 + * + * Round up and use 32 + */ + +#define FLASH_TIMING 0x20 + +#if AO_INTFLASH_BLOCKS < 2 +#error "Too few pages" +#endif + +#if AO_INFTLASH_LOCATION % 1024 != 0 +#error "Pages aren't aligned properly" +#endif + +__xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE]; + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total = sizeof(ao_intflash); + +/* Block size - device is erased in these units. */ +__pdata uint32_t ao_storage_block = AO_INTFLASH_BLOCK; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK; + +/* Storage unit size - device reads and writes must be within blocks of this size. */ +__pdata uint16_t ao_storage_unit = AO_INTFLASH_BLOCK; + +__xdata static uint8_t ao_intflash_dma_done; +static uint8_t ao_intflash_dma; + +/* + * The internal flash chip is arranged in 1kB sectors; the + * chip cannot erase in units smaller than that. + * + * Writing happens in units of 2 bytes and + * can only change bits from 1 to 0. So, you can rewrite + * the same contents, or append to an existing page easily enough + */ + +/* + * Erase the specified sector + */ +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + uint16_t addr; + + if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) + return 0; + + addr = ((uint16_t)(ao_intflash + pos) >> 1); + + FADDRH = addr >> 8; + FADDRL = addr; + + __critical { + _asm + .even + orl _FCTL, #FCTL_ERASE; ; FCTL |= FCTL_ERASE + nop ; Required, see datasheet. + _endasm; + } + + return 1; +} + +/* + * Write to flash + */ + +static void +ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant +{ + pos = ((uint16_t) ao_intflash + pos) >> 1; + + ao_dma_set_transfer(ao_intflash_dma, + d, + &FWDATAXADDR, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_FLASH, + DMA_CFG1_SRCINC_1 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_HIGH); + + FADDRH = pos >> 8; + FADDRL = pos; + + ao_dma_start(ao_intflash_dma); + + __critical { + _asm + .even + orl _FCTL, #FCTL_WRITE; ; FCTL |= FCTL_WRITE + nop + _endasm; + } +} + +static void +ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant +{ + static __xdata uint8_t b[2]; + + if (pos & 1) { + b[0] = 0xff; + b[1] = byte; + } else { + b[0] = byte; + b[1] = 0xff; + } + ao_intflash_write_aligned(pos, b, 2); +} + +uint8_t +ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant +{ + uint16_t pos = pos32; + __xdata uint8_t *d = v; + uint8_t oddlen; + + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + if (len == 0) + return 1; + + if (pos & 1) { + ao_intflash_write_byte(pos++, *d++); + len--; + } + oddlen = len & 1; + len -= oddlen; + if (len) + ao_intflash_write_aligned(pos, d, len); + if (oddlen) + ao_intflash_write_byte(pos + len, d[len]); + + return 1; +} + +/* + * Read from flash + */ +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant +{ + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + memcpy(d, ao_intflash+pos, len); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ +} + +void +ao_storage_setup(void) +{ +} + +void +ao_storage_device_info(void) __reentrant +{ + printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION); +} + +void +ao_storage_device_init(void) +{ + ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done); + + FWT = FLASH_TIMING; +} diff --git a/src/cc1111/ao_led.c b/src/cc1111/ao_led.c new file mode 100644 index 00000000..5beed58d --- /dev/null +++ b/src/cc1111/ao_led.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +__pdata uint8_t ao_led_enable; + +void +ao_led_on(uint8_t colors) +{ + P1 |= (colors & ao_led_enable); +} + +void +ao_led_off(uint8_t colors) +{ + P1 &= ~(colors & ao_led_enable); +} + +void +ao_led_set(uint8_t colors) +{ + P1 = (P1 & ~(ao_led_enable)) | (colors & ao_led_enable); +} + +void +ao_led_toggle(uint8_t colors) +{ + P1 ^= (colors & ao_led_enable); +} + +void +ao_led_for(uint8_t colors, uint16_t ticks) __reentrant +{ + ao_led_on(colors); + ao_delay(ticks); + ao_led_off(colors); +} + +void +ao_led_init(uint8_t enable) +{ + ao_led_enable = enable; + P1SEL &= ~enable; + P1 &= ~enable; + P1DIR |= enable; +} diff --git a/src/cc1111/ao_packet.c b/src/cc1111/ao_packet.c new file mode 100644 index 00000000..f627e02b --- /dev/null +++ b/src/cc1111/ao_packet.c @@ -0,0 +1,148 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +__xdata struct ao_packet_recv ao_rx_packet; +__xdata struct ao_packet ao_tx_packet; +__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; + +static __xdata char tx_data[AO_PACKET_MAX]; +static __xdata char rx_data[AO_PACKET_MAX]; +static __pdata uint8_t rx_seq; + +__xdata struct ao_task ao_packet_task; +__xdata uint8_t ao_packet_enable; +__xdata uint8_t ao_packet_master_sleeping; + +void +ao_packet_send(void) +{ + ao_led_on(AO_LED_RED); + /* If any tx data is pending then copy it into the tx packet */ + if (ao_packet_tx_used && ao_tx_packet.len == 0) { + memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); + ao_tx_packet.len = ao_packet_tx_used; + ao_tx_packet.seq++; + ao_packet_tx_used = 0; + ao_wakeup(&tx_data); + } + ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet)); + ao_led_off(AO_LED_RED); +} + +uint8_t +ao_packet_recv(void) +{ + uint8_t dma_done; + +#ifdef AO_LED_GREEN + ao_led_on(AO_LED_GREEN); +#endif + dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv)); +#ifdef AO_LED_GREEN + ao_led_off(AO_LED_GREEN); +#endif + + /* Check to see if we got a valid packet */ + if (!dma_done) + return 0; + if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) + return 0; + + /* SYN packets carry no data */ + if (ao_rx_packet.packet.len == AO_PACKET_SYN) { + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.seq = ao_rx_packet.packet.ack; + ao_tx_packet.ack = rx_seq; + } else if (ao_rx_packet.packet.len) { + + /* Check for incoming data at the next sequence and + * for an empty data buffer + */ + if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && + ao_packet_rx_used == ao_packet_rx_len) { + + /* Copy data to the receive data buffer and set up the + * offsets + */ + memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); + ao_packet_rx_used = 0; + ao_packet_rx_len = ao_rx_packet.packet.len; + + /* Mark the sequence that we've received to + * let the sender know when we return a packet + */ + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.ack = rx_seq; + + /* Poke anyone looking for received data */ + ao_wakeup(&ao_stdin_ready); + } + } + + /* If the other side has seen the latest data we queued, + * wake up any task waiting to send data and let them go again + */ + if (ao_rx_packet.packet.ack == ao_tx_packet.seq) { + ao_tx_packet.len = 0; + ao_wakeup(&ao_tx_packet); + } + return 1; +} + +#ifndef PACKET_HAS_MASTER +#define PACKET_HAS_MASTER 1 +#endif + +#if PACKET_HAS_MASTER +void +ao_packet_flush(void) +{ + /* If there is data to send, and this is the master, + * then poke the master to send all queued data + */ + if (ao_packet_tx_used && ao_packet_master_sleeping) + ao_wakeup(&ao_packet_master_sleeping); +} +#endif /* PACKET_HAS_MASTER */ + +void +ao_packet_putchar(char c) __reentrant +{ + while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) { +#if PACKET_HAS_MASTER + ao_packet_flush(); +#endif + ao_sleep(&tx_data); + } + + if (ao_packet_enable) + tx_data[ao_packet_tx_used++] = c; +} + +char +ao_packet_pollchar(void) __critical +{ + if (!ao_packet_enable) + return AO_READ_AGAIN; + + if (ao_packet_rx_used == ao_packet_rx_len) + return AO_READ_AGAIN; + + return rx_data[ao_packet_rx_used++]; +} diff --git a/src/cc1111/ao_packet_master.c b/src/cc1111/ao_packet_master.c new file mode 100644 index 00000000..b0fdf5a8 --- /dev/null +++ b/src/cc1111/ao_packet_master.c @@ -0,0 +1,144 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +static char +ao_packet_getchar(void) __critical +{ + char c; + while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) { + if (!ao_packet_enable) + break; + if (ao_packet_master_sleeping) + ao_wakeup(&ao_packet_master_sleeping); + flush(); + ao_sleep(&ao_stdin_ready); + } + return c; +} + +static void +ao_packet_echo(void) __reentrant +{ + char c; + while (ao_packet_enable) { + c = ao_packet_getchar(); + if (c != AO_READ_AGAIN) + putchar(c); + } + ao_exit(); +} + +static __xdata struct ao_task ao_packet_echo_task; +static __xdata uint16_t ao_packet_master_delay; +static __xdata uint16_t ao_packet_master_time; + +#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100) +#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000) +#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000) + +static void +ao_packet_master_busy(void) +{ + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + ao_packet_master_time = ao_time(); +} + +static void +ao_packet_master_check_busy(void) +{ + int16_t idle; + if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT) + return; + idle = (int16_t) (ao_time() - ao_packet_master_time); + + if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT) + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG; +} + +void +ao_packet_master(void) +{ + ao_config_get(); + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + ao_packet_master_time = ao_time(); + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + while (ao_packet_enable) { + memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); + ao_packet_send(); + if (ao_tx_packet.len) + ao_packet_master_busy(); + ao_packet_master_check_busy(); + ao_alarm(ao_packet_master_delay); + if (ao_packet_recv()) { + /* if we can transmit data, do so */ + if (ao_packet_tx_used && ao_tx_packet.len == 0) + continue; + if (ao_rx_packet.packet.len) + ao_packet_master_busy(); + ao_packet_master_sleeping = 1; + ao_alarm(ao_packet_master_delay); + ao_sleep(&ao_packet_master_sleeping); + ao_packet_master_sleeping = 0; + } + } + ao_exit(); +} + +static void +ao_packet_forward(void) __reentrant +{ + char c; + ao_packet_enable = 1; + ao_cmd_white(); + + flush(); +#if HAS_MONITOR + ao_set_monitor(0); +#endif + ao_add_task(&ao_packet_task, ao_packet_master, "master"); + ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo"); + while ((c = getchar()) != '~') { + if (c == '\r') c = '\n'; + ao_packet_putchar(c); + } + + /* Wait for a second if there is any pending data */ + for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++) + ao_delay(AO_MS_TO_TICKS(100)); + ao_packet_enable = 0; + while (ao_packet_echo_task.wchan || ao_packet_task.wchan) { + ao_radio_recv_abort(); + ao_wakeup(&ao_stdin_ready); + ao_delay(AO_MS_TO_TICKS(10)); + } +} + + + +__code struct ao_cmds ao_packet_master_cmds[] = { + { ao_packet_forward, "p\0Remote packet link." }, + { 0, NULL }, +}; + +void +ao_packet_master_init(void) +{ + ao_cmd_register(&ao_packet_master_cmds[0]); +} diff --git a/src/cc1111/ao_packet_slave.c b/src/cc1111/ao_packet_slave.c new file mode 100644 index 00000000..9f14052a --- /dev/null +++ b/src/cc1111/ao_packet_slave.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +void +ao_packet_slave(void) +{ + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + while (ao_packet_enable) { + if (ao_packet_recv()) { + memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); +#if HAS_FLIGHT + ao_flight_force_idle = TRUE; +#endif + ao_packet_send(); + } + } + ao_exit(); +} + +void +ao_packet_slave_start(void) +{ + ao_packet_enable = 1; + ao_add_task(&ao_packet_task, ao_packet_slave, "slave"); +} + +void +ao_packet_slave_stop(void) +{ + if (ao_packet_enable) { + ao_packet_enable = 0; + while (ao_packet_task.wchan) { + ao_radio_recv_abort(); + ao_delay(AO_MS_TO_TICKS(10)); + } + } +} + +void +ao_packet_slave_init(uint8_t enable) +{ + ao_add_stdio(ao_packet_pollchar, + ao_packet_putchar, + NULL); + if (enable) + ao_packet_slave_start(); +} diff --git a/src/cc1111/ao_radio.c b/src/cc1111/ao_radio.c new file mode 100644 index 00000000..00816b33 --- /dev/null +++ b/src/cc1111/ao_radio.c @@ -0,0 +1,475 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +/* Values from SmartRF® Studio for: + * + * Deviation: 20.507812 kHz + * Datarate: 38.360596 kBaud + * Modulation: GFSK + * RF Freq: 434.549927 MHz + * Channel: 99.975586 kHz + * Channel: 0 + * RX filter: 93.75 kHz + */ + +/* + * For IF freq of 140.62kHz, the IF value is: + * + * 140.62e3 / (24e6 / 2**10) = 6 + */ + +#define IF_FREQ_CONTROL 6 + +/* + * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are + * + * BW = 24e6 / (8 * (4 + M) * 2 ** E) + * + * So, M = 0 and E = 3 + */ + +#define CHANBW_M 0 +#define CHANBW_E 3 + +/* + * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are: + * + * R = (256 + M) * 2** E * 24e6 / 2**28 + * + * So M is 163 and E is 10 + */ + +#define DRATE_E 10 +#define DRATE_M 163 + +/* + * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are: + * + * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E + * + * So M is 6 and E is 3 + */ + +#define DEVIATION_M 6 +#define DEVIATION_E 3 + +/* + * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone), + * so the DRATE_E and DRATE_M values are: + * + * M is 94 and E is 6 + * + * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes + */ + +#define RDF_DRATE_E 6 +#define RDF_DRATE_M 94 +#define RDF_PACKET_LEN 50 + +/* + * RDF deviation should match the normal NFM value of 5kHz + * + * M is 6 and E is 1 + * + */ + +#define RDF_DEVIATION_M 6 +#define RDF_DEVIATION_E 1 + +/* This are from the table for 433MHz */ + +#define RF_POWER_M30_DBM 0x12 +#define RF_POWER_M20_DBM 0x0e +#define RF_POWER_M15_DBM 0x1d +#define RF_POWER_M10_DBM 0x34 +#define RF_POWER_M5_DBM 0x2c +#define RF_POWER_0_DBM 0x60 +#define RF_POWER_5_DBM 0x84 +#define RF_POWER_7_DBM 0xc8 +#define RF_POWER_10_DBM 0xc0 + +#define RF_POWER RF_POWER_10_DBM + +static __code uint8_t radio_setup[] = { + RF_PA_TABLE7_OFF, RF_POWER, + RF_PA_TABLE6_OFF, RF_POWER, + RF_PA_TABLE5_OFF, RF_POWER, + RF_PA_TABLE4_OFF, RF_POWER, + RF_PA_TABLE3_OFF, RF_POWER, + RF_PA_TABLE2_OFF, RF_POWER, + RF_PA_TABLE1_OFF, RF_POWER, + RF_PA_TABLE0_OFF, RF_POWER, + + RF_FSCTRL1_OFF, (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT), + RF_FSCTRL0_OFF, (0 << RF_FSCTRL0_FREQOFF_SHIFT), + + RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | + (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | + (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), + RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT), + RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF | + RF_MDMCFG2_MOD_FORMAT_GFSK | + RF_MDMCFG2_SYNC_MODE_15_16_THRES), + RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN | + RF_MDMCFG1_NUM_PREAMBLE_4 | + (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), + RF_MDMCFG0_OFF, (17 << RF_MDMCFG0_CHANSPC_M_SHIFT), + + RF_CHANNR_OFF, 0, + + RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | + (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), + + /* SmartRF says set LODIV_BUF_CURRENT_TX to 0 + * And, we're not using power ramping, so use PA_POWER 0 + */ + RF_FREND0_OFF, ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) | + (0 << RF_FREND0_PA_POWER_SHIFT)), + + RF_FREND1_OFF, ((1 << RF_FREND1_LNA_CURRENT_SHIFT) | + (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) | + (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) | + (2 << RF_FREND1_MIX_CURRENT_SHIFT)), + + RF_FSCAL3_OFF, 0xE9, + RF_FSCAL2_OFF, 0x0A, + RF_FSCAL1_OFF, 0x00, + RF_FSCAL0_OFF, 0x1F, + + RF_TEST2_OFF, 0x88, + RF_TEST1_OFF, 0x31, + RF_TEST0_OFF, 0x09, + + /* default sync values */ + RF_SYNC1_OFF, 0xD3, + RF_SYNC0_OFF, 0x91, + + /* max packet length */ + RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| + PKTCTRL1_APPEND_STATUS| + PKTCTRL1_ADR_CHK_NONE), + RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA| + RF_PKTCTRL0_PKT_FORMAT_NORMAL| + RF_PKTCTRL0_CRC_EN| + RF_PKTCTRL0_LENGTH_CONFIG_FIXED), + RF_ADDR_OFF, 0x00, + RF_MCSM2_OFF, (RF_MCSM2_RX_TIME_END_OF_PACKET), + RF_MCSM1_OFF, (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING| + RF_MCSM1_RXOFF_MODE_IDLE| + RF_MCSM1_TXOFF_MODE_IDLE), + RF_MCSM0_OFF, (RF_MCSM0_FS_AUTOCAL_FROM_IDLE| + RF_MCSM0_MAGIC_3| + RF_MCSM0_CLOSE_IN_RX_0DB), + RF_FOCCFG_OFF, (RF_FOCCFG_FOC_PRE_K_3K, + RF_FOCCFG_FOC_POST_K_PRE_K, + RF_FOCCFG_FOC_LIMIT_BW_OVER_4), + RF_BSCFG_OFF, (RF_BSCFG_BS_PRE_K_2K| + RF_BSCFG_BS_PRE_KP_3KP| + RF_BSCFG_BS_POST_KI_PRE_KI| + RF_BSCFG_BS_POST_KP_PRE_KP| + RF_BSCFG_BS_LIMIT_0), + RF_AGCCTRL2_OFF, 0x43, + RF_AGCCTRL1_OFF, 0x40, + RF_AGCCTRL0_OFF, 0x91, + + RF_IOCFG2_OFF, 0x00, + RF_IOCFG1_OFF, 0x00, + RF_IOCFG0_OFF, 0x00, +}; + +static __code uint8_t rdf_setup[] = { + RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | + (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | + (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), + RF_MDMCFG3_OFF, (RDF_DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT), + RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF | + RF_MDMCFG2_MOD_FORMAT_GFSK | + RF_MDMCFG2_SYNC_MODE_15_16_THRES), + RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_DIS | + RF_MDMCFG1_NUM_PREAMBLE_2 | + (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), + + RF_DEVIATN_OFF, ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | + (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), + + /* packet length is set in-line */ + RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| + PKTCTRL1_ADR_CHK_NONE), + RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL| + RF_PKTCTRL0_LENGTH_CONFIG_FIXED), +}; + +static __code uint8_t fixed_pkt_setup[] = { + RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) | + (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) | + (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)), + RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT), + RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF | + RF_MDMCFG2_MOD_FORMAT_GFSK | + RF_MDMCFG2_SYNC_MODE_15_16_THRES), + RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN | + RF_MDMCFG1_NUM_PREAMBLE_4 | + (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)), + + RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) | + (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)), + + /* max packet length -- now set inline */ + RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)| + PKTCTRL1_APPEND_STATUS| + PKTCTRL1_ADR_CHK_NONE), + RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA| + RF_PKTCTRL0_PKT_FORMAT_NORMAL| + RF_PKTCTRL0_CRC_EN| + RF_PKTCTRL0_LENGTH_CONFIG_FIXED), +}; + +__xdata uint8_t ao_radio_dma; +__xdata uint8_t ao_radio_dma_done; +__xdata uint8_t ao_radio_done; +__xdata uint8_t ao_radio_abort; +__xdata uint8_t ao_radio_mutex; + +void +ao_radio_general_isr(void) __interrupt 16 +{ + S1CON &= ~0x03; + if (RFIF & RFIF_IM_TIMEOUT) { + ao_radio_recv_abort(); + RFIF &= ~ RFIF_IM_TIMEOUT; + } else if (RFIF & RFIF_IM_DONE) { + ao_radio_done = 1; + ao_wakeup(&ao_radio_done); + RFIF &= ~RFIF_IM_DONE; + } +} + +void +ao_radio_set_packet(void) +{ + uint8_t i; + for (i = 0; i < sizeof (fixed_pkt_setup); i += 2) + RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1]; +} + +void +ao_radio_idle(void) +{ + if (RF_MARCSTATE != RF_MARCSTATE_IDLE) + { + do { + RFST = RFST_SIDLE; + ao_yield(); + } while (RF_MARCSTATE != RF_MARCSTATE_IDLE); + } +} + +void +ao_radio_get(uint8_t len) +{ + ao_config_get(); + ao_mutex_get(&ao_radio_mutex); + ao_radio_idle(); + RF_CHANNR = ao_config.radio_channel; + RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16); + RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8); + RF_FREQ0 = (uint8_t) (ao_config.radio_setting); + RF_PKTLEN = len; +} + + +void +ao_radio_send(__xdata void *packet, uint8_t size) __reentrant +{ + ao_radio_get(size); + ao_radio_done = 0; + ao_dma_set_transfer(ao_radio_dma, + packet, + &RFDXADDR, + size, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_RADIO, + DMA_CFG1_SRCINC_1 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_HIGH); + ao_dma_start(ao_radio_dma); + RFST = RFST_STX; + __critical while (!ao_radio_done) + ao_sleep(&ao_radio_done); + ao_radio_put(); +} + +uint8_t +ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant +{ + ao_radio_abort = 0; + ao_radio_get(size - 2); + ao_dma_set_transfer(ao_radio_dma, + &RFDXADDR, + packet, + size, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_RADIO, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_1 | + DMA_CFG1_PRIORITY_HIGH); + ao_dma_start(ao_radio_dma); + RFST = RFST_SRX; + + /* Wait for DMA to be done, for the radio receive process to + * get aborted or for a receive timeout to fire + */ + __critical while (!ao_radio_dma_done && !ao_radio_abort) + if (ao_sleep(&ao_radio_dma_done)) + break; + + /* If recv was aborted, clean up by stopping the DMA engine + * and idling the radio + */ + if (!ao_radio_dma_done) { + ao_dma_abort(ao_radio_dma); + ao_radio_idle(); + } + ao_radio_put(); + return ao_radio_dma_done; +} + +/* + * Wake up a task waiting to receive a radio packet + * and tell them to abort the transfer + */ + +void +ao_radio_recv_abort(void) +{ + ao_radio_abort = 1; + ao_wakeup(&ao_radio_dma_done); +} + +__xdata ao_radio_rdf_value = 0x55; + +void +ao_radio_rdf(int ms) +{ + uint8_t i; + uint8_t pkt_len; + + /* + * Compute the packet length as follows: + * + * 2000 bps (for a 1kHz tone) + * so, for 'ms' milliseconds, we need + * 2 * ms bits, or ms / 4 bytes + */ + if (ms > (255 * 4)) + ms = 255 * 4; + pkt_len = ms >> 2; + + ao_radio_abort = 0; + ao_radio_get(pkt_len); + ao_radio_done = 0; + for (i = 0; i < sizeof (rdf_setup); i += 2) + RF[rdf_setup[i]] = rdf_setup[i+1]; + + ao_dma_set_transfer(ao_radio_dma, + &ao_radio_rdf_value, + &RFDXADDR, + pkt_len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_RADIO, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_HIGH); + ao_dma_start(ao_radio_dma); + RFST = RFST_STX; + __critical while (!ao_radio_done && !ao_radio_abort) + ao_sleep(&ao_radio_done); + if (!ao_radio_done) { + ao_dma_abort(ao_radio_dma); + ao_radio_idle(); + } + ao_radio_set_packet(); + ao_radio_put(); +} + +void +ao_radio_rdf_abort(void) +{ + ao_radio_abort = 1; + ao_wakeup(&ao_radio_done); +} + + +/* Output carrier */ +void +ao_radio_test(void) +{ + uint8_t mode = 2; + static __xdata radio_on; + ao_cmd_white(); + if (ao_cmd_lex_c != '\n') { + ao_cmd_decimal(); + mode = (uint8_t) ao_cmd_lex_u32; + } + mode++; + if ((mode & 2) && !radio_on) { +#if HAS_MONITOR + ao_set_monitor(0); +#endif +#if PACKET_HAS_SLAVE + ao_packet_slave_stop(); +#endif + ao_radio_get(0xff); + RFST = RFST_STX; + radio_on = 1; + } + if (mode == 3) { + printf ("Hit a character to stop..."); flush(); + getchar(); + putchar('\n'); + } + if ((mode & 1) && radio_on) { + ao_radio_idle(); + ao_radio_put(); + radio_on = 0; + } +} + +__code struct ao_cmds ao_radio_cmds[] = { + { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" }, + { 0, NULL }, +}; + +void +ao_radio_init(void) +{ + uint8_t i; + for (i = 0; i < sizeof (radio_setup); i += 2) + RF[radio_setup[i]] = radio_setup[i+1]; + ao_radio_set_packet(); + ao_radio_dma_done = 1; + ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done); + RFIF = 0; + RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE; + IEN2 |= IEN2_RFIE; + ao_cmd_register(&ao_radio_cmds[0]); +} diff --git a/src/cc1111/ao_reboot.c b/src/cc1111/ao_reboot.c new file mode 100644 index 00000000..8c47b893 --- /dev/null +++ b/src/cc1111/ao_reboot.c @@ -0,0 +1,28 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +/* Use the watchdog timer to force a complete reboot + */ +void +ao_reboot(void) +{ + WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_32768; + ao_delay(AO_SEC_TO_TICKS(2)); + ao_panic(AO_PANIC_REBOOT); +} diff --git a/src/cc1111/ao_romconfig.c b/src/cc1111/ao_romconfig.c new file mode 100644 index 00000000..f3fe61b1 --- /dev/null +++ b/src/cc1111/ao_romconfig.c @@ -0,0 +1,32 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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 "ao.h" + +__code __at (0x00a0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION; +__code __at (0x00a2) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION; +__code __at (0x00a4) uint16_t ao_serial_number = 0; +/* + * For 434.550MHz, the frequency value is: + * + * 434.550e6 / (24e6 / 2**16) = 1186611.2 + * + * This value is stored in a const variable so that + * ao-load can change it during programming for + * devices that have no eeprom for config data. + */ +__code __at (0x00a6) uint32_t ao_radio_cal = 1186611; diff --git a/src/cc1111/ao_serial.c b/src/cc1111/ao_serial.c new file mode 100644 index 00000000..82370c64 --- /dev/null +++ b/src/cc1111/ao_serial.c @@ -0,0 +1,175 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +volatile __xdata struct ao_fifo ao_usart1_rx_fifo; +volatile __xdata struct ao_fifo ao_usart1_tx_fifo; + +void +ao_serial_rx1_isr(void) __interrupt 3 +{ + if (!ao_fifo_full(ao_usart1_rx_fifo)) + ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF); + ao_wakeup(&ao_usart1_rx_fifo); +#if USE_SERIAL_STDIN + ao_wakeup(&ao_stdin_ready); +#endif +} + +static __xdata uint8_t ao_serial_tx1_started; + +static void +ao_serial_tx1_start(void) +{ + if (!ao_fifo_empty(ao_usart1_tx_fifo) && + !ao_serial_tx1_started) + { + ao_serial_tx1_started = 1; + ao_fifo_remove(ao_usart1_tx_fifo, U1DBUF); + } +} + +void +ao_serial_tx1_isr(void) __interrupt 14 +{ + UTX1IF = 0; + ao_serial_tx1_started = 0; + ao_serial_tx1_start(); + ao_wakeup(&ao_usart1_tx_fifo); +} + +char +ao_serial_getchar(void) __critical +{ + char c; + while (ao_fifo_empty(ao_usart1_rx_fifo)) + ao_sleep(&ao_usart1_rx_fifo); + ao_fifo_remove(ao_usart1_rx_fifo, c); + return c; +} + +#if USE_SERIAL_STDIN +char +ao_serial_pollchar(void) __critical +{ + char c; + if (ao_fifo_empty(ao_usart1_rx_fifo)) + return AO_READ_AGAIN; + ao_fifo_remove(ao_usart1_rx_fifo,c); + return c; +} +#endif + +void +ao_serial_putchar(char c) __critical +{ + while (ao_fifo_full(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); + ao_fifo_insert(ao_usart1_tx_fifo, c); + ao_serial_tx1_start(); +} + +void +ao_serial_drain(void) __critical +{ + while (!ao_fifo_empty(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); +} + +static __code struct { + uint8_t baud; + uint8_t gcr; +} ao_serial_speeds[] = { + /* [AO_SERIAL_SPEED_4800] = */ { + /* .baud = */ 163, + /* .gcr = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, + /* [AO_SERIAL_SPEED_9600] = */ { + /* .baud = */ 163, + /* .gcr = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, + /* [AO_SERIAL_SPEED_19200] = */ { + /* .baud = */ 163, + /* .gcr = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, + /* [AO_SERIAL_SPEED_57600] = */ { + /* .baud = */ 59, + /* .gcr = */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB + }, +}; + +void +ao_serial_set_speed(uint8_t speed) +{ + ao_serial_drain(); + if (speed > AO_SERIAL_SPEED_57600) + return; + U1UCR |= UxUCR_FLUSH; + U1BAUD = ao_serial_speeds[speed].baud; + U1GCR = ao_serial_speeds[speed].gcr; +} + +void +ao_serial_init(void) +{ +#if HAS_SERIAL_1_ALT_1 + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1; + + P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0; + + /* Make the USART pins be controlled by the USART */ + P0SEL |= (1 << 5) | (1 << 4); +#if HAS_SERIAL_1_HW_FLOW + P0SEL |= (1 << 3) | (1 << 2); +#endif +#else + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2; + + P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) | + (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1); + + /* Make the USART pins be controlled by the USART */ + P1SEL |= (1 << 6) | (1 << 7); + P1SEL |= (1 << 5) | (1 << 4); +#endif + + /* UART mode with receiver enabled */ + U1CSR = (UxCSR_MODE_UART | UxCSR_RE); + + /* Pick a 4800 baud rate */ + ao_serial_set_speed(AO_SERIAL_SPEED_4800); + + /* Reasonable serial parameters */ + U1UCR = (UxUCR_FLUSH | +#if HAS_SERIAL_1_HW_FLOW + UxUCR_FLOW_ENABLE | +#else + UxUCR_FLOW_DISABLE | +#endif + UxUCR_D9_EVEN_PARITY | + UxUCR_BIT9_8_BITS | + UxUCR_PARITY_DISABLE | + UxUCR_SPB_1_STOP_BIT | + UxUCR_STOP_HIGH | + UxUCR_START_LOW); + + IEN0 |= IEN0_URX1IE; + IEN2 |= IEN2_UTX1IE; +} diff --git a/src/cc1111/ao_spi.c b/src/cc1111/ao_spi.c new file mode 100644 index 00000000..fbe613c7 --- /dev/null +++ b/src/cc1111/ao_spi.c @@ -0,0 +1,157 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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 "ao.h" + +/* Shared mutex to protect SPI bus, must cover the entire + * operation, from CS low to CS high. This means that any SPI + * user must protect the SPI bus with this mutex + */ +__xdata uint8_t ao_spi_mutex; +__xdata uint8_t ao_spi_dma_in_done; +__xdata uint8_t ao_spi_dma_out_done; + +uint8_t ao_spi_dma_out_id; +uint8_t ao_spi_dma_in_id; + +static __xdata uint8_t ao_spi_const = 0xff; + +/* Send bytes over SPI. + * + * This sets up two DMA engines, one writing the data and another reading + * bytes coming back. We use the bytes coming back to tell when the transfer + * is complete, as the transmit register is double buffered and hence signals + * completion one byte before the transfer is actually complete + */ +void +ao_spi_send(void __xdata *block, uint16_t len) __reentrant +{ + ao_dma_set_transfer(ao_spi_dma_in_id, + &U0DBUFXADDR, + &ao_spi_const, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_URX0, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_set_transfer(ao_spi_dma_out_id, + block, + &U0DBUFXADDR, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_UTX0, + DMA_CFG1_SRCINC_1 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_start(ao_spi_dma_in_id); + ao_dma_start(ao_spi_dma_out_id); + ao_dma_trigger(ao_spi_dma_out_id); + __critical while (!ao_spi_dma_in_done) + ao_sleep(&ao_spi_dma_in_done); +} + +/* Receive bytes over SPI. + * + * This sets up tow DMA engines, one reading the data and another + * writing constant values to the SPI transmitter as that is what + * clocks the data coming in. + */ +void +ao_spi_recv(void __xdata *block, uint16_t len) __reentrant +{ + ao_dma_set_transfer(ao_spi_dma_in_id, + &U0DBUFXADDR, + block, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_URX0, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_1 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_set_transfer(ao_spi_dma_out_id, + &ao_spi_const, + &U0DBUFXADDR, + len, + DMA_CFG0_WORDSIZE_8 | + DMA_CFG0_TMODE_SINGLE | + DMA_CFG0_TRIGGER_UTX0, + DMA_CFG1_SRCINC_0 | + DMA_CFG1_DESTINC_0 | + DMA_CFG1_PRIORITY_NORMAL); + + ao_dma_start(ao_spi_dma_in_id); + ao_dma_start(ao_spi_dma_out_id); + ao_dma_trigger(ao_spi_dma_out_id); + __critical while (!ao_spi_dma_in_done) + ao_sleep(&ao_spi_dma_in_done); +} + +/* + * Initialize USART0 for SPI using config alt 2 + * + * MO P1_5 + * MI P1_4 + * CLK P1_3 + * + * Chip select is the responsibility of the caller + */ + +void +ao_spi_init(void) +{ + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2; + + /* Ensure that USART0 takes precidence over USART1 for pins that + * they share + */ + P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | P2SEL_PRI3P1_USART0; + + /* Make the SPI pins be controlled by the USART peripheral */ + P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3)); + + /* Set up OUT DMA */ + ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done); + + /* Set up IN DMA */ + ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done); + + /* Set up the USART. + * + * SPI master mode + */ + U0CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_MASTER); + + /* Set the baud rate and signal parameters + * + * The cc1111 is limited to a 24/8 MHz SPI clock. + * Every peripheral I've ever seen goes faster than that, + * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0) + */ + U0BAUD = 0; + U0GCR = (UxGCR_CPOL_NEGATIVE | + UxGCR_CPHA_FIRST_EDGE | + UxGCR_ORDER_MSB | + (17 << UxGCR_BAUD_E_SHIFT)); +} diff --git a/src/cc1111/ao_timer.c b/src/cc1111/ao_timer.c new file mode 100644 index 00000000..c977fbc8 --- /dev/null +++ b/src/cc1111/ao_timer.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +static volatile __data uint16_t ao_tick_count; + +uint16_t ao_time(void) __critical +{ + return ao_tick_count; +} + +static __xdata uint8_t ao_forever; + +void +ao_delay(uint16_t ticks) +{ + ao_alarm(ticks); + ao_sleep(&ao_forever); +} + +#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ +#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ + +#if HAS_ADC +volatile __data uint8_t ao_adc_interval = 1; +volatile __data uint8_t ao_adc_count; +#endif + +void ao_timer_isr(void) __interrupt 9 +{ + ++ao_tick_count; +#if HAS_ADC + if (++ao_adc_count == ao_adc_interval) { + ao_adc_count = 0; + ao_adc_poll(); + } +#endif +} + +#if HAS_ADC +void +ao_timer_set_adc_interval(uint8_t interval) __critical +{ + ao_adc_interval = interval; + ao_adc_count = 0; +} +#endif + +void +ao_timer_init(void) +{ + /* NOTE: This uses a timer only present on cc1111 architecture. */ + + /* disable timer 1 */ + T1CTL = 0; + + /* set the sample rate */ + T1CC0H = T1_SAMPLE_TIME >> 8; + T1CC0L = (uint8_t) T1_SAMPLE_TIME; + + T1CCTL0 = T1CCTL_MODE_COMPARE; + T1CCTL1 = 0; + T1CCTL2 = 0; + + /* clear timer value */ + T1CNTL = 0; + + /* enable overflow interrupt */ + OVFIM = 1; + /* enable timer 1 interrupt */ + T1IE = 1; + + /* enable timer 1 in module mode, dividing by 8 */ + T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8; +} + +/* + * AltOS always cranks the clock to the max frequency + */ +void +ao_clock_init(void) +{ + /* Switch system clock to crystal oscilator */ + CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL); + + while (!(SLEEP & SLEEP_XOSC_STB)) + ; + + /* Crank up the timer tick and system clock speed */ + CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) | + (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)); + + while ((CLKCON & (CLKCON_TICKSPD_MASK|CLKCON_CLKSPD_MASK)) != + (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1)) + ; +} diff --git a/src/cc1111/ao_usb.c b/src/cc1111/ao_usb.c new file mode 100644 index 00000000..08cb7390 --- /dev/null +++ b/src/cc1111/ao_usb.c @@ -0,0 +1,460 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_usb.h" + +struct ao_task __xdata ao_usb_task; + +static __xdata uint16_t ao_usb_in_bytes; +static __pdata uint16_t ao_usb_in_bytes_last; +static __xdata uint16_t ao_usb_out_bytes; +static __pdata uint8_t ao_usb_iif; +static __pdata uint8_t ao_usb_running; + +static void +ao_usb_set_interrupts(void) +{ + /* IN interrupts on the control an IN endpoints */ + USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP); + + /* OUT interrupts on the OUT endpoint */ + USBOIE = (1 << AO_USB_OUT_EP); + + /* Only care about reset */ + USBCIE = USBCIE_RSTIE; +} + +/* This interrupt is shared with port 2, + * so when we hook that up, fix this + */ +void +ao_usb_isr(void) __interrupt 6 +{ + USBIF = 0; + ao_usb_iif |= USBIIF; + if (ao_usb_iif & 1) + ao_wakeup(&ao_usb_task); + if (ao_usb_iif & (1 << AO_USB_IN_EP)) + ao_wakeup(&ao_usb_in_bytes); + + if (USBOIF & (1 << AO_USB_OUT_EP)) + ao_wakeup(&ao_stdin_ready); + + if (USBCIF & USBCIF_RSTIF) + ao_usb_set_interrupts(); +#if HAS_BTM +#if BT_LINK_ON_P2 + ao_btm_isr(); +#endif +#endif +} + +struct ao_usb_setup { + uint8_t dir_type_recip; + uint8_t request; + uint16_t value; + uint16_t index; + uint16_t length; +} __xdata ao_usb_setup; + +__pdata uint8_t ao_usb_ep0_state; +uint8_t * __pdata ao_usb_ep0_in_data; +__pdata uint8_t ao_usb_ep0_in_len; +__pdata uint8_t ao_usb_ep0_in_buf[2]; +__pdata uint8_t ao_usb_ep0_out_len; +__xdata uint8_t *__pdata ao_usb_ep0_out_data; +__pdata uint8_t ao_usb_configuration; + +/* Send an IN data packet */ +static void +ao_usb_ep0_flush(void) +{ + __pdata uint8_t this_len; + __pdata uint8_t cs0; + + /* If the IN packet hasn't been picked up, just return */ + USBINDEX = 0; + cs0 = USBCS0; + if (cs0 & USBCS0_INPKT_RDY) + return; + + this_len = ao_usb_ep0_in_len; + if (this_len > AO_USB_CONTROL_SIZE) + this_len = AO_USB_CONTROL_SIZE; + cs0 = USBCS0_INPKT_RDY; + if (this_len != AO_USB_CONTROL_SIZE) { + cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END; + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } + ao_usb_ep0_in_len -= this_len; + while (this_len--) + USBFIFO[0] = *ao_usb_ep0_in_data++; + USBINDEX = 0; + USBCS0 = cs0; +} + +__xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; + +/* Walk through the list of descriptors and find a match + */ +static void +ao_usb_get_descriptor(uint16_t value) +{ + __code uint8_t *__pdata descriptor; + __pdata uint8_t type = value >> 8; + __pdata uint8_t index = value; + + descriptor = ao_usb_descriptors; + while (descriptor[0] != 0) { + if (descriptor[1] == type && index-- == 0) { + if (type == AO_USB_DESC_CONFIGURATION) + ao_usb_ep0_in_len = descriptor[2]; + else + ao_usb_ep0_in_len = descriptor[0]; + ao_usb_ep0_in_data = descriptor; + break; + } + descriptor += descriptor[0]; + } +} + +/* Read data from the ep0 OUT fifo + */ +static void +ao_usb_ep0_fill(void) +{ + __pdata uint8_t len; + + USBINDEX = 0; + len = USBCNT0; + if (len > ao_usb_ep0_out_len) + len = ao_usb_ep0_out_len; + ao_usb_ep0_out_len -= len; + while (len--) + *ao_usb_ep0_out_data++ = USBFIFO[0]; +} + +void +ao_usb_ep0_queue_byte(uint8_t a) +{ + ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; +} + +void +ao_usb_set_address(uint8_t address) +{ + ao_usb_running = 1; + USBADDR = address | 0x80; + while (USBADDR & 0x80) + ; +} + +static void +ao_usb_set_configuration(void) +{ + /* Set the IN max packet size, double buffered */ + USBINDEX = AO_USB_IN_EP; + USBMAXI = AO_USB_IN_SIZE >> 3; + USBCSIH |= USBCSIH_IN_DBL_BUF; + + /* Set the OUT max packet size, double buffered */ + USBINDEX = AO_USB_OUT_EP; + USBMAXO = AO_USB_OUT_SIZE >> 3; + USBCSOH = USBCSOH_OUT_DBL_BUF; +} + +static void +ao_usb_ep0_setup(void) +{ + /* Pull the setup packet out of the fifo */ + ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup; + ao_usb_ep0_out_len = 8; + ao_usb_ep0_fill(); + if (ao_usb_ep0_out_len != 0) + return; + + /* Figure out how to ACK the setup packet */ + if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) { + if (ao_usb_setup.length) + ao_usb_ep0_state = AO_USB_EP0_DATA_IN; + else + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } else { + if (ao_usb_setup.length) + ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; + else + ao_usb_ep0_state = AO_USB_EP0_IDLE; + } + USBINDEX = 0; + if (ao_usb_ep0_state == AO_USB_EP0_IDLE) + USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; + else + USBCS0 = USBCS0_CLR_OUTPKT_RDY; + + ao_usb_ep0_in_data = ao_usb_ep0_in_buf; + ao_usb_ep0_in_len = 0; + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { + case AO_USB_TYPE_STANDARD: + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) { + case AO_USB_RECIP_DEVICE: + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_SET_ADDRESS: + ao_usb_set_address(ao_usb_setup.value); + break; + case AO_USB_REQ_GET_DESCRIPTOR: + ao_usb_get_descriptor(ao_usb_setup.value); + break; + case AO_USB_REQ_GET_CONFIGURATION: + ao_usb_ep0_queue_byte(ao_usb_configuration); + break; + case AO_USB_REQ_SET_CONFIGURATION: + ao_usb_configuration = ao_usb_setup.value; + ao_usb_set_configuration(); + break; + } + break; + case AO_USB_RECIP_INTERFACE: + #pragma disable_warning 110 + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_GET_INTERFACE: + ao_usb_ep0_queue_byte(0); + break; + case AO_USB_REQ_SET_INTERFACE: + break; + } + break; + case AO_USB_RECIP_ENDPOINT: + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_queue_byte(0); + ao_usb_ep0_queue_byte(0); + break; + } + break; + } + break; + case AO_USB_TYPE_CLASS: + switch (ao_usb_setup.request) { + case SET_LINE_CODING: + ao_usb_ep0_out_len = 7; + ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; + break; + case GET_LINE_CODING: + ao_usb_ep0_in_len = 7; + ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; + break; + case SET_CONTROL_LINE_STATE: + break; + } + break; + } + if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) { + if (ao_usb_setup.length < ao_usb_ep0_in_len) + ao_usb_ep0_in_len = ao_usb_setup.length; + ao_usb_ep0_flush(); + } +} + +/* End point 0 receives all of the control messages. */ +static void +ao_usb_ep0(void) +{ + __pdata uint8_t cs0; + + ao_usb_ep0_state = AO_USB_EP0_IDLE; + for (;;) { + __critical for (;;) { + if (ao_usb_iif & 1) { + ao_usb_iif &= ~1; + break; + } + ao_sleep(&ao_usb_task); + } + USBINDEX = 0; + cs0 = USBCS0; + if (cs0 & USBCS0_SETUP_END) { + ao_usb_ep0_state = AO_USB_EP0_IDLE; + USBCS0 = USBCS0_CLR_SETUP_END; + } + if (cs0 & USBCS0_SENT_STALL) { + ao_usb_ep0_state = AO_USB_EP0_IDLE; + USBCS0 &= ~USBCS0_SENT_STALL; + } + if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN && + (cs0 & USBCS0_INPKT_RDY) == 0) + { + ao_usb_ep0_flush(); + } + if (cs0 & USBCS0_OUTPKT_RDY) { + switch (ao_usb_ep0_state) { + case AO_USB_EP0_IDLE: + ao_usb_ep0_setup(); + break; + case AO_USB_EP0_DATA_OUT: + ao_usb_ep0_fill(); + if (ao_usb_ep0_out_len == 0) + ao_usb_ep0_state = AO_USB_EP0_IDLE; + USBINDEX = 0; + if (ao_usb_ep0_state == AO_USB_EP0_IDLE) + USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; + else + USBCS0 = USBCS0_CLR_OUTPKT_RDY; + break; + } + } + } +} + +/* Wait for a free IN buffer */ +static void +ao_usb_in_wait(void) +{ + for (;;) { + USBINDEX = AO_USB_IN_EP; + if ((USBCSIL & USBCSIL_INPKT_RDY) == 0) + break; + ao_sleep(&ao_usb_in_bytes); + } +} + +/* Send the current IN packet */ +static void +ao_usb_in_send(void) +{ + USBINDEX = AO_USB_IN_EP; + USBCSIL |= USBCSIL_INPKT_RDY; + ao_usb_in_bytes_last = ao_usb_in_bytes; + ao_usb_in_bytes = 0; +} + +void +ao_usb_flush(void) __critical +{ + if (!ao_usb_running) + return; + + /* If there are pending bytes, or if the last packet was full, + * send another IN packet + */ + if (ao_usb_in_bytes || (ao_usb_in_bytes_last == AO_USB_IN_SIZE)) { + ao_usb_in_wait(); + ao_usb_in_send(); + } +} + +void +ao_usb_putchar(char c) __critical __reentrant +{ + if (!ao_usb_running) + return; + + ao_usb_in_wait(); + + /* Queue a byte, sending the packet when full */ + USBFIFO[AO_USB_IN_EP << 1] = c; + if (++ao_usb_in_bytes == AO_USB_IN_SIZE) + ao_usb_in_send(); +} + +char +ao_usb_pollchar(void) __critical +{ + char c; + if (ao_usb_out_bytes == 0) { + USBINDEX = AO_USB_OUT_EP; + if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) + return AO_READ_AGAIN; + ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL; + if (ao_usb_out_bytes == 0) { + USBINDEX = AO_USB_OUT_EP; + USBCSOL &= ~USBCSOL_OUTPKT_RDY; + return AO_READ_AGAIN; + } + } + --ao_usb_out_bytes; + c = USBFIFO[AO_USB_OUT_EP << 1]; + if (ao_usb_out_bytes == 0) { + USBINDEX = AO_USB_OUT_EP; + USBCSOL &= ~USBCSOL_OUTPKT_RDY; + } + return c; +} + +char +ao_usb_getchar(void) __critical +{ + char c; + + while ((c = ao_usb_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_stdin_ready); + return c; +} + +void +ao_usb_enable(void) +{ + /* Turn on the USB controller */ + SLEEP |= SLEEP_USB_EN; + + ao_usb_set_configuration(); + + ao_usb_set_interrupts(); + + /* enable USB interrupts */ + IEN2 |= IEN2_USBIE; + + /* Clear any pending interrupts */ + USBCIF = 0; + USBOIF = 0; + USBIIF = 0; +} + +void +ao_usb_disable(void) +{ + /* Disable USB interrupts */ + USBIIE = 0; + USBOIE = 0; + USBCIE = 0; + IEN2 &= ~IEN2_USBIE; + + /* Clear any pending interrupts */ + USBCIF = 0; + USBOIF = 0; + USBIIF = 0; + + /* Turn off the USB controller */ + SLEEP &= ~SLEEP_USB_EN; +} + +void +ao_usb_init(void) +{ + ao_usb_enable(); + + ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); + ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); +} diff --git a/src/cc1111/ao_usb.h b/src/cc1111/ao_usb.h new file mode 100644 index 00000000..6633dafc --- /dev/null +++ b/src/cc1111/ao_usb.h @@ -0,0 +1,100 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef _AO_USB_H_ +#define _AO_USB_H_ + +#define AO_USB_SETUP_DIR_MASK (0x01 << 7) +#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) +#define AO_USB_SETUP_RECIP_MASK (0x1f) + +#define AO_USB_DIR_OUT 0 +#define AO_USB_DIR_IN (1 << 7) + +#define AO_USB_TYPE_STANDARD 0 +#define AO_USB_TYPE_CLASS (1 << 5) +#define AO_USB_TYPE_VENDOR (2 << 5) +#define AO_USB_TYPE_RESERVED (3 << 5) + +#define AO_USB_RECIP_DEVICE 0 +#define AO_USB_RECIP_INTERFACE 1 +#define AO_USB_RECIP_ENDPOINT 2 +#define AO_USB_RECIP_OTHER 3 + +/* standard requests */ +#define AO_USB_REQ_GET_STATUS 0x00 +#define AO_USB_REQ_CLEAR_FEATURE 0x01 +#define AO_USB_REQ_SET_FEATURE 0x03 +#define AO_USB_REQ_SET_ADDRESS 0x05 +#define AO_USB_REQ_GET_DESCRIPTOR 0x06 +#define AO_USB_REQ_SET_DESCRIPTOR 0x07 +#define AO_USB_REQ_GET_CONFIGURATION 0x08 +#define AO_USB_REQ_SET_CONFIGURATION 0x09 +#define AO_USB_REQ_GET_INTERFACE 0x0A +#define AO_USB_REQ_SET_INTERFACE 0x0B +#define AO_USB_REQ_SYNCH_FRAME 0x0C + +#define AO_USB_DESC_DEVICE 1 +#define AO_USB_DESC_CONFIGURATION 2 +#define AO_USB_DESC_STRING 3 +#define AO_USB_DESC_INTERFACE 4 +#define AO_USB_DESC_ENDPOINT 5 +#define AO_USB_DESC_DEVICE_QUALIFIER 6 +#define AO_USB_DESC_OTHER_SPEED 7 +#define AO_USB_DESC_INTERFACE_POWER 8 + +#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) +#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) + +#define AO_USB_CONTROL_EP 0 +#define AO_USB_INT_EP 1 +#define AO_USB_OUT_EP 4 +#define AO_USB_IN_EP 5 +#define AO_USB_CONTROL_SIZE 32 +/* + * Double buffer IN and OUT EPs, so each + * gets half of the available space + * + * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 + * byte sizes, so we'll use 64 for everything + */ +#define AO_USB_IN_SIZE 64 +#define AO_USB_OUT_SIZE 64 + +#define AO_USB_EP0_IDLE 0 +#define AO_USB_EP0_DATA_IN 1 +#define AO_USB_EP0_DATA_OUT 2 + +#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) + +/* CDC definitions */ +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 + +/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ +struct ao_usb_line_coding { + uint32_t rate; + uint8_t char_format; + uint8_t parity; + uint8_t data_bits; +} ; + +#endif /* _AO_USB_H_ */ diff --git a/src/cc1111/cc1111.h b/src/cc1111/cc1111.h new file mode 100644 index 00000000..e52aa79f --- /dev/null +++ b/src/cc1111/cc1111.h @@ -0,0 +1,1306 @@ +/*------------------------------------------------------------------------- + Register Declarations for the ChipCon CC1111 Processor Range + + Copyright © 2008 Keith Packard + + 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. + + Adapted from the Cygnal C8051F12x config file which is: + + Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-------------------------------------------------------------------------*/ + +#ifndef _CC1111_H_ +#define _CC1111_H_ +#include +#include + +__sfr __at 0xA8 IEN0; /* Interrupt Enable 0 Register */ + +sbit __at 0xA8 RFTXRXIE; /* RF TX/RX done interrupt enable */ +sbit __at 0xA9 ADCIE; /* ADC interrupt enable */ +sbit __at 0xAA URX0IE; /* USART0 RX interrupt enable */ +sbit __at 0xAB URX1IE; /* USART1 RX interrupt enable (shared with I2S RX) */ +sbit __at 0xAB I2SRXIE; /* I2S RX interrupt enable (shared with USART1 RX) */ +sbit __at 0xAC ENCIE; /* AES encryption/decryption interrupt enable */ +sbit __at 0xAD STIE; /* Sleep Timer interrupt enable */ +sbit __at 0xAF EA; /* Enable All */ + +#define IEN0_EA (1 << 7) +#define IEN0_STIE (1 << 5) +#define IEN0_ENCIE (1 << 4) +#define IEN0_URX1IE (1 << 3) +#define IEN0_I2SRXIE (1 << 3) +#define IEN0_URX0IE (1 << 2) +#define IEN0_ADCIE (1 << 1) +#define IEN0_RFTXRXIE (1 << 0) + +__sfr __at 0xB8 IEN1; /* Interrupt Enable 1 Register */ + +#define IEN1_P0IE (1 << 5) /* Port 0 interrupt enable */ +#define IEN1_T4IE (1 << 4) /* Timer 4 interrupt enable */ +#define IEN1_T3IE (1 << 3) /* Timer 3 interrupt enable */ +#define IEN1_T2IE (1 << 2) /* Timer 2 interrupt enable */ +#define IEN1_T1IE (1 << 1) /* Timer 1 interrupt enable */ +#define IEN1_DMAIE (1 << 0) /* DMA transfer interrupt enable */ + +/* IEN2 */ +__sfr __at 0x9A IEN2; /* Interrupt Enable 2 Register */ + +#define IEN2_WDTIE (1 << 5) /* Watchdog timer interrupt enable */ +#define IEN2_P1IE (1 << 4) /* Port 1 interrupt enable */ +#define IEN2_UTX1IE (1 << 3) /* USART1 TX interrupt enable */ +#define IEN2_I2STXIE (1 << 3) /* I2S TX interrupt enable */ +#define IEN2_UTX0IE (1 << 2) /* USART0 TX interrupt enable */ +#define IEN2_P2IE (1 << 1) /* Port 2 interrupt enable */ +#define IEN2_USBIE (1 << 1) /* USB interrupt enable */ +#define IEN2_RFIE (1 << 0) /* RF general interrupt enable */ + +/* CLKCON 0xC6 */ +__sfr __at 0xC6 CLKCON; /* Clock Control */ + +#define CLKCON_OSC32K_RC (1 << 7) +#define CLKCON_OSC32K_XTAL (0 << 7) +#define CLKCON_OSC32K_MASK (1 << 7) +#define CLKCON_OSC_RC (1 << 6) +#define CLKCON_OSC_XTAL (0 << 6) +#define CLKCON_OSC_MASK (1 << 6) +#define CLKCON_TICKSPD_MASK (7 << 3) +# define CLKCON_TICKSPD_1 (0 << 3) +# define CLKCON_TICKSPD_1_2 (1 << 3) +# define CLKCON_TICKSPD_1_4 (2 << 3) +# define CLKCON_TICKSPD_1_8 (3 << 3) +# define CLKCON_TICKSPD_1_16 (4 << 3) +# define CLKCON_TICKSPD_1_32 (5 << 3) +# define CLKCON_TICKSPD_1_64 (6 << 3) +# define CLKCON_TICKSPD_1_128 (7 << 3) + +#define CLKCON_CLKSPD_MASK (7 << 0) +# define CLKCON_CLKSPD_1 (0 << 0) +# define CLKCON_CLKSPD_1_2 (1 << 0) +# define CLKCON_CLKSPD_1_4 (2 << 0) +# define CLKCON_CLKSPD_1_8 (3 << 0) +# define CLKCON_CLKSPD_1_16 (4 << 0) +# define CLKCON_CLKSPD_1_32 (5 << 0) +# define CLKCON_CLKSPD_1_64 (6 << 0) +# define CLKCON_CLKSPD_1_128 (7 << 0) + +/* SLEEP 0xBE */ +#define SLEEP_USB_EN (1 << 7) +#define SLEEP_XOSC_STB (1 << 6) +#define SLEEP_HFRC_STB (1 << 5) +#define SLEEP_RST_POWER (0 << 3) +#define SLEEP_RST_EXTERNAL (1 << 3) +#define SLEEP_RST_WATCHDOG (2 << 3) +#define SLEEP_RST_MASK (3 << 3) +#define SLEEP_OSC_PD (1 << 2) +#define SLEEP_MODE_PM0 (0 << 0) +#define SLEEP_MODE_PM1 (1 << 0) +#define SLEEP_MODE_PM2 (2 << 0) +#define SLEEP_MODE_PM3 (3 << 0) +#define SLEEP_MODE_MASK (3 << 0) + +/* PCON 0x87 */ +__sfr __at 0x87 PCON; /* Power Mode Control Register */ + +#define PCON_IDLE (1 << 0) + +/* + * TCON + */ +__sfr __at 0x88 TCON; /* CPU Interrupt Flag 1 */ + +sbit __at 0x8F URX1IF; /* USART1 RX interrupt flag. Automatically cleared */ +sbit __at 0x8F I2SRXIF; /* I2S RX interrupt flag. Automatically cleared */ +sbit __at 0x8D ADCIF; /* ADC interrupt flag. Automatically cleared */ +sbit __at 0x8B URX0IF; /* USART0 RX interrupt flag. Automatically cleared */ +sbit __at 0x89 RFTXRXIF; /* RF TX/RX complete interrupt flag. Automatically cleared */ + +#define TCON_URX1IF (1 << 7) +#define TCON_I2SRXIF (1 << 7) +#define TCON_ADCIF (1 << 5) +#define TCON_URX0IF (1 << 3) +#define TCON_RFTXRXIF (1 << 1) + +/* + * S0CON + */ +__sfr __at 0x98 S0CON; /* CPU Interrupt Flag 2 */ + +sbit __at 0x98 ENCIF_0; /* AES interrupt 0. */ +sbit __at 0x99 ENCIF_1; /* AES interrupt 1. */ + +#define S0CON_ENCIF_1 (1 << 1) +#define S0CON_ENCIF_0 (1 << 0) + +/* + * S1CON + */ +__sfr __at 0x9B S1CON; /* CPU Interrupt Flag 3 */ + +#define S1CON_RFIF_1 (1 << 1) +#define S1CON_RFIF_0 (1 << 0) + +/* + * IRCON + */ +__sfr __at 0xC0 IRCON; /* CPU Interrupt Flag 4 */ + +sbit __at 0xC0 DMAIF; /* DMA complete interrupt flag */ +sbit __at 0xC1 T1IF; /* Timer 1 interrupt flag. Automatically cleared */ +sbit __at 0xC2 T2IF; /* Timer 2 interrupt flag. Automatically cleared */ +sbit __at 0xC3 T3IF; /* Timer 3 interrupt flag. Automatically cleared */ +sbit __at 0xC4 T4IF; /* Timer 4 interrupt flag. Automatically cleared */ +sbit __at 0xC5 P0IF; /* Port0 interrupt flag */ +sbit __at 0xC7 STIF; /* Sleep Timer interrupt flag */ + +#define IRCON_DMAIF (1 << 0) /* DMA complete interrupt flag */ +#define IRCON_T1IF (1 << 1) /* Timer 1 interrupt flag. Automatically cleared */ +#define IRCON_T2IF (1 << 2) /* Timer 2 interrupt flag. Automatically cleared */ +#define IRCON_T3IF (1 << 3) /* Timer 3 interrupt flag. Automatically cleared */ +#define IRCON_T4IF (1 << 4) /* Timer 4 interrupt flag. Automatically cleared */ +#define IRCON_P0IF (1 << 5) /* Port0 interrupt flag */ +#define IRCON_STIF (1 << 7) /* Sleep Timer interrupt flag */ + +/* + * IRCON2 + */ +__sfr __at 0xE8 IRCON2; /* CPU Interrupt Flag 5 */ + +sbit __at 0xE8 USBIF; /* USB interrupt flag (shared with Port2) */ +sbit __at 0xE8 P2IF; /* Port2 interrupt flag (shared with USB) */ +sbit __at 0xE9 UTX0IF; /* USART0 TX interrupt flag */ +sbit __at 0xEA UTX1IF; /* USART1 TX interrupt flag (shared with I2S TX) */ +sbit __at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */ +sbit __at 0xEB P1IF; /* Port1 interrupt flag */ +sbit __at 0xEC WDTIF; /* Watchdog timer interrupt flag */ + +#define IRCON2_USBIF (1 << 0) /* USB interrupt flag (shared with Port2) */ +#define IRCON2_P2IF (1 << 0) /* Port2 interrupt flag (shared with USB) */ +#define IRCON2_UTX0IF (1 << 1) /* USART0 TX interrupt flag */ +#define IRCON2_UTX1IF (1 << 2) /* USART1 TX interrupt flag (shared with I2S TX) */ +#define IRCON2_I2STXIF (1 << 2) /* I2S TX interrupt flag (shared with USART1 TX) */ +#define IRCON2_P1IF (1 << 3) /* Port1 interrupt flag */ +#define IRCON2_WDTIF (1 << 4) /* Watchdog timer interrupt flag */ + +/* + * IP1 - Interrupt Priority 1 + */ + +/* + * Interrupt priority groups: + * + * IPG0 RFTXRX RF DMA + * IPG1 ADC T1 P2INT/USB + * IPG2 URX0 T2 UTX0 + * IPG3 URX1/I2SRX T3 UTX1 / I2STX + * IPG4 ENC T4 P1INT + * IPG5 ST P0INT WDT + * + * Priority = (IP1 << 1) | IP0. Higher priority interrupts served first + */ + +__sfr __at 0xB9 IP1; /* Interrupt Priority 1 */ +__sfr __at 0xA9 IP0; /* Interrupt Priority 0 */ + +#define IP1_IPG5 (1 << 5) +#define IP1_IPG4 (1 << 4) +#define IP1_IPG3 (1 << 3) +#define IP1_IPG2 (1 << 2) +#define IP1_IPG1 (1 << 1) +#define IP1_IPG0 (1 << 0) + +#define IP0_IPG5 (1 << 5) +#define IP0_IPG4 (1 << 4) +#define IP0_IPG3 (1 << 3) +#define IP0_IPG2 (1 << 2) +#define IP0_IPG1 (1 << 1) +#define IP0_IPG0 (1 << 0) + +/* + * Timer 1 + */ +#define T1CTL_MODE_SUSPENDED (0 << 0) +#define T1CTL_MODE_FREE (1 << 0) +#define T1CTL_MODE_MODULO (2 << 0) +#define T1CTL_MODE_UP_DOWN (3 << 0) +#define T1CTL_MODE_MASK (3 << 0) +#define T1CTL_DIV_1 (0 << 2) +#define T1CTL_DIV_8 (1 << 2) +#define T1CTL_DIV_32 (2 << 2) +#define T1CTL_DIV_128 (3 << 2) +#define T1CTL_DIV_MASK (3 << 2) +#define T1CTL_OVFIF (1 << 4) +#define T1CTL_CH0IF (1 << 5) +#define T1CTL_CH1IF (1 << 6) +#define T1CTL_CH2IF (1 << 7) + +#define T1CCTL_NO_CAPTURE (0 << 0) +#define T1CCTL_CAPTURE_RISING (1 << 0) +#define T1CCTL_CAPTURE_FALLING (2 << 0) +#define T1CCTL_CAPTURE_BOTH (3 << 0) +#define T1CCTL_CAPTURE_MASK (3 << 0) + +#define T1CCTL_MODE_CAPTURE (0 << 2) +#define T1CCTL_MODE_COMPARE (1 << 2) + +#define T1CTL_CMP_SET (0 << 3) +#define T1CTL_CMP_CLEAR (1 << 3) +#define T1CTL_CMP_TOGGLE (2 << 3) +#define T1CTL_CMP_SET_CLEAR (3 << 3) +#define T1CTL_CMP_CLEAR_SET (4 << 3) + +#define T1CTL_IM_DISABLED (0 << 6) +#define T1CTL_IM_ENABLED (1 << 6) + +#define T1CTL_CPSEL_NORMAL (0 << 7) +#define T1CTL_CPSEL_RF (1 << 7) + +/* + * Timer 3 and Timer 4 + */ + +/* Timer count */ +__sfr __at 0xCA T3CNT; +__sfr __at 0xEA T4CNT; + +/* Timer control */ + +__sfr __at 0xCB T3CTL; +__sfr __at 0xEB T4CTL; + +#define TxCTL_DIV_1 (0 << 5) +#define TxCTL_DIV_2 (1 << 5) +#define TxCTL_DIV_4 (2 << 5) +#define TxCTL_DIV_8 (3 << 5) +#define TxCTL_DIV_16 (4 << 5) +#define TxCTL_DIV_32 (5 << 5) +#define TxCTL_DIV_64 (6 << 5) +#define TxCTL_DIV_128 (7 << 5) +#define TxCTL_START (1 << 4) +#define TxCTL_OVFIM (1 << 3) +#define TxCTL_CLR (1 << 2) +#define TxCTL_MODE_FREE (0 << 0) +#define TxCTL_MODE_DOWN (1 << 0) +#define TxCTL_MODE_MODULO (2 << 0) +#define TxCTL_MODE_UP_DOWN (3 << 0) + +/* Timer 4 channel 0 compare control */ + +__sfr __at 0xCC T3CCTL0; +__sfr __at 0xCE T3CCTL1; +__sfr __at 0xEC T4CCTL0; +__sfr __at 0xEE T4CCTL1; + +#define TxCCTLy_IM (1 << 6) +#define TxCCTLy_CMP_SET (0 << 3) +#define TxCCTLy_CMP_CLEAR (1 << 3) +#define TxCCTLy_CMP_TOGGLE (2 << 3) +#define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3) +#define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3) +#define TxCCTLy_CMP_SET_CLEAR_FF (5 << 3) +#define TxCCTLy_CMP_CLEAR_SET_00 (6 << 3) +#define TxCCTLy_CMP_MODE_ENABLE (1 << 2) + +/* Timer compare value */ +__sfr __at 0xCD T3CC0; +__sfr __at 0xCF T3CC1; +__sfr __at 0xED T4CC0; +__sfr __at 0xEF T4CC1; + +/* + * Peripheral control + */ + +__sfr __at 0xf1 PERCFG; +#define PERCFG_T1CFG_ALT_1 (0 << 6) +#define PERCFG_T1CFG_ALT_2 (1 << 6) +#define PERCFG_T1CFG_ALT_MASK (1 << 6) + +#define PERCFG_T3CFG_ALT_1 (0 << 5) +#define PERCFG_T3CFG_ALT_2 (1 << 5) +#define PERCFG_T3CFG_ALT_MASK (1 << 5) + +#define PERCFG_T4CFG_ALT_1 (0 << 4) +#define PERCFG_T4CFG_ALT_2 (1 << 4) +#define PERCFG_T4CFG_ALT_MASK (1 << 4) + +#define PERCFG_U1CFG_ALT_1 (0 << 1) +#define PERCFG_U1CFG_ALT_2 (1 << 1) +#define PERCFG_U1CFG_ALT_MASK (1 << 1) + +#define PERCFG_U0CFG_ALT_1 (0 << 0) +#define PERCFG_U0CFG_ALT_2 (1 << 0) +#define PERCFG_U0CFG_ALT_MASK (1 << 0) + +/* directly addressed USB registers */ +__xdata __at (0xde00) volatile uint8_t USBADDR; +__xdata __at (0xde01) volatile uint8_t USBPOW; +__xdata __at (0xde02) volatile uint8_t USBIIF; + +__xdata __at (0xde04) volatile uint8_t USBOIF; + +__xdata __at (0xde06) volatile uint8_t USBCIF; + +# define USBCIF_SOFIF (1 << 3) +# define USBCIF_RSTIF (1 << 2) +# define USBCIF_RESUMEIF (1 << 1) +# define USBCIF_SUSPENDIF (1 << 0) + +__xdata __at (0xde07) volatile uint8_t USBIIE; + +__xdata __at (0xde09) volatile uint8_t USBOIE; + +__xdata __at (0xde0b) volatile uint8_t USBCIE; + +# define USBCIE_SOFIE (1 << 3) +# define USBCIE_RSTIE (1 << 2) +# define USBCIE_RESUMEIE (1 << 1) +# define USBCIE_SUSPENDIE (1 << 0) + +__xdata __at (0xde0c) volatile uint8_t USBFRML; +__xdata __at (0xde0d) volatile uint8_t USBFRMH; +__xdata __at (0xde0e) volatile uint8_t USBINDEX; + +/* indexed USB registers, must set USBINDEX to 0-5 */ +__xdata __at (0xde10) volatile uint8_t USBMAXI; +__xdata __at (0xde11) volatile uint8_t USBCS0; + +# define USBCS0_CLR_SETUP_END (1 << 7) +# define USBCS0_CLR_OUTPKT_RDY (1 << 6) +# define USBCS0_SEND_STALL (1 << 5) +# define USBCS0_SETUP_END (1 << 4) +# define USBCS0_DATA_END (1 << 3) +# define USBCS0_SENT_STALL (1 << 2) +# define USBCS0_INPKT_RDY (1 << 1) +# define USBCS0_OUTPKT_RDY (1 << 0) + +__xdata __at (0xde11) volatile uint8_t USBCSIL; + +# define USBCSIL_CLR_DATA_TOG (1 << 6) +# define USBCSIL_SENT_STALL (1 << 5) +# define USBCSIL_SEND_STALL (1 << 4) +# define USBCSIL_FLUSH_PACKET (1 << 3) +# define USBCSIL_UNDERRUN (1 << 2) +# define USBCSIL_PKT_PRESENT (1 << 1) +# define USBCSIL_INPKT_RDY (1 << 0) + +__xdata __at (0xde12) volatile uint8_t USBCSIH; + +# define USBCSIH_AUTOSET (1 << 7) +# define USBCSIH_ISO (1 << 6) +# define USBCSIH_FORCE_DATA_TOG (1 << 3) +# define USBCSIH_IN_DBL_BUF (1 << 0) + +__xdata __at (0xde13) volatile uint8_t USBMAXO; +__xdata __at (0xde14) volatile uint8_t USBCSOL; + +# define USBCSOL_CLR_DATA_TOG (1 << 7) +# define USBCSOL_SENT_STALL (1 << 6) +# define USBCSOL_SEND_STALL (1 << 5) +# define USBCSOL_FLUSH_PACKET (1 << 4) +# define USBCSOL_DATA_ERROR (1 << 3) +# define USBCSOL_OVERRUN (1 << 2) +# define USBCSOL_FIFO_FULL (1 << 1) +# define USBCSOL_OUTPKT_RDY (1 << 0) + +__xdata __at (0xde15) volatile uint8_t USBCSOH; + +# define USBCSOH_AUTOCLEAR (1 << 7) +# define USBCSOH_ISO (1 << 6) +# define USBCSOH_OUT_DBL_BUF (1 << 0) + +__xdata __at (0xde16) volatile uint8_t USBCNT0; +__xdata __at (0xde16) volatile uint8_t USBCNTL; +__xdata __at (0xde17) volatile uint8_t USBCNTH; + +__xdata __at (0xde20) volatile uint8_t USBFIFO[12]; + +/* ADC Data register, low and high */ +__sfr at 0xBA ADCL; +__sfr at 0xBB ADCH; +__xdata __at (0xDFBA) volatile uint16_t ADCXDATA; + +/* ADC Control Register 1 */ +__sfr at 0xB4 ADCCON1; + +# define ADCCON1_EOC (1 << 7) /* conversion complete */ +# define ADCCON1_ST (1 << 6) /* start conversion */ + +# define ADCCON1_STSEL_MASK (3 << 4) /* start select */ +# define ADCCON1_STSEL_EXTERNAL (0 << 4) /* P2_0 pin triggers */ +# define ADCCON1_STSEL_FULLSPEED (1 << 4) /* full speed, no waiting */ +# define ADCCON1_STSEL_TIMER1 (2 << 4) /* timer 1 channel 0 */ +# define ADCCON1_STSEL_START (3 << 4) /* set start bit */ + +# define ADCCON1_RCTRL_MASK (3 << 2) /* random number control */ +# define ADCCON1_RCTRL_COMPLETE (0 << 2) /* operation completed */ +# define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2) /* Clock the LFSR once */ + +/* ADC Control Register 2 */ +__sfr at 0xB5 ADCCON2; + +# define ADCCON2_SREF_MASK (3 << 6) /* reference voltage */ +# define ADCCON2_SREF_1_25V (0 << 6) /* internal 1.25V */ +# define ADCCON2_SREF_EXTERNAL (1 << 6) /* external on AIN7 cc1110 */ +# define ADCCON2_SREF_VDD (2 << 6) /* VDD on the AVDD pin */ +# define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6) /* external on AIN6-7 cc1110 */ + +# define ADCCON2_SDIV_MASK (3 << 4) /* decimation rate */ +# define ADCCON2_SDIV_64 (0 << 4) /* 7 bits */ +# define ADCCON2_SDIV_128 (1 << 4) /* 9 bits */ +# define ADCCON2_SDIV_256 (2 << 4) /* 10 bits */ +# define ADCCON2_SDIV_512 (3 << 4) /* 12 bits */ + +# define ADCCON2_SCH_MASK (0xf << 0) /* Sequence channel select */ +# define ADCCON2_SCH_SHIFT 0 +# define ADCCON2_SCH_AIN0 (0 << 0) +# define ADCCON2_SCH_AIN1 (1 << 0) +# define ADCCON2_SCH_AIN2 (2 << 0) +# define ADCCON2_SCH_AIN3 (3 << 0) +# define ADCCON2_SCH_AIN4 (4 << 0) +# define ADCCON2_SCH_AIN5 (5 << 0) +# define ADCCON2_SCH_AIN6 (6 << 0) +# define ADCCON2_SCH_AIN7 (7 << 0) +# define ADCCON2_SCH_AIN0_AIN1 (8 << 0) +# define ADCCON2_SCH_AIN2_AIN3 (9 << 0) +# define ADCCON2_SCH_AIN4_AIN5 (0xa << 0) +# define ADCCON2_SCH_AIN6_AIN7 (0xb << 0) +# define ADCCON2_SCH_GND (0xc << 0) +# define ADCCON2_SCH_VREF (0xd << 0) +# define ADCCON2_SCH_TEMP (0xe << 0) +# define ADCCON2_SCH_VDD_3 (0xf << 0) + + +/* ADC Control Register 3 */ +__sfr at 0xB6 ADCCON3; + +# define ADCCON3_EREF_MASK (3 << 6) /* extra conversion reference */ +# define ADCCON3_EREF_1_25 (0 << 6) /* internal 1.25V */ +# define ADCCON3_EREF_EXTERNAL (1 << 6) /* external AIN7 cc1110 */ +# define ADCCON3_EREF_VDD (2 << 6) /* VDD on the AVDD pin */ +# define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6) /* external AIN6-7 cc1110 */ +# define ADCCON3_EDIV_MASK (3 << 4) /* extral decimation */ +# define ADCCON3_EDIV_64 (0 << 4) /* 7 bits */ +# define ADCCON3_EDIV_128 (1 << 4) /* 9 bits */ +# define ADCCON3_EDIV_256 (2 << 4) /* 10 bits */ +# define ADCCON3_EDIV_512 (3 << 4) /* 12 bits */ +# define ADCCON3_ECH_MASK (0xf << 0) /* Sequence channel select */ +# define ADCCON3_ECH_SHIFT 0 +# define ADCCON3_ECH_AIN0 (0 << 0) +# define ADCCON3_ECH_AIN1 (1 << 0) +# define ADCCON3_ECH_AIN2 (2 << 0) +# define ADCCON3_ECH_AIN3 (3 << 0) +# define ADCCON3_ECH_AIN4 (4 << 0) +# define ADCCON3_ECH_AIN5 (5 << 0) +# define ADCCON3_ECH_AIN6 (6 << 0) +# define ADCCON3_ECH_AIN7 (7 << 0) +# define ADCCON3_ECH_AIN0_AIN1 (8 << 0) +# define ADCCON3_ECH_AIN2_AIN3 (9 << 0) +# define ADCCON3_ECH_AIN4_AIN5 (0xa << 0) +# define ADCCON3_ECH_AIN6_AIN7 (0xb << 0) +# define ADCCON3_ECH_GND (0xc << 0) +# define ADCCON3_ECH_VREF (0xd << 0) +# define ADCCON3_ECH_TEMP (0xe << 0) +# define ADCCON3_ECH_VDD_3 (0xf << 0) + +/* + * ADC configuration register, this selects which + * GPIO pins are to be used as ADC inputs + */ +__sfr at 0xF2 ADCCFG; + +/* + * Watchdog timer + */ + +__sfr at 0xc9 WDCTL; + +#define WDCTL_CLEAR_FIRST (0xa << 4) +#define WDCTL_CLEAR_SECOND (0x5 << 4) +#define WDCTL_EN (1 << 3) +#define WDCTL_MODE_WATCHDOG (0 << 2) +#define WDCTL_MODE_TIMER (1 << 2) +#define WDCTL_MODE_MASK (1 << 2) +#define WDCTL_INT_32768 (0 << 0) +#define WDCTL_INT_8192 (1 << 0) +#define WDCTL_INT_512 (2 << 0) +#define WDCTL_INT_64 (3 << 0) + +/* + * Pin selectors, these set which pins are + * using their peripheral function + */ +__sfr at 0xF3 P0SEL; +__sfr at 0xF4 P1SEL; +__sfr at 0xF5 P2SEL; + +#define P2SEL_PRI3P1_USART0 (0 << 6) +#define P2SEL_PRI3P1_USART1 (1 << 6) +#define P2SEL_PRI3P1_MASK (1 << 6) +#define P2SEL_PRI2P1_USART1 (0 << 5) +#define P2SEL_PRI2P1_TIMER3 (1 << 5) +#define P2SEL_PRI2P1_MASK (1 << 5) +#define P2SEL_PRI1P1_TIMER1 (0 << 4) +#define P2SEL_PRI1P1_TIMER4 (1 << 4) +#define P2SEL_PRI1P1_MASK (1 << 4) +#define P2SEL_PRI0P1_USART0 (0 << 3) +#define P2SEL_PRI0P1_TIMER1 (1 << 3) +#define P2SEL_PRI0P1_MASK (1 << 3) +#define P2SEL_SELP2_4_GPIO (0 << 2) +#define P2SEL_SELP2_4_PERIPHERAL (1 << 2) +#define P2SEL_SELP2_4_MASK (1 << 2) +#define P2SEL_SELP2_3_GPIO (0 << 1) +#define P2SEL_SELP2_3_PERIPHERAL (1 << 1) +#define P2SEL_SELP2_3_MASK (1 << 1) +#define P2SEL_SELP2_0_GPIO (0 << 0) +#define P2SEL_SELP2_0_PERIPHERAL (1 << 0) +#define P2SEL_SELP2_0_MASK (1 << 0) + +/* + * For pins used as GPIOs, these set which are used as outputs + */ +__sfr at 0xFD P0DIR; +__sfr at 0xFE P1DIR; +__sfr at 0xFF P2DIR; + +#define P2DIR_PRIP0_USART0_USART1 (0 << 6) +#define P2DIR_PRIP0_USART1_USART0 (1 << 6) +#define P2DIR_PRIP0_TIMER1_01_USART1 (2 << 6) +#define P2DIR_PRIP0_TIMER1_2_USART0 (3 << 6) +#define P2DIR_PRIP0_MASK (3 << 6) + +__sfr at 0x8F P0INP; + +/* Select between tri-state and pull up/down + * for pins P0_0 - P0_7. + */ +#define P0INP_MDP0_7_PULL (0 << 7) +#define P0INP_MDP0_7_TRISTATE (1 << 7) +#define P0INP_MDP0_6_PULL (0 << 6) +#define P0INP_MDP0_6_TRISTATE (1 << 6) +#define P0INP_MDP0_5_PULL (0 << 5) +#define P0INP_MDP0_5_TRISTATE (1 << 5) +#define P0INP_MDP0_4_PULL (0 << 4) +#define P0INP_MDP0_4_TRISTATE (1 << 4) +#define P0INP_MDP0_3_PULL (0 << 3) +#define P0INP_MDP0_3_TRISTATE (1 << 3) +#define P0INP_MDP0_2_PULL (0 << 2) +#define P0INP_MDP0_2_TRISTATE (1 << 2) +#define P0INP_MDP0_1_PULL (0 << 1) +#define P0INP_MDP0_1_TRISTATE (1 << 1) +#define P0INP_MDP0_0_PULL (0 << 0) +#define P0INP_MDP0_0_TRISTATE (1 << 0) + +__sfr at 0xF6 P1INP; + +/* Select between tri-state and pull up/down + * for pins P1_2 - P1_7. Pins P1_0 and P1_1 are + * always tri-stated + */ +#define P1INP_MDP1_7_PULL (0 << 7) +#define P1INP_MDP1_7_TRISTATE (1 << 7) +#define P1INP_MDP1_6_PULL (0 << 6) +#define P1INP_MDP1_6_TRISTATE (1 << 6) +#define P1INP_MDP1_5_PULL (0 << 5) +#define P1INP_MDP1_5_TRISTATE (1 << 5) +#define P1INP_MDP1_4_PULL (0 << 4) +#define P1INP_MDP1_4_TRISTATE (1 << 4) +#define P1INP_MDP1_3_PULL (0 << 3) +#define P1INP_MDP1_3_TRISTATE (1 << 3) +#define P1INP_MDP1_2_PULL (0 << 2) +#define P1INP_MDP1_2_TRISTATE (1 << 2) + +__sfr at 0xF7 P2INP; +/* P2INP has three extra bits which are used to choose + * between pull-up and pull-down when they are not tri-stated + */ +#define P2INP_PDUP2_PULL_UP (0 << 7) +#define P2INP_PDUP2_PULL_DOWN (1 << 7) +#define P2INP_PDUP1_PULL_UP (0 << 6) +#define P2INP_PDUP1_PULL_DOWN (1 << 6) +#define P2INP_PDUP0_PULL_UP (0 << 5) +#define P2INP_PDUP0_PULL_DOWN (1 << 5) + +/* For the P2 pins, choose between tri-state and pull up/down + * mode + */ +#define P2INP_MDP2_4_PULL (0 << 4) +#define P2INP_MDP2_4_TRISTATE (1 << 4) +#define P2INP_MDP2_3_PULL (0 << 3) +#define P2INP_MDP2_3_TRISTATE (1 << 3) +#define P2INP_MDP2_2_PULL (0 << 2) +#define P2INP_MDP2_2_TRISTATE (1 << 2) +#define P2INP_MDP2_1_PULL (0 << 1) +#define P2INP_MDP2_1_TRISTATE (1 << 1) +#define P2INP_MDP2_0_PULL (0 << 0) +#define P2INP_MDP2_0_TRISTATE (1 << 0) + +/* GPIO interrupt status flags */ +__sfr at 0x89 P0IFG; +__sfr at 0x8A P1IFG; +__sfr at 0x8B P2IFG; + +#define P0IFG_USB_RESUME (1 << 7) + +__sfr at 0x8C PICTL; +#define PICTL_P2IEN (1 << 5) +#define PICTL_P0IENH (1 << 4) +#define PICTL_P0IENL (1 << 3) +#define PICTL_P2ICON (1 << 2) +#define PICTL_P1ICON (1 << 1) +#define PICTL_P0ICON (1 << 0) + +/* GPIO pins */ +__sfr at 0x80 P0; + +sbit at 0x80 P0_0; +sbit at 0x81 P0_1; +sbit at 0x82 P0_2; +sbit at 0x83 P0_3; +sbit at 0x84 P0_4; +sbit at 0x85 P0_5; +sbit at 0x86 P0_6; +sbit at 0x87 P0_7; + +__sfr at 0x90 P1; + +sbit at 0x90 P1_0; +sbit at 0x91 P1_1; +sbit at 0x92 P1_2; +sbit at 0x93 P1_3; +sbit at 0x94 P1_4; +sbit at 0x95 P1_5; +sbit at 0x96 P1_6; +sbit at 0x97 P1_7; + +__sfr at 0xa0 P2; + +sbit at 0xa0 P2_0; +sbit at 0xa1 P2_1; +sbit at 0xa2 P2_2; +sbit at 0xa3 P2_3; +sbit at 0xa4 P2_4; + +/* DMA controller */ +struct cc_dma_channel { + uint8_t src_high; + uint8_t src_low; + uint8_t dst_high; + uint8_t dst_low; + uint8_t len_high; + uint8_t len_low; + uint8_t cfg0; + uint8_t cfg1; +}; + +# define DMA_LEN_HIGH_VLEN_MASK (7 << 5) +# define DMA_LEN_HIGH_VLEN_LEN (0 << 5) +# define DMA_LEN_HIGH_VLEN_PLUS_1 (1 << 5) +# define DMA_LEN_HIGH_VLEN (2 << 5) +# define DMA_LEN_HIGH_VLEN_PLUS_2 (3 << 5) +# define DMA_LEN_HIGH_VLEN_PLUS_3 (4 << 5) +# define DMA_LEN_HIGH_MASK (0x1f) + +# define DMA_CFG0_WORDSIZE_8 (0 << 7) +# define DMA_CFG0_WORDSIZE_16 (1 << 7) +# define DMA_CFG0_TMODE_MASK (3 << 5) +# define DMA_CFG0_TMODE_SINGLE (0 << 5) +# define DMA_CFG0_TMODE_BLOCK (1 << 5) +# define DMA_CFG0_TMODE_REPEATED_SINGLE (2 << 5) +# define DMA_CFG0_TMODE_REPEATED_BLOCK (3 << 5) + +/* + * DMA triggers + */ +# define DMA_CFG0_TRIGGER_NONE 0 +# define DMA_CFG0_TRIGGER_PREV 1 +# define DMA_CFG0_TRIGGER_T1_CH0 2 +# define DMA_CFG0_TRIGGER_T1_CH1 3 +# define DMA_CFG0_TRIGGER_T1_CH2 4 +# define DMA_CFG0_TRIGGER_T2_OVFL 6 +# define DMA_CFG0_TRIGGER_T3_CH0 7 +# define DMA_CFG0_TRIGGER_T3_CH1 8 +# define DMA_CFG0_TRIGGER_T4_CH0 9 +# define DMA_CFG0_TRIGGER_T4_CH1 10 +# define DMA_CFG0_TRIGGER_IOC_0 12 +# define DMA_CFG0_TRIGGER_IOC_1 13 +# define DMA_CFG0_TRIGGER_URX0 14 +# define DMA_CFG0_TRIGGER_UTX0 15 +# define DMA_CFG0_TRIGGER_URX1 16 +# define DMA_CFG0_TRIGGER_UTX1 17 +# define DMA_CFG0_TRIGGER_FLASH 18 +# define DMA_CFG0_TRIGGER_RADIO 19 +# define DMA_CFG0_TRIGGER_ADC_CHALL 20 +# define DMA_CFG0_TRIGGER_ADC_CH0 21 +# define DMA_CFG0_TRIGGER_ADC_CH1 22 +# define DMA_CFG0_TRIGGER_ADC_CH2 23 +# define DMA_CFG0_TRIGGER_ADC_CH3 24 +# define DMA_CFG0_TRIGGER_ADC_CH4 25 +# define DMA_CFG0_TRIGGER_ADC_CH5 26 +# define DMA_CFG0_TRIGGER_ADC_CH6 27 +# define DMA_CFG0_TRIGGER_I2SRX 27 +# define DMA_CFG0_TRIGGER_ADC_CH7 28 +# define DMA_CFG0_TRIGGER_I2STX 28 +# define DMA_CFG0_TRIGGER_ENC_DW 29 +# define DMA_CFG0_TRIGGER_DNC_UP 30 + +# define DMA_CFG1_SRCINC_MASK (3 << 6) +# define DMA_CFG1_SRCINC_0 (0 << 6) +# define DMA_CFG1_SRCINC_1 (1 << 6) +# define DMA_CFG1_SRCINC_2 (2 << 6) +# define DMA_CFG1_SRCINC_MINUS_1 (3 << 6) + +# define DMA_CFG1_DESTINC_MASK (3 << 4) +# define DMA_CFG1_DESTINC_0 (0 << 4) +# define DMA_CFG1_DESTINC_1 (1 << 4) +# define DMA_CFG1_DESTINC_2 (2 << 4) +# define DMA_CFG1_DESTINC_MINUS_1 (3 << 4) + +# define DMA_CFG1_IRQMASK (1 << 3) +# define DMA_CFG1_M8 (1 << 2) + +# define DMA_CFG1_PRIORITY_MASK (3 << 0) +# define DMA_CFG1_PRIORITY_LOW (0 << 0) +# define DMA_CFG1_PRIORITY_NORMAL (1 << 0) +# define DMA_CFG1_PRIORITY_HIGH (2 << 0) + +/* + * DMAARM - DMA Channel Arm + */ + +__sfr at 0xD6 DMAARM; + +# define DMAARM_ABORT (1 << 7) +# define DMAARM_DMAARM4 (1 << 4) +# define DMAARM_DMAARM3 (1 << 3) +# define DMAARM_DMAARM2 (1 << 2) +# define DMAARM_DMAARM1 (1 << 1) +# define DMAARM_DMAARM0 (1 << 0) + +/* + * DMAREQ - DMA Channel Start Request and Status + */ + +__sfr at 0xD7 DMAREQ; + +# define DMAREQ_DMAREQ4 (1 << 4) +# define DMAREQ_DMAREQ3 (1 << 3) +# define DMAREQ_DMAREQ2 (1 << 2) +# define DMAREQ_DMAREQ1 (1 << 1) +# define DMAREQ_DMAREQ0 (1 << 0) + +/* + * DMA configuration 0 address + */ + +__sfr at 0xD5 DMA0CFGH; +__sfr at 0xD4 DMA0CFGL; + +/* + * DMA configuration 1-4 address + */ + +__sfr at 0xD3 DMA1CFGH; +__sfr at 0xD2 DMA1CFGL; + +/* + * DMAIRQ - DMA Interrupt Flag + */ + +__sfr at 0xD1 DMAIRQ; + +# define DMAIRQ_DMAIF4 (1 << 4) +# define DMAIRQ_DMAIF3 (1 << 3) +# define DMAIRQ_DMAIF2 (1 << 2) +# define DMAIRQ_DMAIF1 (1 << 1) +# define DMAIRQ_DMAIF0 (1 << 0) + +/* + * UART registers + */ + +/* USART config/status registers */ +__sfr at 0x86 U0CSR; +__sfr at 0xF8 U1CSR; + +# define UxCSR_MODE_UART (1 << 7) +# define UxCSR_MODE_SPI (0 << 7) +# define UxCSR_RE (1 << 6) +# define UxCSR_SLAVE (1 << 5) +# define UxCSR_MASTER (0 << 5) +# define UxCSR_FE (1 << 4) +# define UxCSR_ERR (1 << 3) +# define UxCSR_RX_BYTE (1 << 2) +# define UxCSR_TX_BYTE (1 << 1) +# define UxCSR_ACTIVE (1 << 0) + +/* UART configuration registers */ +__sfr at 0xc4 U0UCR; +__sfr at 0xfb U1UCR; + +# define UxUCR_FLUSH (1 << 7) +# define UxUCR_FLOW_DISABLE (0 << 6) +# define UxUCR_FLOW_ENABLE (1 << 6) +# define UxUCR_D9_EVEN_PARITY (0 << 5) +# define UxUCR_D9_ODD_PARITY (1 << 5) +# define UxUCR_BIT9_8_BITS (0 << 4) +# define UxUCR_BIT9_9_BITS (1 << 4) +# define UxUCR_PARITY_DISABLE (0 << 3) +# define UxUCR_PARITY_ENABLE (1 << 3) +# define UxUCR_SPB_1_STOP_BIT (0 << 2) +# define UxUCR_SPB_2_STOP_BITS (1 << 2) +# define UxUCR_STOP_LOW (0 << 1) +# define UxUCR_STOP_HIGH (1 << 1) +# define UxUCR_START_LOW (0 << 0) +# define UxUCR_START_HIGH (1 << 0) + +/* USART General configuration registers (mostly SPI) */ +__sfr at 0xc5 U0GCR; +__sfr at 0xfc U1GCR; + +# define UxGCR_CPOL_NEGATIVE (0 << 7) +# define UxGCR_CPOL_POSITIVE (1 << 7) +# define UxGCR_CPHA_FIRST_EDGE (0 << 6) +# define UxGCR_CPHA_SECOND_EDGE (1 << 6) +# define UxGCR_ORDER_LSB (0 << 5) +# define UxGCR_ORDER_MSB (1 << 5) +# define UxGCR_BAUD_E_MASK (0x1f) +# define UxGCR_BAUD_E_SHIFT 0 + +/* USART data registers */ +__sfr at 0xc1 U0DBUF; +__xdata __at (0xDFC1) volatile uint8_t U0DBUFXADDR; +__sfr at 0xf9 U1DBUF; +__xdata __at (0xDFF9) volatile uint8_t U1DBUFXADDR; + +/* USART baud rate registers, M value */ +__sfr at 0xc2 U0BAUD; +__sfr at 0xfa U1BAUD; + +/* Flash controller */ + +__sfr at 0xAE FCTL; +#define FCTL_BUSY (1 << 7) +#define FCTL_SWBSY (1 << 6) +#define FCTL_CONTRD_ENABLE (1 << 4) +#define FCTL_WRITE (1 << 1) +#define FCTL_ERASE (1 << 0) + +/* Flash write data. Write two bytes here */ +__sfr at 0xAF FWDATA; +__xdata __at (0xDFAF) volatile uint8_t FWDATAXADDR; + +/* Flash write/erase address */ +__sfr at 0xAD FADDRH; +__sfr at 0xAC FADDRL; + +/* Flash timing */ +__sfr at 0xAB FWT; + +/* Radio */ + +__sfr at 0xD9 RFD; +__xdata at (0xDFD9) volatile uint8_t RFDXADDR; + +__sfr at 0xE9 RFIF; +#define RFIF_IM_TXUNF (1 << 7) +#define RFIF_IM_RXOVF (1 << 6) +#define RFIF_IM_TIMEOUT (1 << 5) +#define RFIF_IM_DONE (1 << 4) +#define RFIF_IM_CS (1 << 3) +#define RFIF_IM_PQT (1 << 2) +#define RFIF_IM_CCA (1 << 1) +#define RFIF_IM_SFD (1 << 0) + +__sfr at 0x91 RFIM; +#define RFIM_IM_TXUNF (1 << 7) +#define RFIM_IM_RXOVF (1 << 6) +#define RFIM_IM_TIMEOUT (1 << 5) +#define RFIM_IM_DONE (1 << 4) +#define RFIM_IM_CS (1 << 3) +#define RFIM_IM_PQT (1 << 2) +#define RFIM_IM_CCA (1 << 1) +#define RFIM_IM_SFD (1 << 0) + +__sfr at 0xE1 RFST; + +#define RFST_SFSTXON 0x00 +#define RFST_SCAL 0x01 +#define RFST_SRX 0x02 +#define RFST_STX 0x03 +#define RFST_SIDLE 0x04 + +__xdata __at (0xdf00) uint8_t RF[0x3c]; + +__xdata __at (0xdf2f) uint8_t RF_IOCFG2; +#define RF_IOCFG2_OFF 0x2f + +__xdata __at (0xdf30) uint8_t RF_IOCFG1; +#define RF_IOCFG1_OFF 0x30 + +__xdata __at (0xdf31) uint8_t RF_IOCFG0; +#define RF_IOCFG0_OFF 0x31 + +__xdata __at (0xdf00) uint8_t RF_SYNC1; +#define RF_SYNC1_OFF 0x00 + +__xdata __at (0xdf01) uint8_t RF_SYNC0; +#define RF_SYNC0_OFF 0x01 + +__xdata __at (0xdf02) uint8_t RF_PKTLEN; +#define RF_PKTLEN_OFF 0x02 + +__xdata __at (0xdf03) uint8_t RF_PKTCTRL1; +#define RF_PKTCTRL1_OFF 0x03 +#define PKTCTRL1_PQT_MASK (0x7 << 5) +#define PKTCTRL1_PQT_SHIFT 5 +#define PKTCTRL1_APPEND_STATUS (1 << 2) +#define PKTCTRL1_ADR_CHK_NONE (0 << 0) +#define PKTCTRL1_ADR_CHK_NO_BROADCAST (1 << 0) +#define PKTCTRL1_ADR_CHK_00_BROADCAST (2 << 0) +#define PKTCTRL1_ADR_CHK_00_FF_BROADCAST (3 << 0) + +/* If APPEND_STATUS is used, two bytes will be added to the packet data */ +#define PKT_APPEND_STATUS_0_RSSI_MASK (0xff) +#define PKT_APPEND_STATUS_0_RSSI_SHIFT 0 +#define PKT_APPEND_STATUS_1_CRC_OK (1 << 7) +#define PKT_APPEND_STATUS_1_LQI_MASK (0x7f) +#define PKT_APPEND_STATUS_1_LQI_SHIFT 0 + +__xdata __at (0xdf04) uint8_t RF_PKTCTRL0; +#define RF_PKTCTRL0_OFF 0x04 +#define RF_PKTCTRL0_WHITE_DATA (1 << 6) +#define RF_PKTCTRL0_PKT_FORMAT_NORMAL (0 << 4) +#define RF_PKTCTRL0_PKT_FORMAT_RANDOM (2 << 4) +#define RF_PKTCTRL0_CRC_EN (1 << 2) +#define RF_PKTCTRL0_LENGTH_CONFIG_FIXED (0 << 0) +#define RF_PKTCTRL0_LENGTH_CONFIG_VARIABLE (1 << 0) + +__xdata __at (0xdf05) uint8_t RF_ADDR; +#define RF_ADDR_OFF 0x05 + +__xdata __at (0xdf06) uint8_t RF_CHANNR; +#define RF_CHANNR_OFF 0x06 + +__xdata __at (0xdf07) uint8_t RF_FSCTRL1; +#define RF_FSCTRL1_OFF 0x07 + +#define RF_FSCTRL1_FREQ_IF_SHIFT (0) + +__xdata __at (0xdf08) uint8_t RF_FSCTRL0; +#define RF_FSCTRL0_OFF 0x08 + +#define RF_FSCTRL0_FREQOFF_SHIFT (0) + +__xdata __at (0xdf09) uint8_t RF_FREQ2; +#define RF_FREQ2_OFF 0x09 + +__xdata __at (0xdf0a) uint8_t RF_FREQ1; +#define RF_FREQ1_OFF 0x0a + +__xdata __at (0xdf0b) uint8_t RF_FREQ0; +#define RF_FREQ0_OFF 0x0b + +__xdata __at (0xdf0c) uint8_t RF_MDMCFG4; +#define RF_MDMCFG4_OFF 0x0c + +#define RF_MDMCFG4_CHANBW_E_SHIFT 6 +#define RF_MDMCFG4_CHANBW_M_SHIFT 4 +#define RF_MDMCFG4_DRATE_E_SHIFT 0 + +__xdata __at (0xdf0d) uint8_t RF_MDMCFG3; +#define RF_MDMCFG3_OFF 0x0d + +#define RF_MDMCFG3_DRATE_M_SHIFT 0 + +__xdata __at (0xdf0e) uint8_t RF_MDMCFG2; +#define RF_MDMCFG2_OFF 0x0e + +#define RF_MDMCFG2_DEM_DCFILT_OFF (1 << 7) +#define RF_MDMCFG2_DEM_DCFILT_ON (0 << 7) + +#define RF_MDMCFG2_MOD_FORMAT_MASK (7 << 4) +#define RF_MDMCFG2_MOD_FORMAT_2_FSK (0 << 4) +#define RF_MDMCFG2_MOD_FORMAT_GFSK (1 << 4) +#define RF_MDMCFG2_MOD_FORMAT_ASK_OOK (3 << 4) +#define RF_MDMCFG2_MOD_FORMAT_MSK (7 << 4) + +#define RF_MDMCFG2_MANCHESTER_EN (1 << 3) + +#define RF_MDMCFG2_SYNC_MODE_MASK (0x7 << 0) +#define RF_MDMCFG2_SYNC_MODE_NONE (0x0 << 0) +#define RF_MDMCFG2_SYNC_MODE_15_16 (0x1 << 0) +#define RF_MDMCFG2_SYNC_MODE_16_16 (0x2 << 0) +#define RF_MDMCFG2_SYNC_MODE_30_32 (0x3 << 0) +#define RF_MDMCFG2_SYNC_MODE_NONE_THRES (0x4 << 0) +#define RF_MDMCFG2_SYNC_MODE_15_16_THRES (0x5 << 0) +#define RF_MDMCFG2_SYNC_MODE_16_16_THRES (0x6 << 0) +#define RF_MDMCFG2_SYNC_MODE_30_32_THRES (0x7 << 0) + +__xdata __at (0xdf0f) uint8_t RF_MDMCFG1; +#define RF_MDMCFG1_OFF 0x0f + +#define RF_MDMCFG1_FEC_EN (1 << 7) +#define RF_MDMCFG1_FEC_DIS (0 << 7) + +#define RF_MDMCFG1_NUM_PREAMBLE_MASK (7 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_2 (0 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_3 (1 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_4 (2 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_6 (3 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_8 (4 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_12 (5 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_16 (6 << 4) +#define RF_MDMCFG1_NUM_PREAMBLE_24 (7 << 4) + +#define RF_MDMCFG1_CHANSPC_E_MASK (3 << 0) +#define RF_MDMCFG1_CHANSPC_E_SHIFT (0) + +__xdata __at (0xdf10) uint8_t RF_MDMCFG0; +#define RF_MDMCFG0_OFF 0x10 + +#define RF_MDMCFG0_CHANSPC_M_SHIFT (0) + +__xdata __at (0xdf11) uint8_t RF_DEVIATN; +#define RF_DEVIATN_OFF 0x11 + +#define RF_DEVIATN_DEVIATION_E_SHIFT 4 +#define RF_DEVIATN_DEVIATION_M_SHIFT 0 + +__xdata __at (0xdf12) uint8_t RF_MCSM2; +#define RF_MCSM2_OFF 0x12 +#define RF_MCSM2_RX_TIME_RSSI (1 << 4) +#define RF_MCSM2_RX_TIME_QUAL (1 << 3) +#define RF_MCSM2_RX_TIME_MASK (0x7) +#define RF_MCSM2_RX_TIME_SHIFT 0 +#define RF_MCSM2_RX_TIME_END_OF_PACKET (7) + +__xdata __at (0xdf13) uint8_t RF_MCSM1; +#define RF_MCSM1_OFF 0x13 +#define RF_MCSM1_CCA_MODE_ALWAYS (0 << 4) +#define RF_MCSM1_CCA_MODE_RSSI_BELOW (1 << 4) +#define RF_MCSM1_CCA_MODE_UNLESS_RECEIVING (2 << 4) +#define RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING (3 << 4) +#define RF_MCSM1_RXOFF_MODE_IDLE (0 << 2) +#define RF_MCSM1_RXOFF_MODE_FSTXON (1 << 2) +#define RF_MCSM1_RXOFF_MODE_TX (2 << 2) +#define RF_MCSM1_RXOFF_MODE_RX (3 << 2) +#define RF_MCSM1_TXOFF_MODE_IDLE (0 << 0) +#define RF_MCSM1_TXOFF_MODE_FSTXON (1 << 0) +#define RF_MCSM1_TXOFF_MODE_TX (2 << 0) +#define RF_MCSM1_TXOFF_MODE_RX (3 << 0) + +__xdata __at (0xdf14) uint8_t RF_MCSM0; +#define RF_MCSM0_OFF 0x14 +#define RF_MCSM0_FS_AUTOCAL_NEVER (0 << 4) +#define RF_MCSM0_FS_AUTOCAL_FROM_IDLE (1 << 4) +#define RF_MCSM0_FS_AUTOCAL_TO_IDLE (2 << 4) +#define RF_MCSM0_FS_AUTOCAL_TO_IDLE_EVERY_4 (3 << 4) +#define RF_MCSM0_MAGIC_3 (1 << 3) +#define RF_MCSM0_MAGIC_2 (1 << 2) +#define RF_MCSM0_CLOSE_IN_RX_0DB (0 << 0) +#define RF_MCSM0_CLOSE_IN_RX_6DB (1 << 0) +#define RF_MCSM0_CLOSE_IN_RX_12DB (2 << 0) +#define RF_MCSM0_CLOSE_IN_RX_18DB (3 << 0) + +__xdata __at (0xdf15) uint8_t RF_FOCCFG; +#define RF_FOCCFG_OFF 0x15 +#define RF_FOCCFG_FOC_BS_CS_GATE (1 << 5) +#define RF_FOCCFG_FOC_PRE_K_1K (0 << 3) +#define RF_FOCCFG_FOC_PRE_K_2K (1 << 3) +#define RF_FOCCFG_FOC_PRE_K_3K (2 << 3) +#define RF_FOCCFG_FOC_PRE_K_4K (3 << 3) +#define RF_FOCCFG_FOC_POST_K_PRE_K (0 << 2) +#define RF_FOCCFG_FOC_POST_K_PRE_K_OVER_2 (1 << 2) +#define RF_FOCCFG_FOC_LIMIT_0 (0 << 0) +#define RF_FOCCFG_FOC_LIMIT_BW_OVER_8 (1 << 0) +#define RF_FOCCFG_FOC_LIMIT_BW_OVER_4 (2 << 0) +#define RF_FOCCFG_FOC_LIMIT_BW_OVER_2 (3 << 0) + +__xdata __at (0xdf16) uint8_t RF_BSCFG; +#define RF_BSCFG_OFF 0x16 +#define RF_BSCFG_BS_PRE_K_1K (0 << 6) +#define RF_BSCFG_BS_PRE_K_2K (1 << 6) +#define RF_BSCFG_BS_PRE_K_3K (2 << 6) +#define RF_BSCFG_BS_PRE_K_4K (3 << 6) +#define RF_BSCFG_BS_PRE_KP_1KP (0 << 4) +#define RF_BSCFG_BS_PRE_KP_2KP (1 << 4) +#define RF_BSCFG_BS_PRE_KP_3KP (2 << 4) +#define RF_BSCFG_BS_PRE_KP_4KP (3 << 4) +#define RF_BSCFG_BS_POST_KI_PRE_KI (0 << 3) +#define RF_BSCFG_BS_POST_KI_PRE_KI_OVER_2 (1 << 3) +#define RF_BSCFG_BS_POST_KP_PRE_KP (0 << 2) +#define RF_BSCFG_BS_POST_KP_PRE_KP_OVER_2 (1 << 2) +#define RF_BSCFG_BS_LIMIT_0 (0 << 0) +#define RF_BSCFG_BS_LIMIT_3_125 (1 << 0) +#define RF_BSCFG_BS_LIMIT_6_25 (2 << 0) +#define RF_BSCFG_BS_LIMIT_12_5 (3 << 0) + +__xdata __at (0xdf17) uint8_t RF_AGCCTRL2; +#define RF_AGCCTRL2_OFF 0x17 + +__xdata __at (0xdf18) uint8_t RF_AGCCTRL1; +#define RF_AGCCTRL1_OFF 0x18 + +__xdata __at (0xdf19) uint8_t RF_AGCCTRL0; +#define RF_AGCCTRL0_OFF 0x19 + +__xdata __at (0xdf1a) uint8_t RF_FREND1; +#define RF_FREND1_OFF 0x1a + +#define RF_FREND1_LNA_CURRENT_SHIFT 6 +#define RF_FREND1_LNA2MIX_CURRENT_SHIFT 4 +#define RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT 2 +#define RF_FREND1_MIX_CURRENT_SHIFT 0 + +__xdata __at (0xdf1b) uint8_t RF_FREND0; +#define RF_FREND0_OFF 0x1b + +#define RF_FREND0_LODIV_BUF_CURRENT_TX_MASK (0x3 << 4) +#define RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT 4 +#define RF_FREND0_PA_POWER_MASK (0x7) +#define RF_FREND0_PA_POWER_SHIFT 0 + +__xdata __at (0xdf1c) uint8_t RF_FSCAL3; +#define RF_FSCAL3_OFF 0x1c + +__xdata __at (0xdf1d) uint8_t RF_FSCAL2; +#define RF_FSCAL2_OFF 0x1d + +__xdata __at (0xdf1e) uint8_t RF_FSCAL1; +#define RF_FSCAL1_OFF 0x1e + +__xdata __at (0xdf1f) uint8_t RF_FSCAL0; +#define RF_FSCAL0_OFF 0x1f + +__xdata __at (0xdf23) uint8_t RF_TEST2; +#define RF_TEST2_OFF 0x23 + +#define RF_TEST2_NORMAL_MAGIC 0x88 +#define RF_TEST2_RX_LOW_DATA_RATE_MAGIC 0x81 + +__xdata __at (0xdf24) uint8_t RF_TEST1; +#define RF_TEST1_OFF 0x24 + +#define RF_TEST1_TX_MAGIC 0x31 +#define RF_TEST1_RX_LOW_DATA_RATE_MAGIC 0x35 + +__xdata __at (0xdf25) uint8_t RF_TEST0; +#define RF_TEST0_OFF 0x25 + +#define RF_TEST0_7_2_MASK (0xfc) +#define RF_TEST0_VCO_SEL_CAL_EN (1 << 1) +#define RF_TEST0_0_MASK (1) + +/* These are undocumented, and must be computed + * using the provided tool. + */ +__xdata __at (0xdf27) uint8_t RF_PA_TABLE7; +#define RF_PA_TABLE7_OFF 0x27 + +__xdata __at (0xdf28) uint8_t RF_PA_TABLE6; +#define RF_PA_TABLE6_OFF 0x28 + +__xdata __at (0xdf29) uint8_t RF_PA_TABLE5; +#define RF_PA_TABLE5_OFF 0x29 + +__xdata __at (0xdf2a) uint8_t RF_PA_TABLE4; +#define RF_PA_TABLE4_OFF 0x2a + +__xdata __at (0xdf2b) uint8_t RF_PA_TABLE3; +#define RF_PA_TABLE3_OFF 0x2b + +__xdata __at (0xdf2c) uint8_t RF_PA_TABLE2; +#define RF_PA_TABLE2_OFF 0x2c + +__xdata __at (0xdf2d) uint8_t RF_PA_TABLE1; +#define RF_PA_TABLE1_OFF 0x2d + +__xdata __at (0xdf2e) uint8_t RF_PA_TABLE0; +#define RF_PA_TABLE0_OFF 0x2e + +__xdata __at (0xdf36) uint8_t RF_PARTNUM; +#define RF_PARTNUM_OFF 0x36 + +__xdata __at (0xdf37) uint8_t RF_VERSION; +#define RF_VERSION_OFF 0x37 + +__xdata __at (0xdf38) uint8_t RF_FREQEST; +#define RF_FREQEST_OFF 0x38 + +__xdata __at (0xdf39) uint8_t RF_LQI; +#define RF_LQI_OFF 0x39 + +#define RF_LQI_CRC_OK (1 << 7) +#define RF_LQI_LQI_EST_MASK (0x7f) + +__xdata __at (0xdf3a) uint8_t RF_RSSI; +#define RF_RSSI_OFF 0x3a + +__xdata __at (0xdf3b) uint8_t RF_MARCSTATE; +#define RF_MARCSTATE_OFF 0x3b + +#define RF_MARCSTATE_MASK 0x1f +#define RF_MARCSTATE_SLEEP 0x00 +#define RF_MARCSTATE_IDLE 0x01 +#define RF_MARCSTATE_VCOON_MC 0x03 +#define RF_MARCSTATE_REGON_MC 0x04 +#define RF_MARCSTATE_MANCAL 0x05 +#define RF_MARCSTATE_VCOON 0x06 +#define RF_MARCSTATE_REGON 0x07 +#define RF_MARCSTATE_STARTCAL 0x08 +#define RF_MARCSTATE_BWBOOST 0x09 +#define RF_MARCSTATE_FS_LOCK 0x0a +#define RF_MARCSTATE_IFADCON 0x0b +#define RF_MARCSTATE_ENDCAL 0x0c +#define RF_MARCSTATE_RX 0x0d +#define RF_MARCSTATE_RX_END 0x0e +#define RF_MARCSTATE_RX_RST 0x0f +#define RF_MARCSTATE_TXRX_SWITCH 0x10 +#define RF_MARCSTATE_RX_OVERFLOW 0x11 +#define RF_MARCSTATE_FSTXON 0x12 +#define RF_MARCSTATE_TX 0x13 +#define RF_MARCSTATE_TX_END 0x14 +#define RF_MARCSTATE_RXTX_SWITCH 0x15 +#define RF_MARCSTATE_TX_UNDERFLOW 0x16 + + +__xdata __at (0xdf3c) uint8_t RF_PKTSTATUS; +#define RF_PKTSTATUS_OFF 0x3c + +#define RF_PKTSTATUS_CRC_OK (1 << 7) +#define RF_PKTSTATUS_CS (1 << 6) +#define RF_PKTSTATUS_PQT_REACHED (1 << 5) +#define RF_PKTSTATUS_CCA (1 << 4) +#define RF_PKTSTATUS_SFD (1 << 3) + +__xdata __at (0xdf3d) uint8_t RF_VCO_VC_DAC; +#define RF_VCO_VC_DAC_OFF 0x3d + +#endif diff --git a/src/check-stack b/src/check-stack deleted file mode 100755 index 1e8044e0..00000000 --- a/src/check-stack +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -HEADER=$1 -MEM=$2 - -HEADER_STACK=`awk '/#define AO_STACK_START/ {print strtonum($3)}' $HEADER` -MEM_STACK=`awk '/Stack starts at/ {print strtonum ($4)}' $MEM` - -if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then - echo $MEM_STACK | awk '{ printf ("Set AO_STACK_START to at least 0x%x\n", $1); }' - exit 1 -else - exit 0 -fi diff --git a/src/core/altitude.h b/src/core/altitude.h new file mode 100644 index 00000000..a278bbc6 --- /dev/null +++ b/src/core/altitude.h @@ -0,0 +1,132 @@ +/*max error 3.197865153490684 at 0.782%. Average error 0.260150920474668*/ +#define NALT 129 +#define ALT_FRAC_BITS 8 + 15835, /* 10.56 kPa 0.000% */ + 15332, /* 11.42 kPa 0.781% */ + 14868, /* 12.29 kPa 1.563% */ + 14435, /* 13.16 kPa 2.344% */ + 14030, /* 14.02 kPa 3.125% */ + 13649, /* 14.90 kPa 3.906% */ + 13290, /* 15.76 kPa 4.688% */ + 12950, /* 16.63 kPa 5.469% */ + 12627, /* 17.50 kPa 6.250% */ + 12320, /* 18.37 kPa 7.031% */ + 12027, /* 19.24 kPa 7.813% */ + 11747, /* 20.10 kPa 8.594% */ + 11479, /* 20.97 kPa 9.375% */ + 11222, /* 21.84 kPa 10.156% */ + 10975, /* 22.71 kPa 10.938% */ + 10736, /* 23.58 kPa 11.719% */ + 10504, /* 24.44 kPa 12.500% */ + 10278, /* 25.31 kPa 13.281% */ + 10059, /* 26.18 kPa 14.063% */ + 9846, /* 27.05 kPa 14.844% */ + 9638, /* 27.91 kPa 15.625% */ + 9435, /* 28.78 kPa 16.406% */ + 9237, /* 29.65 kPa 17.188% */ + 9044, /* 30.52 kPa 17.969% */ + 8855, /* 31.39 kPa 18.750% */ + 8670, /* 32.26 kPa 19.531% */ + 8490, /* 33.13 kPa 20.313% */ + 8313, /* 33.99 kPa 21.094% */ + 8140, /* 34.86 kPa 21.875% */ + 7970, /* 35.73 kPa 22.656% */ + 7803, /* 36.60 kPa 23.438% */ + 7640, /* 37.47 kPa 24.219% */ + 7480, /* 38.33 kPa 25.000% */ + 7322, /* 39.20 kPa 25.781% */ + 7168, /* 40.07 kPa 26.563% */ + 7016, /* 40.94 kPa 27.344% */ + 6867, /* 41.80 kPa 28.125% */ + 6720, /* 42.67 kPa 28.906% */ + 6575, /* 43.54 kPa 29.688% */ + 6433, /* 44.41 kPa 30.469% */ + 6294, /* 45.28 kPa 31.250% */ + 6156, /* 46.15 kPa 32.031% */ + 6020, /* 47.01 kPa 32.813% */ + 5887, /* 47.88 kPa 33.594% */ + 5755, /* 48.75 kPa 34.375% */ + 5625, /* 49.62 kPa 35.156% */ + 5497, /* 50.49 kPa 35.938% */ + 5371, /* 51.35 kPa 36.719% */ + 5247, /* 52.22 kPa 37.500% */ + 5124, /* 53.09 kPa 38.281% */ + 5003, /* 53.96 kPa 39.063% */ + 4883, /* 54.83 kPa 39.844% */ + 4765, /* 55.69 kPa 40.625% */ + 4648, /* 56.56 kPa 41.406% */ + 4533, /* 57.43 kPa 42.188% */ + 4419, /* 58.30 kPa 42.969% */ + 4307, /* 59.17 kPa 43.750% */ + 4196, /* 60.03 kPa 44.531% */ + 4086, /* 60.90 kPa 45.313% */ + 3977, /* 61.77 kPa 46.094% */ + 3870, /* 62.63 kPa 46.875% */ + 3764, /* 63.51 kPa 47.656% */ + 3659, /* 64.38 kPa 48.438% */ + 3555, /* 65.24 kPa 49.219% */ + 3453, /* 66.11 kPa 50.000% */ + 3351, /* 66.98 kPa 50.781% */ + 3250, /* 67.85 kPa 51.563% */ + 3151, /* 68.72 kPa 52.344% */ + 3052, /* 69.58 kPa 53.125% */ + 2955, /* 70.45 kPa 53.906% */ + 2858, /* 71.32 kPa 54.688% */ + 2763, /* 72.19 kPa 55.469% */ + 2668, /* 73.06 kPa 56.250% */ + 2574, /* 73.92 kPa 57.031% */ + 2482, /* 74.79 kPa 57.813% */ + 2390, /* 75.66 kPa 58.594% */ + 2298, /* 76.52 kPa 59.375% */ + 2208, /* 77.40 kPa 60.156% */ + 2119, /* 78.26 kPa 60.938% */ + 2030, /* 79.13 kPa 61.719% */ + 1942, /* 80.00 kPa 62.500% */ + 1855, /* 80.87 kPa 63.281% */ + 1769, /* 81.74 kPa 64.063% */ + 1683, /* 82.60 kPa 64.844% */ + 1598, /* 83.47 kPa 65.625% */ + 1514, /* 84.34 kPa 66.406% */ + 1430, /* 85.21 kPa 67.188% */ + 1347, /* 86.08 kPa 67.969% */ + 1265, /* 86.94 kPa 68.750% */ + 1184, /* 87.81 kPa 69.531% */ + 1103, /* 88.68 kPa 70.313% */ + 1023, /* 89.55 kPa 71.094% */ + 943, /* 90.41 kPa 71.875% */ + 864, /* 91.28 kPa 72.656% */ + 786, /* 92.15 kPa 73.438% */ + 708, /* 93.02 kPa 74.219% */ + 631, /* 93.89 kPa 75.000% */ + 554, /* 94.76 kPa 75.781% */ + 478, /* 95.63 kPa 76.563% */ + 403, /* 96.49 kPa 77.344% */ + 328, /* 97.36 kPa 78.125% */ + 254, /* 98.23 kPa 78.906% */ + 180, /* 99.10 kPa 79.688% */ + 106, /* 99.97 kPa 80.469% */ + 34, /* 100.83 kPa 81.250% */ + -39, /* 101.70 kPa 82.031% */ + -111, /* 102.57 kPa 82.813% */ + -182, /* 103.44 kPa 83.594% */ + -253, /* 104.30 kPa 84.375% */ + -323, /* 105.17 kPa 85.156% */ + -393, /* 106.04 kPa 85.938% */ + -462, /* 106.91 kPa 86.719% */ + -531, /* 107.78 kPa 87.500% */ + -600, /* 108.65 kPa 88.281% */ + -668, /* 109.51 kPa 89.063% */ + -736, /* 110.38 kPa 89.844% */ + -803, /* 111.25 kPa 90.625% */ + -870, /* 112.12 kPa 91.406% */ + -936, /* 112.99 kPa 92.188% */ + -1002, /* 113.85 kPa 92.969% */ + -1068, /* 114.72 kPa 93.750% */ + -1133, /* 115.59 kPa 94.531% */ + -1198, /* 116.46 kPa 95.313% */ + -1262, /* 117.33 kPa 96.094% */ + -1326, /* 118.19 kPa 96.875% */ + -1389, /* 119.06 kPa 97.656% */ + -1453, /* 119.93 kPa 98.438% */ + -1516, /* 120.80 kPa 99.219% */ + -1578, /* 121.67 kPa 100.000% */ diff --git a/src/core/ao.h b/src/core/ao.h new file mode 100644 index 00000000..8ac9ac3d --- /dev/null +++ b/src/core/ao.h @@ -0,0 +1,1610 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef _AO_H_ +#define _AO_H_ + +#include +#include +#include +#include +#include "cc1111.h" +#include "ao_pins.h" + +#define TRUE 1 +#define FALSE 0 + +/* Convert a __data pointer into an __xdata pointer */ +#define DATA_TO_XDATA(a) ((void __xdata *) ((uint8_t) (a) | 0xff00)) + +/* Stack runs from above the allocated __data space to 0xfe, which avoids + * writing to 0xff as that triggers the stack overflow indicator + */ +#define AO_STACK_START 0x90 +#define AO_STACK_END 0xfe +#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1) + +/* An AltOS task */ +struct ao_task { + __xdata void *wchan; /* current wait channel (NULL if running) */ + uint16_t alarm; /* abort ao_sleep time */ + uint8_t stack_count; /* amount of saved stack */ + uint8_t task_id; /* unique id */ + __code char *name; /* task name */ + uint8_t stack[AO_STACK_SIZE]; /* saved stack */ +}; + +extern __xdata struct ao_task *__data ao_cur_task; + +#define AO_NUM_TASKS 16 /* maximum number of tasks */ +#define AO_NO_TASK 0 /* no task id */ + +/* + ao_task.c + */ + +/* Suspend the current task until wchan is awoken. + * returns: + * 0 on normal wake + * 1 on alarm + */ +uint8_t +ao_sleep(__xdata void *wchan); + +/* Wake all tasks sleeping on wchan */ +void +ao_wakeup(__xdata void *wchan); + +/* set an alarm to go off in 'delay' ticks */ +void +ao_alarm(uint16_t delay); + +/* Yield the processor to another task */ +void +ao_yield(void) __naked; + +/* Add a task to the run queue */ +void +ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant; + +/* Terminate the current task */ +void +ao_exit(void); + +/* Dump task info to console */ +void +ao_task_info(void); + +/* Start the scheduler. This will not return */ +void +ao_start_scheduler(void); + +/* + * ao_panic.c + */ + +#define AO_PANIC_NO_TASK 1 /* AO_NUM_TASKS is not large enough */ +#define AO_PANIC_DMA 2 /* Attempt to start DMA while active */ +#define AO_PANIC_MUTEX 3 /* Mis-using mutex API */ +#define AO_PANIC_EE 4 /* Mis-using eeprom API */ +#define AO_PANIC_LOG 5 /* Failing to read/write log data */ +#define AO_PANIC_CMD 6 /* Too many command sets registered */ +#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */ +#define AO_PANIC_REBOOT 8 /* Reboot failed */ +#define AO_PANIC_FLASH 9 /* Invalid flash part (or wrong blocksize) */ +#define AO_PANIC_USB 10 /* Trying to send USB packet while busy */ +#define AO_PANIC_BT 11 /* Communications with bluetooth device failed */ + +/* Stop the operating system, beeping and blinking the reason */ +void +ao_panic(uint8_t reason); + +/* + * ao_timer.c + */ + +/* Our timer runs at 100Hz */ +#define AO_HERTZ 100 +#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ)) +#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ) + +/* Returns the current time in ticks */ +uint16_t +ao_time(void); + +/* Suspend the current task until ticks time has passed */ +void +ao_delay(uint16_t ticks); + +/* Set the ADC interval */ +void +ao_timer_set_adc_interval(uint8_t interval) __critical; + +/* Timer interrupt */ +void +ao_timer_isr(void) __interrupt 9; + +/* Initialize the timer */ +void +ao_timer_init(void); + +/* Initialize the hardware clock. Must be called first */ +void +ao_clock_init(void); + +/* + * One set of samples read from the A/D converter or telemetry + */ +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + int16_t accel; /* accelerometer */ + int16_t pres; /* pressure sensor */ + int16_t temp; /* temperature sensor */ + int16_t v_batt; /* battery voltage */ + int16_t sense_d; /* drogue continuity sense */ + int16_t sense_m; /* main continuity sense */ +}; + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#if HAS_ADC + +#if HAS_ACCEL +#ifndef HAS_ACCEL_REF +#error Please define HAS_ACCEL_REF +#endif +#else +#define HAS_ACCEL_REF 0 +#endif + +/* + * ao_adc.c + */ + +#define AO_ADC_RING 32 +#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) +#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) + + +/* + * A/D data is stored in a ring, with the next sample to be written + * at ao_adc_head + */ +extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; +extern volatile __data uint8_t ao_adc_head; +#if HAS_ACCEL_REF +extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; +#endif + +/* Trigger a conversion sequence (called from the timer interrupt) */ +void +ao_adc_poll(void); + +/* Suspend the current task until another A/D sample is converted */ +void +ao_adc_sleep(void); + +/* Get a copy of the last complete A/D sample set */ +void +ao_adc_get(__xdata struct ao_adc *packet); + +/* The A/D interrupt handler */ + +void +ao_adc_isr(void) __interrupt 1; + +/* Initialize the A/D converter */ +void +ao_adc_init(void); + +#endif /* HAS_ADC */ + +/* + * ao_beep.c + */ + +/* + * Various pre-defined beep frequencies + * + * frequency = 1/2 (24e6/32) / beep + */ + +#define AO_BEEP_LOW 150 /* 2500Hz */ +#define AO_BEEP_MID 94 /* 3989Hz */ +#define AO_BEEP_HIGH 75 /* 5000Hz */ +#define AO_BEEP_OFF 0 /* off */ + +#define AO_BEEP_g 240 /* 1562.5Hz */ +#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */ +#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */ +#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */ +#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */ +#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */ +#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */ +#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */ +#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */ +#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */ +#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */ +#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */ +#define AO_BEEP_gg 120 /* 3125Hz */ +#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */ +#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */ +#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */ +#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */ +#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */ +#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */ +#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */ +#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */ +#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */ +#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */ +#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */ +#define AO_BEEP_ggg 60 /* 6250Hz */ + +/* Set the beeper to the specified tone */ +void +ao_beep(uint8_t beep); + +/* Turn on the beeper for the specified time */ +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant; + +/* Initialize the beeper */ +void +ao_beep_init(void); + +/* + * ao_led.c + */ + +#define AO_LED_NONE 0 + +/* Turn on the specified LEDs */ +void +ao_led_on(uint8_t colors); + +/* Turn off the specified LEDs */ +void +ao_led_off(uint8_t colors); + +/* Set all of the LEDs to the specified state */ +void +ao_led_set(uint8_t colors); + +/* Toggle the specified LEDs */ +void +ao_led_toggle(uint8_t colors); + +/* Turn on the specified LEDs for the indicated interval */ +void +ao_led_for(uint8_t colors, uint16_t ticks) __reentrant; + +/* Initialize the LEDs */ +void +ao_led_init(uint8_t enable); + +/* + * ao_romconfig.c + */ + +#define AO_ROMCONFIG_VERSION 2 + +extern __code __at (0x00a0) uint16_t ao_romconfig_version; +extern __code __at (0x00a2) uint16_t ao_romconfig_check; +extern __code __at (0x00a4) uint16_t ao_serial_number; +extern __code __at (0x00a6) uint32_t ao_radio_cal; + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + +#if HAS_USB +extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; +#endif + +/* + * ao_usb.c + */ + +/* Put one character to the USB output queue */ +void +ao_usb_putchar(char c); + +/* Get one character from the USB input queue */ +char +ao_usb_getchar(void); + +/* Poll for a charcter on the USB input queue. + * returns AO_READ_AGAIN if none are available + */ +char +ao_usb_pollchar(void); + +/* Flush the USB output queue */ +void +ao_usb_flush(void); + +#if HAS_USB +/* USB interrupt handler */ +void +ao_usb_isr(void) __interrupt 6; +#endif + +/* Enable the USB controller */ +void +ao_usb_enable(void); + +/* Disable the USB controller */ +void +ao_usb_disable(void); + +/* Initialize the USB system */ +void +ao_usb_init(void); + +/* + * ao_cmd.c + */ + +enum ao_cmd_status { + ao_cmd_success = 0, + ao_cmd_lex_error = 1, + ao_cmd_syntax_error = 2, +}; + +extern __pdata uint16_t ao_cmd_lex_i; +extern __pdata uint32_t ao_cmd_lex_u32; +extern __pdata char ao_cmd_lex_c; +extern __pdata enum ao_cmd_status ao_cmd_status; + +void +ao_cmd_lex(void); + +void +ao_cmd_put8(uint8_t v); + +void +ao_cmd_put16(uint16_t v); + +void +ao_cmd_white(void); + +void +ao_cmd_hex(void); + +void +ao_cmd_decimal(void); + +uint8_t +ao_match_word(__code char *word); + +struct ao_cmds { + void (*func)(void); + __code char *help; +}; + +void +ao_cmd_register(__code struct ao_cmds *cmds); + +void +ao_cmd_init(void); + +#if HAS_CMD_FILTER +/* + * Provided by an external module to filter raw command lines + */ +uint8_t +ao_cmd_filter(void); +#endif + +/* + * ao_dma.c + */ + +/* Allocate a DMA channel. the 'done' parameter will be set when the + * dma is finished and will be used to wakeup any waiters + */ + +uint8_t +ao_dma_alloc(__xdata uint8_t * done); + +/* Setup a DMA channel */ +void +ao_dma_set_transfer(uint8_t id, + void __xdata *srcaddr, + void __xdata *dstaddr, + uint16_t count, + uint8_t cfg0, + uint8_t cfg1); + +/* Start a DMA channel */ +void +ao_dma_start(uint8_t id); + +/* Manually trigger a DMA channel */ +void +ao_dma_trigger(uint8_t id); + +/* Abort a running DMA transfer */ +void +ao_dma_abort(uint8_t id); + +/* DMA interrupt routine */ +void +ao_dma_isr(void) __interrupt 8; + +/* + * ao_mutex.c + */ + +void +ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant; + +void +ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant; + +/* + * Storage interface, provided by one of the eeprom or flash + * drivers + */ + +/* Total bytes of available storage */ +extern __pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +extern __pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +extern __pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +extern __pdata uint16_t ao_storage_unit; + +#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE) + +/* Initialize above values. Can only be called once the OS is running */ +void +ao_storage_setup(void) __reentrant; + +/* Write data. Returns 0 on failure, 1 on success */ +uint8_t +ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Read data. Returns 0 on failure, 1 on success */ +uint8_t +ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Erase a block of storage. This always clears ao_storage_block bytes */ +uint8_t +ao_storage_erase(uint32_t pos) __reentrant; + +/* Flush any pending writes to stable storage */ +void +ao_storage_flush(void) __reentrant; + +/* Initialize the storage code */ +void +ao_storage_init(void); + +/* + * Low-level functions wrapped by ao_storage.c + */ + +/* Read data within a storage unit */ +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Write data within a storage unit */ +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Initialize low-level device bits */ +void +ao_storage_device_init(void); + +/* Print out information about flash chips */ +void +ao_storage_device_info(void) __reentrant; + +/* + * ao_log.c + */ + +/* We record flight numbers in the first record of + * the log. Tasks may wait for this to be initialized + * by sleeping on this variable. + */ +extern __xdata uint16_t ao_flight_number; + +extern __pdata uint32_t ao_log_current_pos; +extern __pdata uint32_t ao_log_end_pos; +extern __pdata uint32_t ao_log_start_pos; +extern __xdata uint8_t ao_log_running; +extern __pdata enum flight_state ao_log_state; + +/* required functions from the underlying log system */ + +#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ +#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ +#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ +#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ +#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ +#define AO_LOG_FORMAT_NONE 127 /* No log at all */ + +extern __code uint8_t ao_log_format; + +/* Return the flight number from the given log slot, 0 if none */ +uint16_t +ao_log_flight(uint8_t slot); + +/* Flush the log */ +void +ao_log_flush(void); + +/* Logging thread main routine */ +void +ao_log(void); + +/* functions provided in ao_log.c */ + +/* Figure out the current flight number */ +void +ao_log_scan(void) __reentrant; + +/* Return the position of the start of the given log slot */ +uint32_t +ao_log_pos(uint8_t slot); + +/* Start logging to eeprom */ +void +ao_log_start(void); + +/* Stop logging */ +void +ao_log_stop(void); + +/* Initialize the logging system */ +void +ao_log_init(void); + +/* Write out the current flight number to the erase log */ +void +ao_log_write_erase(uint8_t pos); + +/* Returns true if there are any logs stored in eeprom */ +uint8_t +ao_log_present(void); + +/* Returns true if there is no more storage space available */ +uint8_t +ao_log_full(void); + +/* + * ao_log_big.c + */ + +/* + * The data log is recorded in the eeprom as a sequence + * of data packets. + * + * Each packet starts with a 4-byte header that has the + * packet type, the packet checksum and the tick count. Then + * they all contain 2 16 bit values which hold packet-specific + * data. + * + * For each flight, the first packet + * is FLIGHT packet, indicating the serial number of the + * device and a unique number marking the number of flights + * recorded by this device. + * + * During flight, data from the accelerometer and barometer + * are recorded in SENSOR packets, using the raw 16-bit values + * read from the A/D converter. + * + * Also during flight, but at a lower rate, the deployment + * sensors are recorded in DEPLOY packets. The goal here is to + * detect failure in the deployment circuits. + * + * STATE packets hold state transitions as the flight computer + * transitions through different stages of the flight. + */ +#define AO_LOG_FLIGHT 'F' +#define AO_LOG_SENSOR 'A' +#define AO_LOG_TEMP_VOLT 'T' +#define AO_LOG_DEPLOY 'D' +#define AO_LOG_STATE 'S' +#define AO_LOG_GPS_TIME 'G' +#define AO_LOG_GPS_LAT 'N' +#define AO_LOG_GPS_LON 'W' +#define AO_LOG_GPS_ALT 'H' +#define AO_LOG_GPS_SAT 'V' +#define AO_LOG_GPS_DATE 'Y' + +#define AO_LOG_POS_NONE (~0UL) + +struct ao_log_record { + char type; + uint8_t csum; + uint16_t tick; + union { + struct { + int16_t ground_accel; + uint16_t flight; + } flight; + struct { + int16_t accel; + int16_t pres; + } sensor; + struct { + int16_t temp; + int16_t v_batt; + } temp_volt; + struct { + int16_t drogue; + int16_t main; + } deploy; + struct { + uint16_t state; + uint16_t reason; + } state; + struct { + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t flags; + } gps_time; + int32_t gps_latitude; + int32_t gps_longitude; + struct { + int16_t altitude; + uint16_t unused; + } gps_altitude; + struct { + uint16_t svid; + uint8_t unused; + uint8_t c_n; + } gps_sat; + struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t extra; + } gps_date; + struct { + uint16_t d0; + uint16_t d1; + } anon; + } u; +}; + +/* Write a record to the eeprom log */ +uint8_t +ao_log_data(__xdata struct ao_log_record *log) __reentrant; + +/* + * ao_flight.c + */ + +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 __pdata enum ao_flight_state ao_flight_state; + +extern __pdata uint16_t ao_launch_time; +extern __pdata uint8_t ao_flight_force_idle; + +/* Flight thread */ +void +ao_flight(void); + +/* Initialize flight thread */ +void +ao_flight_init(void); + +/* + * ao_flight_nano.c + */ + +void +ao_flight_nano_init(void); + +/* + * ao_sample.c + */ + +/* + * Barometer calibration + * + * We directly sample the barometer. The specs say: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * If we want to detect launch with the barometer, we need + * a large enough bump to not be fooled by noise. At typical + * launch elevations (0-2000m), a 200Pa pressure change cooresponds + * to about a 20m elevation change. This is 5.4mV, or about 3LSB. + * As all of our calculations are done in 16 bits, we'll actually see a change + * of 16 times this though + * + * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa + */ + +/* Accelerometer calibration + * + * We're sampling the accelerometer through a resistor divider which + * consists of 5k and 10k resistors. This multiplies the values by 2/3. + * That goes into the cc1111 A/D converter, which is running at 11 bits + * of precision with the bits in the MSB of the 16 bit value. Only positive + * values are used, so values should range from 0-32752 for 0-3.3V. The + * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what + * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, + * for a final computation of: + * + * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g + * + * Zero g was measured at 16000 (we would expect 16384). + * Note that this value is only require to tell if the + * rocket is standing upright. Once that is determined, + * the value of the accelerometer is averaged for 100 samples + * to find the resting accelerometer value, which is used + * for all further flight computations + */ + +#define GRAVITY 9.80665 + +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 12000 + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 200 + +#define ACCEL_NOSE_UP (ao_accel_2g >> 2) + +/* + * Speed and acceleration are scaled by 16 to provide a bit more + * resolution while still having reasonable range. Note that this + * limits speed to 2047m/s (around mach 6) and acceleration to + * 2047m/s² (over 200g) + */ + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + +extern __pdata uint16_t ao_sample_tick; /* time of last data */ +extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */ +extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */ +extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */ +extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ + +#if HAS_ACCEL +extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */ +#endif + +extern __pdata int16_t ao_ground_pres; /* startup pressure */ +extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +extern __pdata int16_t ao_ground_accel; /* startup acceleration */ +extern __pdata int16_t ao_accel_2g; /* factory accel calibration */ +extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +void ao_sample_init(void); + +/* returns FALSE in preflight mode, TRUE in flight mode */ +uint8_t ao_sample(void); + +/* + * ao_kalman.c + */ + +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) +#define from_fix(x) ((x) >> 16) + +extern __pdata int16_t ao_height; /* meters */ +extern __pdata int16_t ao_speed; /* m/s * 16 */ +extern __pdata int16_t ao_accel; /* m/s² * 16 */ +extern __pdata int16_t ao_max_height; /* max of ao_height */ +extern __pdata int16_t ao_avg_height; /* running average of height */ + +extern __pdata int16_t ao_error_h; +extern __pdata int16_t ao_error_h_sq_avg; + +#if HAS_ACCEL +extern __pdata int16_t ao_error_a; +#endif + +void ao_kalman(void); + +/* + * ao_report.c + */ + +void +ao_report_init(void); + +/* + * ao_convert.c + * + * Given raw data, convert to SI units + */ + +/* pressure from the sensor to altitude in meters */ +int16_t +ao_pres_to_altitude(int16_t pres) __reentrant; + +int16_t +ao_altitude_to_pres(int16_t alt) __reentrant; + +int16_t +ao_temp_to_dC(int16_t temp) __reentrant; + +/* + * ao_dbg.c + * + * debug another telemetrum board + */ + +/* Send a byte to the dbg target */ +void +ao_dbg_send_byte(uint8_t byte); + +/* Receive a byte from the dbg target */ +uint8_t +ao_dbg_recv_byte(void); + +/* Start a bulk transfer to/from dbg target memory */ +void +ao_dbg_start_transfer(uint16_t addr); + +/* End a bulk transfer to/from dbg target memory */ +void +ao_dbg_end_transfer(void); + +/* Write a byte to dbg target memory */ +void +ao_dbg_write_byte(uint8_t byte); + +/* Read a byte from dbg target memory */ +uint8_t +ao_dbg_read_byte(void); + +/* Enable dbg mode, switching use of the pins */ +void +ao_dbg_debug_mode(void); + +/* Reset the dbg target */ +void +ao_dbg_reset(void); + +void +ao_dbg_init(void); + +/* + * ao_serial.c + */ + +#ifndef HAS_SERIAL_1 +#error Please define HAS_SERIAL_1 +#endif + +#if HAS_SERIAL_1 +#ifndef USE_SERIAL_STDIN +#error Please define USE_SERIAL_STDIN +#endif + +void +ao_serial_rx1_isr(void) __interrupt 3; + +void +ao_serial_tx1_isr(void) __interrupt 14; + +char +ao_serial_getchar(void) __critical; + +#if USE_SERIAL_STDIN +char +ao_serial_pollchar(void) __critical; + +void +ao_serial_set_stdin(uint8_t stdin); +#endif + +void +ao_serial_putchar(char c) __critical; + +void +ao_serial_drain(void) __critical; + +#define AO_SERIAL_SPEED_4800 0 +#define AO_SERIAL_SPEED_9600 1 +#define AO_SERIAL_SPEED_19200 2 +#define AO_SERIAL_SPEED_57600 3 + +void +ao_serial_set_speed(uint8_t speed); + +void +ao_serial_init(void); +#endif + +/* + * ao_spi.c + */ + +extern __xdata uint8_t ao_spi_mutex; + +#define ao_spi_get_mask(reg,mask) do {\ + ao_mutex_get(&ao_spi_mutex); \ + (reg) &= ~(mask); \ + } while (0) + +#define ao_spi_put_mask(reg,mask) do { \ + (reg) |= (mask); \ + ao_mutex_put(&ao_spi_mutex); \ + } while (0) + +#define ao_spi_get_bit(bit) do {\ + ao_mutex_get(&ao_spi_mutex); \ + (bit) = 0; \ + } while (0) + +#define ao_spi_put_bit(bit) do { \ + (bit) = 1; \ + ao_mutex_put(&ao_spi_mutex); \ + } while (0) + +/* + * The SPI mutex must be held to call either of these + * functions -- this mutex covers the entire SPI operation, + * from chip select low to chip select high + */ + +void +ao_spi_send(void __xdata *block, uint16_t len) __reentrant; + +void +ao_spi_recv(void __xdata *block, uint16_t len) __reentrant; + +void +ao_spi_init(void); + +/* + * ao_telemetry.c + */ +#define AO_MAX_CALLSIGN 8 +#define AO_MAX_VERSION 8 +#define AO_MAX_TELEMETRY 128 + +struct ao_telemetry_generic { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t payload[27]; /* 5 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 +#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 +#define AO_TELEMETRY_SENSOR_TELENANO 0x03 + +struct ao_telemetry_sensor { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t state; /* 5 flight state */ + int16_t accel; /* 6 accelerometer (TM only) */ + int16_t pres; /* 8 pressure sensor */ + int16_t temp; /* 10 temperature sensor */ + int16_t v_batt; /* 12 battery voltage */ + int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ + int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ + + int16_t acceleration; /* 18 m/s² * 16 */ + int16_t speed; /* 20 m/s * 16 */ + int16_t height; /* 22 m */ + + int16_t ground_pres; /* 24 average pres on pad */ + int16_t ground_accel; /* 26 average accel on pad */ + int16_t accel_plus_g; /* 28 accel calibration at +1g */ + int16_t accel_minus_g; /* 30 accel calibration at -1g */ + /* 32 */ +}; + +#define AO_TELEMETRY_CONFIGURATION 0x04 + +struct ao_telemetry_configuration { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t device; /* 5 device type */ + uint16_t flight; /* 6 flight number */ + uint8_t config_major; /* 8 Config major version */ + uint8_t config_minor; /* 9 Config minor version */ + uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ + uint16_t main_deploy; /* 12 Main deploy alt in meters */ + uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ + char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ + char version[AO_MAX_VERSION]; /* 24 Software version */ + /* 32 */ +}; + +#define AO_TELEMETRY_LOCATION 0x05 + +#define AO_GPS_MODE_NOT_VALID 'N' +#define AO_GPS_MODE_AUTONOMOUS 'A' +#define AO_GPS_MODE_DIFFERENTIAL 'D' +#define AO_GPS_MODE_ESTIMATED 'E' +#define AO_GPS_MODE_MANUAL 'M' +#define AO_GPS_MODE_SIMULATED 'S' + +struct ao_telemetry_location { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t flags; /* 5 Number of sats and other flags */ + int16_t altitude; /* 6 GPS reported altitude (m) */ + int32_t latitude; /* 8 latitude (degrees * 10⁷) */ + int32_t longitude; /* 12 longitude (degrees * 10⁷) */ + uint8_t year; /* 16 (- 2000) */ + uint8_t month; /* 17 (1-12) */ + uint8_t day; /* 18 (1-31) */ + uint8_t hour; /* 19 (0-23) */ + uint8_t minute; /* 20 (0-59) */ + uint8_t second; /* 21 (0-59) */ + uint8_t pdop; /* 22 (m * 5) */ + uint8_t hdop; /* 23 (m * 5) */ + uint8_t vdop; /* 24 (m * 5) */ + uint8_t mode; /* 25 */ + uint16_t ground_speed; /* 26 cm/s */ + int16_t climb_rate; /* 28 cm/s */ + uint8_t course; /* 30 degrees / 2 */ + uint8_t unused[1]; /* 31 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SATELLITE 0x06 + +struct ao_telemetry_satellite_info { + uint8_t svid; + uint8_t c_n_1; +}; + +struct ao_telemetry_satellite { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t channels; /* 5 number of reported sats */ + + struct ao_telemetry_satellite_info sats[12]; /* 6 */ + uint8_t unused[2]; /* 30 */ + /* 32 */ +}; + +#define AO_TELEMETRY_COMPANION 0x07 + +#define AO_COMPANION_MAX_CHANNELS 12 + +struct ao_telemetry_companion { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t board_id; /* 5 */ + + uint8_t update_period; /* 6 */ + uint8_t channels; /* 7 */ + uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */ + /* 32 */ +}; + +union ao_telemetry_all { + struct ao_telemetry_generic generic; + struct ao_telemetry_sensor sensor; + struct ao_telemetry_configuration configuration; + struct ao_telemetry_location location; + struct ao_telemetry_satellite satellite; + struct ao_telemetry_companion companion; +}; + +/* + * ao_gps.c + */ + +#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) + +extern __pdata uint16_t ao_gps_tick; +extern __xdata uint8_t ao_gps_mutex; +extern __xdata struct ao_telemetry_location ao_gps_data; +extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data; + +struct ao_gps_orig { + 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 hdop; /* * 5 */ + int16_t climb_rate; /* cm/s */ + uint16_t h_error; /* m */ + uint16_t v_error; /* m */ +}; + +struct ao_gps_sat_orig { + uint8_t svid; + uint8_t c_n_1; +}; + +#define AO_MAX_GPS_TRACKING 12 + +struct ao_gps_tracking_orig { + uint8_t channels; + struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; +}; + +void +ao_gps(void); + +void +ao_gps_print(__xdata struct ao_gps_orig *gps_data); + +void +ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data); + +void +ao_gps_init(void); + +/* + * ao_gps_report.c + */ + +void +ao_gps_report(void); + +void +ao_gps_report_init(void); + +/* + * ao_telemetry_orig.c + */ + +struct ao_telemetry_orig { + uint16_t serial; + uint16_t flight; + uint8_t flight_state; + int16_t accel; + int16_t ground_accel; + union { + struct { + int16_t speed; + int16_t unused; + } k; + int32_t flight_vel; + } u; + int16_t height; + int16_t ground_pres; + int16_t accel_plus_g; + int16_t accel_minus_g; + struct ao_adc adc; + struct ao_gps_orig gps; + char callsign[AO_MAX_CALLSIGN]; + struct ao_gps_tracking_orig gps_tracking; +}; + +struct ao_telemetry_tiny { + uint16_t serial; + uint16_t flight; + uint8_t flight_state; + int16_t height; /* AGL in meters */ + int16_t speed; /* in m/s * 16 */ + int16_t accel; /* in m/s² * 16 */ + int16_t ground_pres; /* sensor units */ + struct ao_adc adc; /* raw ADC readings */ + char callsign[AO_MAX_CALLSIGN]; +}; + +/* + * ao_radio_recv tacks on rssi and status bytes + */ + +struct ao_telemetry_raw_recv { + uint8_t packet[AO_MAX_TELEMETRY + 2]; +}; + +struct ao_telemetry_orig_recv { + struct ao_telemetry_orig telemetry_orig; + int8_t rssi; + uint8_t status; +}; + +struct ao_telemetry_tiny_recv { + struct ao_telemetry_tiny telemetry_tiny; + int8_t rssi; + uint8_t status; +}; + +/* Set delay between telemetry reports (0 to disable) */ + +#define AO_TELEMETRY_INTERVAL_PAD AO_MS_TO_TICKS(1000) +#define AO_TELEMETRY_INTERVAL_FLIGHT AO_MS_TO_TICKS(100) +#define AO_TELEMETRY_INTERVAL_RECOVER AO_MS_TO_TICKS(1000) + +void +ao_telemetry_set_interval(uint16_t interval); + +void +ao_rdf_set(uint8_t rdf); + +void +ao_telemetry_init(void); + +void +ao_telemetry_orig_init(void); + +void +ao_telemetry_tiny_init(void); + +/* + * ao_radio.c + */ + +extern __xdata uint8_t ao_radio_dma; +extern __xdata uint8_t ao_radio_dma_done; +extern __xdata uint8_t ao_radio_done; +extern __xdata uint8_t ao_radio_mutex; + +void +ao_radio_general_isr(void) __interrupt 16; + +void +ao_radio_get(uint8_t len); + +#define ao_radio_put() ao_mutex_put(&ao_radio_mutex) + +void +ao_radio_set_packet(void); + +void +ao_radio_send(__xdata void *data, uint8_t size) __reentrant; + +uint8_t +ao_radio_recv(__xdata void *data, uint8_t size) __reentrant; + +void +ao_radio_recv_abort(void); + +void +ao_radio_rdf(int ms); + +void +ao_radio_rdf_abort(void); + +void +ao_radio_idle(void); + +void +ao_radio_init(void); + +/* + * ao_monitor.c + */ + +extern const char const * const ao_state_names[]; + +void +ao_monitor(void); + +#define AO_MONITORING_OFF 0 +#define AO_MONITORING_ORIG 1 +#define AO_MONITORING_TINY 2 + +void +ao_set_monitor(uint8_t monitoring); + +void +ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant; + +/* + * ao_stdio.c + */ + +#define AO_READ_AGAIN ((char) -1) + +struct ao_stdio { + char (*pollchar)(void); + void (*putchar)(char c) __reentrant; + void (*flush)(void); + uint8_t echo; +}; + +extern __xdata struct ao_stdio ao_stdios[]; +extern __pdata int8_t ao_cur_stdio; +extern __pdata int8_t ao_num_stdios; + +void +flush(void); + +extern __xdata uint8_t ao_stdin_ready; + +uint8_t +ao_echo(void); + +int8_t +ao_add_stdio(char (*pollchar)(void), + void (*putchar)(char) __reentrant, + void (*flush)(void)) __reentrant; + +/* + * ao_ignite.c + */ + +enum ao_igniter { + ao_igniter_drogue = 0, + ao_igniter_main = 1 +}; + +void +ao_ignite(enum ao_igniter igniter); + +enum ao_igniter_status { + ao_igniter_unknown, /* unknown status (ambiguous voltage) */ + ao_igniter_ready, /* continuity detected */ + ao_igniter_active, /* igniter firing */ + ao_igniter_open, /* open circuit detected */ +}; + +enum ao_igniter_status +ao_igniter_status(enum ao_igniter igniter); + +void +ao_ignite_set_pins(void); + +void +ao_igniter_init(void); + +/* + * ao_config.c + */ + +#define AO_CONFIG_MAJOR 1 +#define AO_CONFIG_MINOR 8 + +struct ao_config { + uint8_t major; + uint8_t minor; + uint16_t main_deploy; + int16_t accel_plus_g; /* changed for minor version 2 */ + uint8_t radio_channel; + char callsign[AO_MAX_CALLSIGN + 1]; + uint8_t apogee_delay; /* minor version 1 */ + int16_t accel_minus_g; /* minor version 2 */ + uint32_t radio_cal; /* minor version 3 */ + uint32_t flight_log_max; /* minor version 4 */ + uint8_t ignite_mode; /* minor version 5 */ + uint8_t pad_orientation; /* minor version 6 */ + uint32_t radio_setting; /* minor version 7 */ + uint8_t radio_enable; /* minor version 8 */ +}; + +#define AO_IGNITE_MODE_DUAL 0 +#define AO_IGNITE_MODE_APOGEE 1 +#define AO_IGNITE_MODE_MAIN 2 + +#define AO_PAD_ORIENTATION_ANTENNA_UP 0 +#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 + +extern __xdata struct ao_config ao_config; + +#define AO_CONFIG_MAX_SIZE 128 + +void +ao_config_get(void); + +void +ao_config_put(void); + +void +ao_config_init(void); + +/* + * ao_rssi.c + */ + +void +ao_rssi_set(int rssi_value); + +void +ao_rssi_init(uint8_t rssi_led); + +/* + * ao_product.c + * + * values which need to be defined for + * each instance of a product + */ + +extern const char ao_version[]; +extern const char ao_manufacturer[]; +extern const char ao_product[]; + +/* + * Fifos + */ + +#define AO_FIFO_SIZE 32 + +struct ao_fifo { + uint8_t insert; + uint8_t remove; + char fifo[AO_FIFO_SIZE]; +}; + +#define ao_fifo_insert(f,c) do { \ + (f).fifo[(f).insert] = (c); \ + (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \ +} while(0) + +#define ao_fifo_remove(f,c) do {\ + c = (f).fifo[(f).remove]; \ + (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \ +} while(0) + +#define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove) +#define ao_fifo_empty(f) ((f).insert == (f).remove) + +/* + * ao_packet.c + * + * Packet-based command interface + */ + +#define AO_PACKET_MAX 64 +#define AO_PACKET_SYN (uint8_t) 0xff + +struct ao_packet { + uint8_t addr; + uint8_t len; + uint8_t seq; + uint8_t ack; + uint8_t d[AO_PACKET_MAX]; + uint8_t callsign[AO_MAX_CALLSIGN]; +}; + +struct ao_packet_recv { + struct ao_packet packet; + int8_t rssi; + uint8_t status; +}; + +extern __xdata struct ao_packet_recv ao_rx_packet; +extern __xdata struct ao_packet ao_tx_packet; +extern __xdata struct ao_task ao_packet_task; +extern __xdata uint8_t ao_packet_enable; +extern __xdata uint8_t ao_packet_master_sleeping; +extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; + +void +ao_packet_send(void); + +uint8_t +ao_packet_recv(void); + +void +ao_packet_flush(void); + +void +ao_packet_putchar(char c) __reentrant; + +char +ao_packet_pollchar(void) __critical; + +/* ao_packet_master.c */ + +void +ao_packet_master_init(void); + +/* ao_packet_slave.c */ + +void +ao_packet_slave_start(void); + +void +ao_packet_slave_stop(void); + +void +ao_packet_slave_init(uint8_t enable); + +/* ao_btm.c */ + +/* If bt_link is on P2, this interrupt is shared by USB, so the USB + * code calls this function. Otherwise, it's a regular ISR. + */ + +void +ao_btm_isr(void) +#if BT_LINK_ON_P1 + __interrupt 15 +#endif + ; + +void +ao_btm_init(void); + +/* ao_companion.c */ + +#define AO_COMPANION_SETUP 1 +#define AO_COMPANION_FETCH 2 +#define AO_COMPANION_NOTIFY 3 + +struct ao_companion_command { + uint8_t command; + uint8_t flight_state; + uint16_t tick; + uint16_t serial; + uint16_t flight; +}; + +struct ao_companion_setup { + uint16_t board_id; + uint16_t board_id_inverse; + uint8_t update_period; + uint8_t channels; +}; + +extern __pdata uint8_t ao_companion_running; +extern __xdata struct ao_companion_setup ao_companion_setup; +extern __xdata uint8_t ao_companion_mutex; +extern __xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; + +void +ao_companion_init(void); + +#endif /* _AO_H_ */ diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c new file mode 100644 index 00000000..1442ebea --- /dev/null +++ b/src/core/ao_cmd.c @@ -0,0 +1,320 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +__pdata uint16_t ao_cmd_lex_i; +__pdata uint32_t ao_cmd_lex_u32; +__pdata char ao_cmd_lex_c; +__pdata enum ao_cmd_status ao_cmd_status; + +#define CMD_LEN 32 + +static __xdata char cmd_line[CMD_LEN]; +static __pdata uint8_t cmd_len; +static __pdata uint8_t cmd_i; + +static void +put_string(__code char *s) +{ + char c; + while (c = *s++) + putchar(c); +} + +static void +readline(void) +{ + __pdata char c; + if (ao_echo()) + put_string("> "); + cmd_len = 0; + for (;;) { + flush(); + c = getchar(); + /* backspace/delete */ + if (c == '\010' || c == '\177') { + if (cmd_len != 0) { + if (ao_echo()) + put_string("\010 \010"); + --cmd_len; + } + continue; + } + + /* ^U */ + if (c == '\025') { + while (cmd_len != 0) { + if (ao_echo()) + put_string("\010 \010"); + --cmd_len; + } + continue; + } + + /* map CR to NL */ + if (c == '\r') + c = '\n'; + + if (c == '\n') { + if (ao_echo()) + putchar('\n'); + break; + } + + if (cmd_len >= CMD_LEN - 2) { + if (ao_echo()) + putchar('\007'); + continue; + } + cmd_line[cmd_len++] = c; + if (ao_echo()) + putchar(c); + } + cmd_line[cmd_len++] = '\n'; + cmd_line[cmd_len++] = '\0'; + cmd_i = 0; +} + +void +ao_cmd_lex(void) +{ + ao_cmd_lex_c = '\n'; + if (cmd_i < cmd_len) + ao_cmd_lex_c = cmd_line[cmd_i++]; +} + +static void +putnibble(uint8_t v) +{ + if (v < 10) + putchar(v + '0'); + else + putchar(v + ('a' - 10)); +} + +void +ao_cmd_put16(uint16_t v) +{ + ao_cmd_put8(v >> 8); + ao_cmd_put8(v); +} + +void +ao_cmd_put8(uint8_t v) +{ + putnibble((v >> 4) & 0xf); + putnibble(v & 0xf); +} + +void +ao_cmd_white(void) +{ + while (ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t') + ao_cmd_lex(); +} + +void +ao_cmd_hex(void) +{ + __pdata uint8_t r = ao_cmd_lex_error; + uint8_t n; + + ao_cmd_lex_i = 0; + ao_cmd_white(); + for(;;) { + if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') + n = (ao_cmd_lex_c - '0'); + else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f') + n = (ao_cmd_lex_c - 'a' + 10); + else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F') + n = (ao_cmd_lex_c - 'A' + 10); + else + break; + ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n; + r = ao_cmd_success; + ao_cmd_lex(); + } + if (r != ao_cmd_success) + ao_cmd_status = r; +} + +void +ao_cmd_decimal(void) +{ + __pdata uint8_t r = ao_cmd_lex_error; + + ao_cmd_lex_u32 = 0; + ao_cmd_white(); + for(;;) { + if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') + ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0'); + else + break; + r = ao_cmd_success; + ao_cmd_lex(); + } + if (r != ao_cmd_success) + ao_cmd_status = r; + ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32; +} + +uint8_t +ao_match_word(__code char *word) +{ + while (*word) { + if (ao_cmd_lex_c != *word) { + ao_cmd_status = ao_cmd_syntax_error; + return 0; + } + word++; + ao_cmd_lex(); + } + return 1; +} + +static void +eol(void) +{ + while (ao_cmd_lex_c != '\n') + ao_cmd_lex(); +} + +static void +echo(void) +{ + ao_cmd_hex(); + if (ao_cmd_status == ao_cmd_success) + ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0; +} + +static void +ao_reboot(void) +{ + ao_cmd_white(); + if (!ao_match_word("eboot")) + return; + WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64; + ao_delay(AO_SEC_TO_TICKS(2)); + ao_panic(AO_PANIC_REBOOT); +} + +static void +version(void) +{ + printf("manufacturer %s\n", ao_manufacturer); + printf("product %s\n", ao_product); + printf("serial-number %u\n", ao_serial_number); +#if HAS_EEPROM + printf("log-format %u\n", ao_log_format); +#endif + printf("software-version %s\n", ao_version); +} + +#define NUM_CMDS 11 + +static __code struct ao_cmds *__xdata (ao_cmds[NUM_CMDS]); +static __pdata uint8_t ao_ncmds; + +static void +help(void) +{ + register uint8_t cmds; + register uint8_t cmd; + register __code struct ao_cmds * cs; + + for (cmds = 0; cmds < ao_ncmds; cmds++) { + cs = ao_cmds[cmds]; + for (cmd = 0; cs[cmd].func; cmd++) + printf("%-45s %s\n", + cs[cmd].help, + cs[cmd].help+1+strlen(cs[cmd].help)); + } +} + +static void +report(void) +{ + switch(ao_cmd_status) { + case ao_cmd_lex_error: + case ao_cmd_syntax_error: + puts("Syntax error"); + ao_cmd_status = 0; + break; + } +} + +void +ao_cmd_register(__code struct ao_cmds *cmds) +{ + if (ao_ncmds >= NUM_CMDS) + ao_panic(AO_PANIC_CMD); + ao_cmds[ao_ncmds++] = cmds; +} + +void +ao_cmd(void) +{ + char c; + uint8_t cmd, cmds; + __code struct ao_cmds * __xdata cs; + void (*__xdata func)(void); + + for (;;) { + readline(); + ao_cmd_lex(); + ao_cmd_white(); + c = ao_cmd_lex_c; + ao_cmd_lex(); + if (c == '\r' || c == '\n') + continue; + func = (void (*)(void)) NULL; + for (cmds = 0; cmds < ao_ncmds; cmds++) { + cs = ao_cmds[cmds]; + for (cmd = 0; cs[cmd].func; cmd++) + if (cs[cmd].help[0] == c) { + func = cs[cmd].func; + break; + } + if (func) + break; + } + if (func) + (*func)(); + else + ao_cmd_status = ao_cmd_syntax_error; + report(); + } +} + +__xdata struct ao_task ao_cmd_task; + +__code struct ao_cmds ao_base_cmds[] = { + { help, "?\0Help" }, + { ao_task_info, "T\0Show tasks" }, + { echo, "E <0 off, 1 on>\0Set echo mode" }, + { ao_reboot, "r eboot\0Reboot" }, + { version, "v\0Version" }, + { 0, NULL }, +}; + +void +ao_cmd_init(void) +{ + ao_cmd_register(&ao_base_cmds[0]); + ao_add_task(&ao_cmd_task, ao_cmd, "cmd"); +} diff --git a/src/core/ao_config.c b/src/core/ao_config.c new file mode 100644 index 00000000..0c10e608 --- /dev/null +++ b/src/core/ao_config.c @@ -0,0 +1,542 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +__xdata struct ao_config ao_config; +__pdata uint8_t ao_config_loaded; +__pdata uint8_t ao_config_dirty; +__xdata uint8_t ao_config_mutex; + +#define AO_CONFIG_DEFAULT_MAIN_DEPLOY 250 +#define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0 +#define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL" +#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000 +#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0 +#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL +#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP +#if HAS_EEPROM +#ifndef USE_INTERNAL_FLASH +#error Please define USE_INTERNAL_FLASH +#endif +#endif +#if USE_INTERNAL_FLASH +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config +#else +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024) +#endif + +#if HAS_EEPROM +static void +_ao_config_put(void) +{ + ao_storage_setup(); + ao_storage_erase(ao_storage_config); + ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config)); + ao_log_write_erase(0); + ao_storage_flush(); +} + +void +ao_config_put(void) +{ + ao_mutex_get(&ao_config_mutex); + _ao_config_put(); + ao_mutex_put(&ao_config_mutex); +} +#endif + +static void +_ao_config_get(void) +{ + if (ao_config_loaded) + return; +#if HAS_EEPROM + ao_storage_setup(); + ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config)); +#endif + if (ao_config.major != AO_CONFIG_MAJOR) { + ao_config.major = AO_CONFIG_MAJOR; + ao_config.minor = 0; + ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY; + ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL; + memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); + memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, + sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); + } + if (ao_config.minor < AO_CONFIG_MINOR) { + /* Fixups for minor version 1 */ + if (ao_config.minor < 1) + ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY; + /* Fixups for minor version 2 */ + if (ao_config.minor < 2) { + ao_config.accel_plus_g = 0; + ao_config.accel_minus_g = 0; + } + /* Fixups for minor version 3 */ + if (ao_config.minor < 3) + ao_config.radio_cal = ao_radio_cal; + /* Fixups for minor version 4 */ + if (ao_config.minor < 4) + ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; + /* Fixupes for minor version 5 */ + if (ao_config.minor < 5) + ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; + if (ao_config.minor < 6) + ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; + if (ao_config.minor < 7) + ao_config.radio_setting = ao_config.radio_cal; + if (ao_config.minor < 8) + ao_config.radio_enable = TRUE; + ao_config.minor = AO_CONFIG_MINOR; + ao_config_dirty = 1; + } + ao_config_loaded = 1; +} + +static void +_ao_config_edit_start(void) +{ + ao_mutex_get(&ao_config_mutex); + _ao_config_get(); +} + +static void +_ao_config_edit_finish(void) +{ + ao_config_dirty = 1; + ao_mutex_put(&ao_config_mutex); +} + +void +ao_config_get(void) +{ + _ao_config_edit_start(); + ao_mutex_put(&ao_config_mutex); +} + +void +ao_config_callsign_show(void) +{ + printf ("Callsign: \"%s\"\n", ao_config.callsign); +} + +void +ao_config_callsign_set(void) __reentrant +{ + uint8_t c; + static __xdata char callsign[AO_MAX_CALLSIGN + 1]; + + memset(callsign, '\0', sizeof callsign); + ao_cmd_white(); + c = 0; + while (ao_cmd_lex_c != '\n') { + if (c < AO_MAX_CALLSIGN) + callsign[c++] = ao_cmd_lex_c; + else + ao_cmd_status = ao_cmd_lex_error; + ao_cmd_lex(); + } + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + memcpy(&ao_config.callsign, &callsign, + AO_MAX_CALLSIGN + 1); + _ao_config_edit_finish(); +} + +void +ao_config_radio_channel_show(void) __reentrant +{ + printf("Radio channel: %d\n", + ao_config.radio_channel); +} + +void +ao_config_radio_channel_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_channel = ao_cmd_lex_i; + _ao_config_edit_finish(); + ao_radio_recv_abort(); +} + +#if HAS_ADC + +void +ao_config_main_deploy_show(void) __reentrant +{ + printf("Main deploy: %d meters\n", + ao_config.main_deploy); +} + +void +ao_config_main_deploy_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.main_deploy = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +#if HAS_ACCEL +void +ao_config_accel_calibrate_show(void) __reentrant +{ + printf("Accel cal +1g: %d -1g: %d\n", + ao_config.accel_plus_g, ao_config.accel_minus_g); +} + +#define ACCEL_CALIBRATE_SAMPLES 1024 +#define ACCEL_CALIBRATE_SHIFT 10 + +static int16_t +ao_config_accel_calibrate_auto(char *orientation) __reentrant +{ + uint16_t i; + int32_t accel_total; + uint8_t cal_adc_ring; + + printf("Orient antenna %s and press a key...", orientation); + flush(); + (void) getchar(); + puts("\r\n"); flush(); + puts("Calibrating..."); flush(); + i = ACCEL_CALIBRATE_SAMPLES; + accel_total = 0; + cal_adc_ring = ao_sample_adc; + while (i) { + ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); + while (i && cal_adc_ring != ao_sample_adc) { + accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel; + cal_adc_ring = ao_adc_ring_next(cal_adc_ring); + i--; + } + } + return accel_total >> ACCEL_CALIBRATE_SHIFT; +} + +void +ao_config_accel_calibrate_set(void) __reentrant +{ + int16_t up, down; + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + if (ao_cmd_lex_i == 0) { + up = ao_config_accel_calibrate_auto("up"); + down = ao_config_accel_calibrate_auto("down"); + } else { + up = ao_cmd_lex_i; + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + down = ao_cmd_lex_i; + } + if (up >= down) { + printf("Invalid accel: up (%d) down (%d)\n", + up, down); + return; + } + _ao_config_edit_start(); + ao_config.accel_plus_g = up; + ao_config.accel_minus_g = down; + _ao_config_edit_finish(); +} +#endif /* HAS_ACCEL */ + +void +ao_config_apogee_delay_show(void) __reentrant +{ + printf("Apogee delay: %d seconds\n", + ao_config.apogee_delay); +} + +void +ao_config_apogee_delay_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.apogee_delay = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +#endif /* HAS_ADC */ + +void +ao_config_radio_cal_show(void) __reentrant +{ + printf("Radio cal: %ld\n", ao_config.radio_cal); +} + +void +ao_config_radio_cal_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_setting = ao_config.radio_cal = ao_cmd_lex_u32; + _ao_config_edit_finish(); +} + +#if HAS_EEPROM +void +ao_config_log_show(void) __reentrant +{ + printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10)); +} + +void +ao_config_log_set(void) __reentrant +{ + uint16_t block = (uint16_t) (ao_storage_block >> 10); + uint16_t config = (uint16_t) (ao_storage_config >> 10); + + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + if (ao_log_present()) + printf("Storage must be empty before changing log size\n"); + else if (block > 1024 && (ao_cmd_lex_i & (block - 1))) + printf("Flight log size must be multiple of %d kB\n", block); + else if (ao_cmd_lex_i > config) + printf("Flight log max %d kB\n", config); + else { + _ao_config_edit_start(); + ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10; + _ao_config_edit_finish(); + } +} +#endif /* HAS_EEPROM */ + +#if HAS_IGNITE +void +ao_config_ignite_mode_show(void) __reentrant +{ + printf("Ignite mode: %d\n", ao_config.ignite_mode); +} + +void +ao_config_ignite_mode_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.ignite_mode = ao_cmd_lex_i; + _ao_config_edit_finish(); +} +#endif + +#if HAS_ACCEL +void +ao_config_pad_orientation_show(void) __reentrant +{ + printf("Pad orientation: %d\n", ao_config.pad_orientation); +} + +void +ao_config_pad_orientation_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_cmd_lex_i &= 1; + if (ao_config.pad_orientation != ao_cmd_lex_i) { + uint16_t t; + t = ao_config.accel_plus_g; + ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g; + ao_config.accel_minus_g = 0x7fff - t; + } + ao_config.pad_orientation = ao_cmd_lex_i; + _ao_config_edit_finish(); +} +#endif + +void +ao_config_radio_setting_show(void) __reentrant +{ + printf("Radio setting: %ld\n", ao_config.radio_setting); +} + +void +ao_config_radio_setting_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_setting = ao_cmd_lex_u32; + ao_config.radio_channel = 0; + _ao_config_edit_finish(); + ao_radio_recv_abort(); +} + +void +ao_config_radio_enable_show(void) __reentrant +{ + printf("Radio enable: %d\n", ao_config.radio_enable); +} + +void +ao_config_radio_enable_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_enable = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + +struct ao_config_var { + __code char *str; + void (*set)(void) __reentrant; + void (*show)(void) __reentrant; +}; + +static void +ao_config_help(void) __reentrant; + +static void +ao_config_show(void) __reentrant; + +static void +ao_config_write(void) __reentrant; + +__code struct ao_config_var ao_config_vars[] = { +#if HAS_ADC + { "m \0Main deploy (in meters)", + ao_config_main_deploy_set, ao_config_main_deploy_show, }, + { "d \0Apogee delay (in seconds)", + ao_config_apogee_delay_set, ao_config_apogee_delay_show }, +#endif /* HAS_ADC */ + { "r \0Radio channel (freq = 434.550 + chan * .1)", + ao_config_radio_channel_set, ao_config_radio_channel_show }, + { "c \0Callsign (8 char max)", + ao_config_callsign_set, ao_config_callsign_show }, + { "R \0Radio freq control (freq = 434.550 * setting/cal)", + ao_config_radio_setting_set, ao_config_radio_setting_show }, + { "e <0 disable, 1 enable>\0Enable telemetry and RDF", + ao_config_radio_enable_set, ao_config_radio_enable_show }, +#if HAS_ACCEL + { "a <+g> <-g>\0Accel calib (0 for auto)", + ao_config_accel_calibrate_set,ao_config_accel_calibrate_show }, +#endif /* HAS_ACCEL */ + { "f \0Radio calib (cal = rf/(xtal/2^16))", + ao_config_radio_cal_set, ao_config_radio_cal_show }, +#if HAS_EEPROM + { "l \0Flight log size in kB", + ao_config_log_set, ao_config_log_show }, +#endif +#if HAS_IGNITE + { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode", + ao_config_ignite_mode_set, ao_config_ignite_mode_show }, +#endif +#if HAS_ACCEL + { "o <0 antenna up, 1 antenna down>\0Set pad orientation", + ao_config_pad_orientation_set,ao_config_pad_orientation_show }, +#endif + { "s\0Show", + ao_config_show, 0 }, +#if HAS_EEPROM + { "w\0Write to eeprom", + ao_config_write, 0 }, +#endif + { "?\0Help", + ao_config_help, 0 }, + { 0, 0, 0 } +}; + +void +ao_config_set(void) +{ + char c; + uint8_t cmd; + void (*__xdata func)(void) __reentrant; + + ao_cmd_white(); + c = ao_cmd_lex_c; + ao_cmd_lex(); + func = 0; + for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) + if (ao_config_vars[cmd].str[0] == c) { + (*ao_config_vars[cmd].set)(); + return; + } + ao_cmd_status = ao_cmd_syntax_error; +} + +static void +ao_config_help(void) __reentrant +{ + uint8_t cmd; + for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) + printf("%-20s %s\n", + ao_config_vars[cmd].str, + ao_config_vars[cmd].str+1+strlen(ao_config_vars[cmd].str)); +} + +static void +ao_config_show(void) __reentrant +{ + uint8_t cmd; + printf("Config version: %d.%d\n", + ao_config.major, ao_config.minor); + for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) + if (ao_config_vars[cmd].show) + (*ao_config_vars[cmd].show)(); +} + +#if HAS_EEPROM +static void +ao_config_write(void) __reentrant +{ + uint8_t saved = 0; + ao_mutex_get(&ao_config_mutex); + if (ao_config_dirty) { + _ao_config_put(); + ao_config_dirty = 0; + saved = 1; + } + ao_mutex_put(&ao_config_mutex); + if (saved) + puts("Saved"); + else + puts("Nothing to save"); +} +#endif + +__code struct ao_cmds ao_config_cmds[] = { + { ao_config_set, "c \0Set config variable (? for help, s to show)" }, + { 0, NULL }, +}; + +void +ao_config_init(void) +{ + ao_cmd_register(&ao_config_cmds[0]); +} diff --git a/src/core/ao_convert.c b/src/core/ao_convert.c new file mode 100644 index 00000000..0969f107 --- /dev/null +++ b/src/core/ao_convert.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST) +#include "ao.h" +#endif + +static const int16_t altitude_table[] = { +#include "altitude.h" +}; + +#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS) +#define ALT_FRAC_MASK (ALT_FRAC_SCALE - 1) + +int16_t +ao_pres_to_altitude(int16_t pres) __reentrant +{ + uint8_t o; + int16_t part; + + if (pres < 0) + pres = 0; + o = pres >> ALT_FRAC_BITS; + part = pres & ALT_FRAC_MASK; + + return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) + + (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS; +} + +int16_t +ao_altitude_to_pres(int16_t alt) __reentrant +{ + int16_t span, sub_span; + uint8_t l, h, m; + int32_t pres; + + l = 0; + h = NALT - 1; + while ((h - l) != 1) { + m = (l + h) >> 1; + if (altitude_table[m] < alt) + h = m; + else + l = m; + } + span = altitude_table[l] - altitude_table[h]; + sub_span = altitude_table[l] - alt; + pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span; + if (pres > 32767) + pres = 32767; + if (pres < 0) + pres = 0; + return (int16_t) pres; +} + +int16_t +ao_temp_to_dC(int16_t temp) __reentrant +{ + int16_t ret; + + /* Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + * ≃ (value - 19791) * 1012 / 65536 + */ + ret = ((temp - 19791) * 1012L) >> 16; + return ret; +} diff --git a/src/core/ao_convert_test.c b/src/core/ao_convert_test.c new file mode 100644 index 00000000..e2c28b73 --- /dev/null +++ b/src/core/ao_convert_test.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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 +#define AO_CONVERT_TEST +#include "ao_host.h" +#include "ao_convert.c" + +#define STEP 1 + +static inline i_abs(int i) { return i < 0 ? -i : i; } + +main () +{ + int i; + int16_t p_to_a, p_to_a_to_p; + int16_t a_to_p, a_to_p_to_a; + int max_p_error = 0, max_p_error_p = -1; + int max_a_error = 0, max_a_error_a = -1; + int p_error; + int a_error; + int ret = 0; + + for (i = 0; i < 32767 + STEP; i += STEP) { + if (i > 32767) + i = 32767; + p_to_a = ao_pres_to_altitude(i); + p_to_a_to_p = ao_altitude_to_pres(p_to_a); + p_error = i_abs(p_to_a_to_p - i); + if (p_error > max_p_error) { + max_p_error = p_error; + max_p_error_p = i; + } +// printf ("pres %d alt %d pres %d\n", +// i, p_to_a, p_to_a_to_p); + } + for (i = -1578; i < 15835 + STEP; i += STEP) { + if (i > 15835) + i = 15835; + a_to_p = ao_altitude_to_pres(i); + a_to_p_to_a = ao_pres_to_altitude(a_to_p); + a_error = i_abs(a_to_p_to_a - i); + if (a_error > max_a_error) { + max_a_error = a_error; + max_a_error_a = i; + } +// printf ("alt %d pres %d alt %d\n", +// i, a_to_p, a_to_p_to_a); + } + if (max_p_error > 2) { + printf ("max p error %d at %d\n", max_p_error, + max_p_error_p); + ret++; + } + if (max_a_error > 1) { + printf ("max a error %d at %d\n", max_a_error, + max_a_error_a); + ret++; + } + return ret; +} diff --git a/src/core/ao_ee_fake.c b/src/core/ao_ee_fake.c new file mode 100644 index 00000000..b0c1d61e --- /dev/null +++ b/src/core/ao_ee_fake.c @@ -0,0 +1,37 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +/* + * For hardware without eeprom, the config code still + * wants to call these functions + */ +uint8_t +ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant +{ + (void) buf; + (void) len; + return 1; +} + +uint8_t +ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant +{ + memset(buf, '\0', len); + return 1; +} diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c new file mode 100644 index 00000000..85c1825b --- /dev/null +++ b/src/core/ao_flight.c @@ -0,0 +1,315 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef AO_FLIGHT_TEST +#include "ao.h" +#endif + +#ifndef HAS_ACCEL +#error Please define HAS_ACCEL +#endif + +#ifndef HAS_GPS +#error Please define HAS_GPS +#endif + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + +/* Main flight thread. */ + +__pdata enum ao_flight_state ao_flight_state; /* current flight state */ +__pdata uint16_t ao_launch_tick; /* time of launch detect */ + +/* + * track min/max data over a long interval to detect + * resting + */ +__pdata uint16_t ao_interval_end; +__pdata int16_t ao_interval_min_height; +__pdata int16_t ao_interval_max_height; +__pdata uint8_t ao_flight_force_idle; + +/* We also have a clock, which can be used to sanity check things in + * case of other failures + */ + +#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) + +/* Landing is detected by getting constant readings from both pressure and accelerometer + * for a fairly long time (AO_INTERVAL_TICKS) + */ +#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10) + +#define abs(a) ((a) < 0 ? -(a) : (a)) + +void +ao_flight(void) +{ + ao_sample_init(); + ao_flight_state = ao_flight_startup; + for (;;) { + + /* + * Process ADC samples, just looping + * until the sensors are calibrated. + */ + if (!ao_sample()) + continue; + + switch (ao_flight_state) { + case ao_flight_startup: + + /* Check to see what mode we should go to. + * - Invalid mode if accel cal appears to be out + * - pad mode if we're upright, + * - idle mode otherwise + */ +#if HAS_ACCEL + if (ao_config.accel_plus_g == 0 || + ao_config.accel_minus_g == 0 || + ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || + ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) + { + /* Detected an accel value outside -1.5g to 1.5g + * (or uncalibrated values), so we go into invalid mode + */ + ao_flight_state = ao_flight_invalid; + + } else +#endif + if (!ao_flight_force_idle +#if HAS_ACCEL + && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP +#endif + ) + { + /* Set pad mode - we can fly! */ + ao_flight_state = ao_flight_pad; +#if HAS_USB + /* Disable the USB controller in flight mode + * to save power + */ + ao_usb_disable(); +#endif + + /* Disable packet mode in pad state */ + ao_packet_slave_stop(); + + /* Turn on telemetry system */ + ao_rdf_set(1); + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); + + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + } else { + /* Set idle mode */ + ao_flight_state = ao_flight_idle; + + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + } + /* wakeup threads due to state change */ + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + + break; + case ao_flight_pad: + + /* pad to boost: + * + * barometer: > 20m vertical motion + * OR + * accelerometer: > 2g AND velocity > 5m/s + * + * The accelerometer should always detect motion before + * the barometer, but we use both to make sure this + * transition is detected. If the device + * doesn't have an accelerometer, then ignore the + * speed and acceleration as they are quite noisy + * on the pad. + */ + if (ao_height > AO_M_TO_HEIGHT(20) +#if HAS_ACCEL + || (ao_accel > AO_MSS_TO_ACCEL(20) && + ao_speed > AO_MS_TO_SPEED(5)) +#endif + ) + { + ao_flight_state = ao_flight_boost; + ao_launch_tick = ao_sample_tick; + + /* start logging data */ + ao_log_start(); + + /* Increase telemetry rate */ + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT); + + /* disable RDF beacon */ + ao_rdf_set(0); + +#if HAS_GPS + /* Record current GPS position by waking up GPS log tasks */ + ao_wakeup(&ao_gps_data); + ao_wakeup(&ao_gps_tracking_data); +#endif + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + case ao_flight_boost: + + /* boost to fast: + * + * accelerometer: start to fall at > 1/4 G + * OR + * time: boost for more than 15 seconds + * + * Detects motor burn out by the switch from acceleration to + * deceleration, or by waiting until the maximum burn duration + * (15 seconds) has past. + */ + if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || + (int16_t) (ao_sample_tick - ao_launch_tick) > BOOST_TICKS_MAX) + { +#if HAS_ACCEL + ao_flight_state = ao_flight_fast; +#else + ao_flight_state = ao_flight_coast; +#endif + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; +#if HAS_ACCEL + case ao_flight_fast: + /* + * This is essentially the same as coast, + * but the barometer is being ignored as + * it may be unreliable. + */ + if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) + { + ao_flight_state = ao_flight_coast; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; +#endif + case ao_flight_coast: + + /* apogee detect: coast to drogue deploy: + * + * speed: < 0 + * + * Also make sure the model altitude is tracking + * the measured altitude reasonably closely; otherwise + * we're probably transsonic. + */ + if (ao_speed < 0 +#if !HAS_ACCEL + && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) +#endif + ) + { + /* ignite the drogue charge */ + ao_ignite(ao_igniter_drogue); + + /* slow down the telemetry system */ + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); + + /* Turn the RDF beacon back on */ + ao_rdf_set(1); + + /* and enter drogue state */ + ao_flight_state = ao_flight_drogue; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + + break; + case ao_flight_drogue: + + /* drogue to main deploy: + * + * barometer: reach main deploy altitude + * + * Would like to use the accelerometer for this test, but + * the orientation of the flight computer is unknown after + * drogue deploy, so we ignore it. Could also detect + * high descent rate using the pressure sensor to + * recognize drogue deploy failure and eject the main + * at that point. Perhaps also use the drogue sense lines + * to notice continutity? + */ + if (ao_height <= ao_config.main_deploy) + { + ao_ignite(ao_igniter_main); + + /* + * Start recording min/max height + * to figure out when the rocket has landed + */ + + /* initialize interval values */ + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + + ao_interval_min_height = ao_interval_max_height = ao_avg_height; + + ao_flight_state = ao_flight_main; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + + /* fall through... */ + case ao_flight_main: + + /* main to land: + * + * barometer: altitude stable + */ + + if (ao_avg_height < ao_interval_min_height) + ao_interval_min_height = ao_avg_height; + if (ao_avg_height > ao_interval_max_height) + ao_interval_max_height = ao_avg_height; + + if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { + if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4)) + { + ao_flight_state = ao_flight_landed; + + /* turn off the ADC capture */ + ao_timer_set_adc_interval(0); + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + ao_interval_min_height = ao_interval_max_height = ao_avg_height; + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + } + break; + case ao_flight_landed: + break; + } + } +} + +static __xdata struct ao_task flight_task; + +void +ao_flight_init(void) +{ + ao_flight_state = ao_flight_startup; + ao_add_task(&flight_task, ao_flight, "flight"); +} diff --git a/src/core/ao_flight_nano.c b/src/core/ao_flight_nano.c new file mode 100644 index 00000000..2e332b12 --- /dev/null +++ b/src/core/ao_flight_nano.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +/* Main flight thread. */ + +__pdata enum ao_flight_state ao_flight_state; /* current flight state */ +__pdata uint16_t ao_launch_tick; /* time of launch detect */ + +/* + * track min/max data over a long interval to detect + * resting + */ +__pdata uint16_t ao_interval_end; +__pdata int16_t ao_interval_min_height; +__pdata int16_t ao_interval_max_height; + +__pdata uint8_t ao_flight_force_idle; + +/* Landing is detected by getting constant readings from both pressure and accelerometer + * for a fairly long time (AO_INTERVAL_TICKS) + */ +#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5) + +static void +ao_flight_nano(void) +{ + ao_sample_init(); + ao_flight_state = ao_flight_startup; + + for (;;) { + /* + * Process ADC samples, just looping + * until the sensors are calibrated. + */ + if (!ao_sample()) + continue; + + switch (ao_flight_state) { + case ao_flight_startup: + if (ao_flight_force_idle) { + /* Set idle mode */ + ao_flight_state = ao_flight_idle; + } else { + ao_flight_state = ao_flight_pad; + /* Disable packet mode in pad state */ + ao_packet_slave_stop(); + + /* Turn on telemetry system */ + ao_rdf_set(1); + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); + } + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + + /* wakeup threads due to state change */ + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + break; + case ao_flight_pad: + if (ao_height> AO_M_TO_HEIGHT(20)) { + ao_flight_state = ao_flight_drogue; + ao_launch_tick = ao_sample_tick; + + /* start logging data */ + ao_log_start(); + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + case ao_flight_drogue: + /* drogue/main to land: + * + * barometer: altitude stable + */ + + if (ao_height < ao_interval_min_height) + ao_interval_min_height = ao_height; + if (ao_height > ao_interval_max_height) + ao_interval_max_height = ao_height; + + if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { + if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5)) + { + ao_flight_state = ao_flight_landed; + + /* turn off the ADC capture */ + ao_timer_set_adc_interval(0); + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + ao_interval_min_height = ao_interval_max_height = ao_height; + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + } + break; + } + } +} + +static __xdata struct ao_task flight_task; + +void +ao_flight_nano_init(void) +{ + ao_flight_state = ao_flight_startup; + ao_add_task(&flight_task, ao_flight_nano, "flight"); +} diff --git a/src/core/ao_gps_print.c b/src/core/ao_gps_print.c new file mode 100644 index 00000000..fcdedd30 --- /dev/null +++ b/src/core/ao_gps_print.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef AO_GPS_TEST +#include "ao.h" +#endif +#include "ao_telem.h" + +void +ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant +{ + char state; + + if (gps_data->flags & AO_GPS_VALID) + state = AO_TELEM_GPS_STATE_LOCKED; + else if (gps_data->flags & AO_GPS_RUNNING) + state = AO_TELEM_GPS_STATE_UNLOCKED; + else + state = AO_TELEM_GPS_STATE_ERROR; + printf(AO_TELEM_GPS_STATE " %c " + AO_TELEM_GPS_NUM_SAT " %d ", + state, + (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT); + if (!(gps_data->flags & AO_GPS_VALID)) + return; + printf(AO_TELEM_GPS_LATITUDE " %ld " + AO_TELEM_GPS_LONGITUDE " %ld " + AO_TELEM_GPS_ALTITUDE " %d ", + gps_data->latitude, + gps_data->longitude, + gps_data->altitude); + + if (gps_data->flags & AO_GPS_DATE_VALID) + printf(AO_TELEM_GPS_YEAR " %d " + AO_TELEM_GPS_MONTH " %d " + AO_TELEM_GPS_DAY " %d ", + gps_data->year, + gps_data->month, + gps_data->day); + + printf(AO_TELEM_GPS_HOUR " %d " + AO_TELEM_GPS_MINUTE " %d " + AO_TELEM_GPS_SECOND " %d ", + gps_data->hour, + gps_data->minute, + gps_data->second); + + printf(AO_TELEM_GPS_HDOP " %d ", + gps_data->hdop * 2); + + if (gps_data->flags & AO_GPS_COURSE_VALID) { + printf(AO_TELEM_GPS_HERROR " %d " + AO_TELEM_GPS_VERROR " %d " + AO_TELEM_GPS_VERTICAL_SPEED " %d " + AO_TELEM_GPS_HORIZONTAL_SPEED " %d " + AO_TELEM_GPS_COURSE " %d ", + gps_data->h_error, + gps_data->v_error, + gps_data->climb_rate, + gps_data->ground_speed, + (int) gps_data->course * 2); + } +} + +void +ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant +{ + uint8_t c, n, v; + __xdata struct ao_gps_sat_orig *sat; + + n = gps_tracking_data->channels; + if (n == 0) + return; + + sat = gps_tracking_data->sats; + v = 0; + for (c = 0; c < n; c++) { + if (sat->svid) + v++; + sat++; + } + + printf (AO_TELEM_SAT_NUM " %d ", + v); + + sat = gps_tracking_data->sats; + v = 0; + for (c = 0; c < n; c++) { + if (sat->svid) { + printf (AO_TELEM_SAT_SVID "%d %d " + AO_TELEM_SAT_C_N_0 "%d %d ", + v, sat->svid, + v, sat->c_n_1); + v++; + } + sat++; + } +} diff --git a/src/core/ao_gps_report.c b/src/core/ao_gps_report.c new file mode 100644 index 00000000..e57f8744 --- /dev/null +++ b/src/core/ao_gps_report.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +void +ao_gps_report(void) +{ + static __xdata struct ao_log_record gps_log; + static __xdata struct ao_telemetry_location gps_data; + uint8_t date_reported = 0; + + for (;;) { + ao_sleep(&ao_gps_data); + ao_mutex_get(&ao_gps_mutex); + memcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data)); + ao_mutex_put(&ao_gps_mutex); + + if (!(gps_data.flags & AO_GPS_VALID)) + continue; + + gps_log.tick = ao_gps_tick; + gps_log.type = AO_LOG_GPS_TIME; + gps_log.u.gps_time.hour = gps_data.hour; + gps_log.u.gps_time.minute = gps_data.minute; + gps_log.u.gps_time.second = gps_data.second; + gps_log.u.gps_time.flags = gps_data.flags; + ao_log_data(&gps_log); + gps_log.type = AO_LOG_GPS_LAT; + gps_log.u.gps_latitude = gps_data.latitude; + ao_log_data(&gps_log); + gps_log.type = AO_LOG_GPS_LON; + gps_log.u.gps_longitude = gps_data.longitude; + ao_log_data(&gps_log); + gps_log.type = AO_LOG_GPS_ALT; + gps_log.u.gps_altitude.altitude = gps_data.altitude; + gps_log.u.gps_altitude.unused = 0xffff; + ao_log_data(&gps_log); + if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) { + gps_log.type = AO_LOG_GPS_DATE; + gps_log.u.gps_date.year = gps_data.year; + gps_log.u.gps_date.month = gps_data.month; + gps_log.u.gps_date.day = gps_data.day; + gps_log.u.gps_date.extra = 0; + date_reported = ao_log_data(&gps_log); + } + } +} + +void +ao_gps_tracking_report(void) +{ + static __xdata struct ao_log_record gps_log; + static __xdata struct ao_telemetry_satellite gps_tracking_data; + uint8_t c, n; + + for (;;) { + ao_sleep(&ao_gps_tracking_data); + ao_mutex_get(&ao_gps_mutex); + gps_log.tick = ao_gps_tick; + memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data)); + ao_mutex_put(&ao_gps_mutex); + + if (!(n = gps_tracking_data.channels)) + continue; + + gps_log.type = AO_LOG_GPS_SAT; + for (c = 0; c < n; c++) + if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid)) + { + gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1; + ao_log_data(&gps_log); + } + } +} + +__xdata struct ao_task ao_gps_report_task; +__xdata struct ao_task ao_gps_tracking_report_task; + +void +ao_gps_report_init(void) +{ + ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report"); + ao_add_task(&ao_gps_tracking_report_task, ao_gps_tracking_report, "gps_tracking_report"); +} diff --git a/src/core/ao_host.h b/src/core/ao_host.h new file mode 100644 index 00000000..65c25fe5 --- /dev/null +++ b/src/core/ao_host.h @@ -0,0 +1,127 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#include + +#define AO_ADC_RING 64 +#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) +#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) + +/* + * One set of samples read from the A/D converter + */ +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + int16_t accel; /* accelerometer */ + int16_t pres; /* pressure sensor */ + int16_t temp; /* temperature sensor */ + int16_t v_batt; /* battery voltage */ + int16_t sense_d; /* drogue continuity sense */ + int16_t sense_m; /* main continuity sense */ +}; + +#define __pdata +#define __data +#define __xdata +#define __code +#define __reentrant + +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 +}; + +struct ao_adc ao_adc_ring[AO_ADC_RING]; +uint8_t ao_adc_head; + +#define ao_led_on(l) +#define ao_led_off(l) +#define ao_timer_set_adc_interval(i) +#define ao_wakeup(wchan) ao_dump_state(wchan) +#define ao_cmd_register(c) +#define ao_usb_disable() +#define ao_telemetry_set_interval(x) +#define ao_delay(x) + +enum ao_igniter { + ao_igniter_drogue = 0, + ao_igniter_main = 1 +}; + +void +ao_ignite(enum ao_igniter igniter) +{ + printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main"); +} + +struct ao_task { + int dummy; +}; + +#define ao_add_task(t,f,n) + +#define ao_log_start() +#define ao_log_stop() + +#define AO_MS_TO_TICKS(ms) ((ms) / 10) +#define AO_SEC_TO_TICKS(s) ((s) * 100) + +#define AO_FLIGHT_TEST + +struct ao_adc ao_adc_static; + +FILE *emulator_in; + +void +ao_dump_state(void *wchan); + +void +ao_sleep(void *wchan); + +const char const * const ao_state_names[] = { + "startup", "idle", "pad", "boost", "fast", + "coast", "drogue", "main", "landed", "invalid" +}; + +struct ao_cmds { + void (*func)(void); + const char *help; +}; + + +struct ao_config { + uint16_t main_deploy; + int16_t accel_zero_g; +}; + +#define ao_config_get() + +struct ao_config ao_config = { 250, 16000 }; diff --git a/src/core/ao_kalman.c b/src/core/ao_kalman.c new file mode 100644 index 00000000..ee01949e --- /dev/null +++ b/src/core/ao_kalman.c @@ -0,0 +1,292 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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. + */ + +#ifndef AO_FLIGHT_TEST +#include "ao.h" +#endif + +#include "ao_kalman.h" + +static __pdata int32_t ao_k_height; +static __pdata int32_t ao_k_speed; +static __pdata int32_t ao_k_accel; + +#define AO_K_STEP_100 to_fix16(0.01) +#define AO_K_STEP_2_2_100 to_fix16(0.00005) + +#define AO_K_STEP_10 to_fix16(0.1) +#define AO_K_STEP_2_2_10 to_fix16(0.005) + +#define AO_K_STEP_1 to_fix16(1) +#define AO_K_STEP_2_2_1 to_fix16(0.5) + +__pdata int16_t ao_height; +__pdata int16_t ao_speed; +__pdata int16_t ao_accel; +__pdata int16_t ao_max_height; +static __pdata int32_t ao_avg_height_scaled; +__pdata int16_t ao_avg_height; + +__pdata int16_t ao_error_h; +__pdata int16_t ao_error_h_sq_avg; + +#if HAS_ACCEL +__pdata int16_t ao_error_a; +#endif + +static void +ao_kalman_predict(void) +{ +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) { + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 + + (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1; + + return; + } + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 + + (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10; + + return; + } + if (ao_flight_debug) { + printf ("predict speed %g + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0, + (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0)); + } +#endif + ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 + + (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4; + ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100; +} + +static void +ao_kalman_err_height(void) +{ + int16_t e; + int16_t height_distrust; +#if HAS_ACCEL + int16_t speed_distrust; +#endif + + ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16); + + e = ao_error_h; + if (e < 0) + e = -e; + if (e > 127) + e = 127; +#if HAS_ACCEL + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2; + ao_error_h_sq_avg += (e * e) >> 2; +#else + ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4; + ao_error_h_sq_avg += (e * e) >> 4; +#endif + + if (ao_flight_state >= ao_flight_drogue) + return; + height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT; +#if HAS_ACCEL + /* speed is stored * 16, but we need to ramp between 200 and 328, so + * we want to multiply by 2. The result is a shift by 3. + */ + speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1); + if (speed_distrust <= 0) + speed_distrust = 0; + else if (speed_distrust > height_distrust) + height_distrust = speed_distrust; +#endif + if (height_distrust > 0) { +#ifdef AO_FLIGHT_TEST + int old_ao_error_h = ao_error_h; +#endif + if (height_distrust > 0x100) + height_distrust = 0x100; + ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8); +#ifdef AO_FLIGHT_TEST + if (ao_flight_debug) { + printf("over height %g over speed %g distrust: %g height: error %d -> %d\n", + (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT), + (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0, + height_distrust / 256.0, + old_ao_error_h, ao_error_h); + } +#endif + } +} + +static void +ao_kalman_correct_baro(void) +{ + ao_kalman_err_height(); +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) { + ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_1 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_1 * ao_error_h; + return; + } + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h; + return; + } +#endif + ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h; + ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h; + ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h; +} + +#if HAS_ACCEL + +static void +ao_kalman_err_accel(void) +{ + int32_t accel; + + accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale; + + /* Can't use ao_accel here as it is the pre-prediction value still */ + ao_error_a = (accel - ao_k_accel) >> 16; +} + +static void +ao_kalman_correct_both(void) +{ + ao_kalman_err_height(); + ao_kalman_err_accel(); + +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) { + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_1 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_1 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_1 * ao_error_h + + (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0)); + } + ao_k_height += + (int32_t) AO_BOTH_K00_1 * ao_error_h + + (int32_t) AO_BOTH_K01_1 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_1 * ao_error_h + + (int32_t) AO_BOTH_K11_1 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_1 * ao_error_h + + (int32_t) AO_BOTH_K21_1 * ao_error_a; + return; + } + if (ao_sample_tick - ao_sample_prev_tick > 5) { + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_10 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_10 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_10 * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0)); + } + ao_k_height += + (int32_t) AO_BOTH_K00_10 * ao_error_h + + (int32_t) AO_BOTH_K01_10 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_10 * ao_error_h + + (int32_t) AO_BOTH_K11_10 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_10 * ao_error_h + + (int32_t) AO_BOTH_K21_10 * ao_error_a; + return; + } + if (ao_flight_debug) { + printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n", + ao_k_speed / (65536.0 * 16.0), + (double) ao_error_h, AO_BOTH_K10_100 / 65536.0, + (double) ao_error_a, AO_BOTH_K11_100 / 65536.0, + (ao_k_speed + + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0)); + } +#endif + ao_k_height += + (int32_t) AO_BOTH_K00_100 * ao_error_h + + (int32_t) AO_BOTH_K01_100 * ao_error_a; + ao_k_speed += + (int32_t) AO_BOTH_K10_100 * ao_error_h + + (int32_t) AO_BOTH_K11_100 * ao_error_a; + ao_k_accel += + (int32_t) AO_BOTH_K20_100 * ao_error_h + + (int32_t) AO_BOTH_K21_100 * ao_error_a; +} + +#ifdef FORCE_ACCEL +static void +ao_kalman_correct_accel(void) +{ + ao_kalman_err_accel(); + + if (ao_sample_tick - ao_sample_prev_tick > 5) { + ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a; + return; + } + ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a; + ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a; + ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a; +} +#endif +#endif /* HAS_ACCEL */ + +void +ao_kalman(void) +{ + ao_kalman_predict(); +#if HAS_ACCEL + if (ao_flight_state <= ao_flight_coast) { +#ifdef FORCE_ACCEL + ao_kalman_correct_accel(); +#else + ao_kalman_correct_both(); +#endif + } else +#endif + ao_kalman_correct_baro(); + ao_height = from_fix(ao_k_height); + ao_speed = from_fix(ao_k_speed); + ao_accel = from_fix(ao_k_accel); + if (ao_height > ao_max_height) + ao_max_height = ao_height; + ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height; +#ifdef AO_FLIGHT_TEST + if (ao_sample_tick - ao_sample_prev_tick > 50) + ao_avg_height = (ao_avg_height_scaled + 1) >> 1; + else if (ao_sample_tick - ao_sample_prev_tick > 5) + ao_avg_height = (ao_avg_height_scaled + 7) >> 4; + else +#endif + ao_avg_height = (ao_avg_height_scaled + 63) >> 7; +#ifdef AO_FLIGHT_TEST + ao_sample_prev_tick = ao_sample_tick; +#endif +} diff --git a/src/core/ao_log.c b/src/core/ao_log.c new file mode 100644 index 00000000..6d3ad535 --- /dev/null +++ b/src/core/ao_log.c @@ -0,0 +1,284 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +__pdata uint32_t ao_log_current_pos; +__pdata uint32_t ao_log_end_pos; +__pdata uint32_t ao_log_start_pos; +__xdata uint8_t ao_log_running; +__pdata enum flight_state ao_log_state; +__xdata uint16_t ao_flight_number; + +__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL; + +void +ao_log_flush(void) +{ + ao_storage_flush(); +} + +/* + * When erasing a flight log, make sure the config block + * has an up-to-date version of the current flight number + */ + +struct ao_log_erase { + uint8_t unused; + uint16_t flight; +}; + +static __xdata struct ao_log_erase erase; + +#define LOG_MAX_ERASE 16 + +static uint32_t +ao_log_erase_pos(uint8_t i) +{ + return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG; +} + +void +ao_log_write_erase(uint8_t pos) +{ + erase.unused = 0x00; + erase.flight = ao_flight_number; + ao_storage_write(ao_log_erase_pos(pos), &erase, sizeof (erase)); + ao_storage_flush(); +} + +static void +ao_log_read_erase(uint8_t pos) +{ + ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase)); +} + + +static void +ao_log_erase_mark(void) +{ + uint8_t i; + + for (i = 0; i < LOG_MAX_ERASE; i++) { + ao_log_read_erase(i); + if (erase.unused == 0 && erase.flight == ao_flight_number) + return; + if (erase.unused == 0xff) { + ao_log_write_erase(i); + return; + } + } + ao_config_put(); +} + +static uint8_t +ao_log_slots() +{ + return (uint8_t) (ao_storage_config / ao_config.flight_log_max); +} + +uint32_t +ao_log_pos(uint8_t slot) +{ + return ((slot) * ao_config.flight_log_max); +} + +static uint16_t +ao_log_max_flight(void) +{ + uint8_t log_slot; + uint8_t log_slots; + uint16_t log_flight; + uint16_t max_flight = 0; + + /* Scan the log space looking for the biggest flight number */ + log_slots = ao_log_slots(); + for (log_slot = 0; log_slot < log_slots; log_slot++) { + log_flight = ao_log_flight(log_slot); + if (!log_flight) + continue; + if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0) + max_flight = log_flight; + } + return max_flight; +} + +void +ao_log_scan(void) __reentrant +{ + uint8_t log_slot; + uint8_t log_slots; + uint8_t log_want; + + ao_config_get(); + + ao_flight_number = ao_log_max_flight(); + if (ao_flight_number) + if (++ao_flight_number == 0) + ao_flight_number = 1; + + /* Now look through the log of flight numbers from erase operations and + * see if the last one is bigger than what we found above + */ + for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) { + ao_log_read_erase(log_slot); + if (erase.unused == 0) { + if (ao_flight_number == 0 || + (int16_t) (erase.flight - ao_flight_number) > 0) + ao_flight_number = erase.flight; + break; + } + } + if (ao_flight_number == 0) + ao_flight_number = 1; + + /* With a flight number in hand, find a place to write a new log, + * use the target flight number to index the available log slots so + * that we write logs to each spot about the same number of times. + */ + + /* Find a log slot for the next flight, if available */ + ao_log_current_pos = ao_log_end_pos = 0; + log_slots = ao_log_slots(); + log_want = (ao_flight_number - 1) % log_slots; + log_slot = log_want; + do { + if (ao_log_flight(log_slot) == 0) { + ao_log_current_pos = ao_log_pos(log_slot); + ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; + break; + } + if (++log_slot >= log_slots) + log_slot = 0; + } while (log_slot != log_want); + + ao_wakeup(&ao_flight_number); +} + +void +ao_log_start(void) +{ + /* start logging */ + ao_log_running = 1; + ao_wakeup(&ao_log_running); +} + +void +ao_log_stop(void) +{ + ao_log_running = 0; + ao_log_flush(); +} + +uint8_t +ao_log_present(void) +{ + return ao_log_max_flight() != 0; +} + +uint8_t +ao_log_full(void) +{ + return ao_log_current_pos == ao_log_end_pos; +} + +static __xdata struct ao_task ao_log_task; + +void +ao_log_list(void) __reentrant +{ + uint8_t slot; + uint8_t slots; + uint16_t flight; + + slots = ao_log_slots(); + for (slot = 0; slot < slots; slot++) + { + flight = ao_log_flight(slot); + if (flight) + printf ("flight %d start %x end %x\n", + flight, + (uint16_t) (ao_log_pos(slot) >> 8), + (uint16_t) (ao_log_pos(slot+1) >> 8)); + } + printf ("done\n"); +} + +void +ao_log_delete(void) __reentrant +{ + uint8_t slot; + uint8_t slots; + + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + + slots = ao_log_slots(); + /* Look for the flight log matching the requested flight */ + if (ao_cmd_lex_i) { + for (slot = 0; slot < slots; slot++) { + if (ao_log_flight(slot) == ao_cmd_lex_i) { + ao_log_erase_mark(); + ao_log_current_pos = ao_log_pos(slot); + ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max; + while (ao_log_current_pos < ao_log_end_pos) { + uint8_t i; + static __xdata uint8_t b; + + /* + * Check to see if we've reached the end of + * the used memory to avoid re-erasing the same + * memory over and over again + */ + for (i = 0; i < 16; i++) { + if (ao_storage_read(ao_log_current_pos + i, &b, 1)) + if (b != 0xff) + break; + } + if (i == 16) + break; + ao_storage_erase(ao_log_current_pos); + ao_log_current_pos += ao_storage_block; + } + puts("Erased"); + return; + } + } + } + printf("No such flight: %d\n", ao_cmd_lex_i); +} + +__code struct ao_cmds ao_log_cmds[] = { + { ao_log_list, "l\0List flight logs" }, + { ao_log_delete, "d \0Delete flight" }, + { 0, NULL }, +}; + +void +ao_log_init(void) +{ + ao_log_running = 0; + + /* For now, just log the flight starting at the begining of eeprom */ + ao_log_state = ao_flight_invalid; + + ao_cmd_register(&ao_log_cmds[0]); + + /* Create a task to log events to eeprom */ + ao_add_task(&ao_log_task, ao_log, "log"); +} diff --git a/src/core/ao_log_big.c b/src/core/ao_log_big.c new file mode 100644 index 00000000..74d94c4b --- /dev/null +++ b/src/core/ao_log_big.c @@ -0,0 +1,158 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +static __xdata uint8_t ao_log_mutex; +static __xdata struct ao_log_record log; + +static uint8_t +ao_log_csum(__xdata uint8_t *b) __reentrant +{ + uint8_t sum = 0x5a; + uint8_t i; + + for (i = 0; i < sizeof (struct ao_log_record); i++) + sum += *b++; + return -sum; +} + +uint8_t +ao_log_data(__xdata struct ao_log_record *log) __reentrant +{ + uint8_t wrote = 0; + /* set checksum */ + log->csum = 0; + log->csum = ao_log_csum((__xdata uint8_t *) log); + ao_mutex_get(&ao_log_mutex); { + if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) + ao_log_stop(); + if (ao_log_running) { + wrote = 1; + ao_storage_write(ao_log_current_pos, + log, + sizeof (struct ao_log_record)); + ao_log_current_pos += sizeof (struct ao_log_record); + } + } ao_mutex_put(&ao_log_mutex); + return wrote; +} + +static uint8_t +ao_log_dump_check_data(void) +{ + if (ao_log_csum((uint8_t *) &log) != 0) + return 0; + return 1; +} + +static __data uint8_t ao_log_adc_pos; + +/* a hack to make sure that ao_log_records fill the eeprom block in even units */ +typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ; + +#define AO_SENSOR_INTERVAL_ASCENT 1 +#define AO_SENSOR_INTERVAL_DESCENT 10 +#define AO_OTHER_INTERVAL 32 + +void +ao_log(void) +{ + __pdata uint16_t next_sensor, next_other; + + ao_storage_setup(); + + ao_log_scan(); + + while (!ao_log_running) + ao_sleep(&ao_log_running); + + log.type = AO_LOG_FLIGHT; + log.tick = ao_sample_tick; +#if HAS_ACCEL + log.u.flight.ground_accel = ao_ground_accel; +#endif + log.u.flight.flight = ao_flight_number; + ao_log_data(&log); + + /* Write the whole contents of the ring to the log + * when starting up. + */ + ao_log_adc_pos = ao_adc_ring_next(ao_sample_adc); + next_other = next_sensor = ao_adc_ring[ao_log_adc_pos].tick; + ao_log_state = ao_flight_startup; + for (;;) { + /* Write samples to EEPROM */ + while (ao_log_adc_pos != ao_sample_adc) { + log.tick = ao_adc_ring[ao_log_adc_pos].tick; + if ((int16_t) (log.tick - next_sensor) >= 0) { + log.type = AO_LOG_SENSOR; + log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel; + log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres; + ao_log_data(&log); + if (ao_log_state <= ao_flight_coast) + next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT; + else + next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT; + } + if ((int16_t) (log.tick - next_other) >= 0) { + log.type = AO_LOG_TEMP_VOLT; + log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp; + log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt; + ao_log_data(&log); + log.type = AO_LOG_DEPLOY; + log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d; + log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m; + ao_log_data(&log); + next_other = log.tick + AO_OTHER_INTERVAL; + } + ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos); + } + /* Write state change to EEPROM */ + if (ao_flight_state != ao_log_state) { + ao_log_state = ao_flight_state; + log.type = AO_LOG_STATE; + log.tick = ao_sample_tick; + log.u.state.state = ao_log_state; + log.u.state.reason = 0; + ao_log_data(&log); + + if (ao_log_state == ao_flight_landed) + ao_log_stop(); + } + + /* Wait for a while */ + ao_delay(AO_MS_TO_TICKS(100)); + + /* Stop logging when told to */ + while (!ao_log_running) + ao_sleep(&ao_log_running); + } +} + +uint16_t +ao_log_flight(uint8_t slot) +{ + if (!ao_storage_read(ao_log_pos(slot), + &log, + sizeof (struct ao_log_record))) + return 0; + + if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) + return log.u.flight.flight; + return 0; +} diff --git a/src/core/ao_log_telem.c b/src/core/ao_log_telem.c new file mode 100644 index 00000000..1b472efe --- /dev/null +++ b/src/core/ao_log_telem.c @@ -0,0 +1,30 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +void +ao_log_write_erase(uint8_t pos) +{ + (void) pos; +} + +uint8_t +ao_log_present(void) +{ + return 0; +} diff --git a/src/core/ao_log_tiny.c b/src/core/ao_log_tiny.c new file mode 100644 index 00000000..d5a3b99f --- /dev/null +++ b/src/core/ao_log_tiny.c @@ -0,0 +1,161 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +static __data uint16_t ao_log_tiny_interval; + +#define AO_LOG_TINY_INTERVAL_DEFAULT AO_MS_TO_TICKS(1000) +#if USE_FAST_ASCENT_LOG +#define AO_LOG_TINY_INTERVAL_ASCENT AO_MS_TO_TICKS(100) +#define AO_PAD_RING 8 +#else +#define AO_LOG_TINY_INTERVAL_ASCENT AO_LOG_TINY_INTERVAL_DEFAULT +#define AO_PAD_RING 2 +#endif + +__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY; + +void +ao_log_tiny_set_interval(uint16_t ticks) +{ + ao_log_tiny_interval = ticks; +} + + +static void ao_log_tiny_data(uint16_t d) +{ + if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) + ao_log_stop(); + if (ao_log_running) { + ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2); + ao_log_current_pos += 2; + } +} + +static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING]; +static __pdata uint8_t ao_log_pad_ring_pos; + +#define ao_pad_ring_next(n) (((n) + 1) & (AO_PAD_RING - 1)) + +static void ao_log_tiny_queue(uint16_t d) +{ + ao_log_pad_ring[ao_log_pad_ring_pos] = d; + ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos); +} + +static void ao_log_tiny_start(void) +{ + uint8_t p; + uint16_t d; + + ao_log_tiny_data(ao_flight_number); + ao_log_tiny_data(ao_ground_pres); + p = ao_log_pad_ring_pos; + do { + d = ao_log_pad_ring[p]; + /* + * ignore unwritten slots + */ + if (d) + ao_log_tiny_data(d); + p = ao_pad_ring_next(p); + } while (p != ao_log_pad_ring_pos); +} + +void +ao_log(void) +{ + uint16_t last_time; + uint16_t now; + enum ao_flight_state ao_log_tiny_state; + int32_t sum; + int16_t count; + uint8_t ao_log_adc; + uint8_t ao_log_started = 0; + + ao_storage_setup(); + + ao_log_scan(); + + ao_log_tiny_state = ao_flight_invalid; + ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; + sum = 0; + count = 0; + ao_log_adc = ao_sample_adc; + last_time = ao_time(); + for (;;) { + + /* + * Add in pending sample data + */ + ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); + while (ao_log_adc != ao_sample_adc) { + sum += ao_adc_ring[ao_log_adc].pres; + count++; + ao_log_adc = ao_adc_ring_next(ao_log_adc); + } + if (ao_log_running) { + if (!ao_log_started) { + ao_log_tiny_start(); + ao_log_started = 1; + } + if (ao_flight_state != ao_log_tiny_state) { + ao_log_tiny_data(ao_flight_state | 0x8000); + ao_log_tiny_state = ao_flight_state; + ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT; +#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT + if (ao_log_tiny_state <= ao_flight_coast) + ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT; +#endif + if (ao_log_tiny_state == ao_flight_landed) + ao_log_stop(); + } + } + + /* Stop logging when told to */ + if (!ao_log_running && ao_log_started) + ao_exit(); + + /* + * Write out the sample when finished + */ + now = ao_time(); + if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) { + count = sum / count; + if (ao_log_started) + ao_log_tiny_data(count); + else + ao_log_tiny_queue(count); + sum = 0; + count = 0; + last_time = now; + } + } +} + +uint16_t +ao_log_flight(uint8_t slot) +{ + static __xdata uint16_t flight; + + (void) slot; + ao_storage_read(0, &flight, 2); + if (flight == 0xffff) + flight = 0; + return flight; +} diff --git a/src/core/ao_monitor.c b/src/core/ao_monitor.c new file mode 100644 index 00000000..69eb58e8 --- /dev/null +++ b/src/core/ao_monitor.c @@ -0,0 +1,277 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_telem.h" + +#if !HAS_MONITOR +#error Must define HAS_MONITOR to 1 +#endif + +__xdata uint8_t ao_monitoring; +__pdata uint8_t ao_monitor_led; + +#define AO_MONITOR_RING 8 + +__xdata union ao_monitor { + struct ao_telemetry_raw_recv raw; + struct ao_telemetry_orig_recv orig; + struct ao_telemetry_tiny_recv tiny; +} ao_monitor_ring[AO_MONITOR_RING]; + +#define ao_monitor_ring_next(n) (((n) + 1) & (AO_MONITOR_RING - 1)) + +__data uint8_t ao_monitor_head; + +void +ao_monitor_get(void) +{ + uint8_t size; + + for (;;) { + switch (ao_monitoring) { + case 0: + ao_sleep(&ao_monitoring); + continue; + case AO_MONITORING_ORIG: + size = sizeof (struct ao_telemetry_orig_recv); + break; + case AO_MONITORING_TINY: + size = sizeof (struct ao_telemetry_tiny_recv); + break; + default: + if (ao_monitoring > AO_MAX_TELEMETRY) + ao_monitoring = AO_MAX_TELEMETRY; + size = ao_monitoring; + break; + } + if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2)) + continue; + ao_monitor_head = ao_monitor_ring_next(ao_monitor_head); + ao_wakeup(DATA_TO_XDATA(&ao_monitor_head)); + ao_led_toggle(ao_monitor_led); + } +} + +void +ao_monitor_put(void) +{ + __xdata char callsign[AO_MAX_CALLSIGN+1]; + + uint8_t ao_monitor_tail; + uint8_t state; + uint8_t sum, byte; + int16_t rssi; + __xdata union ao_monitor *m; + +#define recv_raw ((m->raw)) +#define recv_orig ((m->orig)) +#define recv_tiny ((m->tiny)) + + ao_monitor_tail = ao_monitor_head; + for (;;) { + while (ao_monitor_tail == ao_monitor_head) + ao_sleep(DATA_TO_XDATA(&ao_monitor_head)); + m = &ao_monitor_ring[ao_monitor_tail]; + ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail); + switch (ao_monitoring) { + case AO_MONITORING_ORIG: + state = recv_orig.telemetry_orig.flight_state; + + /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ + rssi = (int16_t) (recv_orig.rssi >> 1) - 74; + memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN); + if (state > ao_flight_invalid) + state = ao_flight_invalid; + if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) { + + /* General header fields */ + printf(AO_TELEM_VERSION " %d " + AO_TELEM_CALL " %s " + AO_TELEM_SERIAL " %d " + AO_TELEM_FLIGHT " %d " + AO_TELEM_RSSI " %d " + AO_TELEM_STATE " %s " + AO_TELEM_TICK " %d ", + AO_TELEMETRY_VERSION, + callsign, + recv_orig.telemetry_orig.serial, + recv_orig.telemetry_orig.flight, + rssi, + ao_state_names[state], + recv_orig.telemetry_orig.adc.tick); + + /* Raw sensor values */ + printf(AO_TELEM_RAW_ACCEL " %d " + AO_TELEM_RAW_BARO " %d " + AO_TELEM_RAW_THERMO " %d " + AO_TELEM_RAW_BATT " %d " + AO_TELEM_RAW_DROGUE " %d " + AO_TELEM_RAW_MAIN " %d ", + recv_orig.telemetry_orig.adc.accel, + recv_orig.telemetry_orig.adc.pres, + recv_orig.telemetry_orig.adc.temp, + recv_orig.telemetry_orig.adc.v_batt, + recv_orig.telemetry_orig.adc.sense_d, + recv_orig.telemetry_orig.adc.sense_m); + + /* Sensor calibration values */ + printf(AO_TELEM_CAL_ACCEL_GROUND " %d " + AO_TELEM_CAL_BARO_GROUND " %d " + AO_TELEM_CAL_ACCEL_PLUS " %d " + AO_TELEM_CAL_ACCEL_MINUS " %d ", + recv_orig.telemetry_orig.ground_accel, + recv_orig.telemetry_orig.ground_pres, + recv_orig.telemetry_orig.accel_plus_g, + recv_orig.telemetry_orig.accel_minus_g); + + if (recv_orig.telemetry_orig.u.k.unused == 0x8000) { + /* Kalman state values */ + printf(AO_TELEM_KALMAN_HEIGHT " %d " + AO_TELEM_KALMAN_SPEED " %d " + AO_TELEM_KALMAN_ACCEL " %d ", + recv_orig.telemetry_orig.height, + recv_orig.telemetry_orig.u.k.speed, + recv_orig.telemetry_orig.accel); + } else { + /* Ad-hoc flight values */ + printf(AO_TELEM_ADHOC_ACCEL " %d " + AO_TELEM_ADHOC_SPEED " %ld " + AO_TELEM_ADHOC_BARO " %d ", + recv_orig.telemetry_orig.accel, + recv_orig.telemetry_orig.u.flight_vel, + recv_orig.telemetry_orig.height); + } + ao_gps_print(&recv_orig.telemetry_orig.gps); + ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking); + putchar('\n'); + ao_rssi_set(rssi); + } else { + printf("CRC INVALID RSSI %3d\n", rssi); + } + break; + case AO_MONITORING_TINY: + state = recv_tiny.telemetry_tiny.flight_state; + + /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ + rssi = (int16_t) (recv_tiny.rssi >> 1) - 74; + memcpy(callsign, recv_tiny.telemetry_tiny.callsign, AO_MAX_CALLSIGN); + if (state > ao_flight_invalid) + state = ao_flight_invalid; + if (recv_tiny.status & PKT_APPEND_STATUS_1_CRC_OK) { + /* General header fields */ + printf(AO_TELEM_VERSION " %d " + AO_TELEM_CALL " %s " + AO_TELEM_SERIAL " %d " + AO_TELEM_FLIGHT " %d " + AO_TELEM_RSSI " %d " + AO_TELEM_STATE " %s " + AO_TELEM_TICK " %d ", + AO_TELEMETRY_VERSION, + callsign, + recv_tiny.telemetry_tiny.serial, + recv_tiny.telemetry_tiny.flight, + rssi, + ao_state_names[state], + recv_tiny.telemetry_tiny.adc.tick); + + /* Raw sensor values */ + printf(AO_TELEM_RAW_BARO " %d " + AO_TELEM_RAW_THERMO " %d " + AO_TELEM_RAW_BATT " %d " + AO_TELEM_RAW_DROGUE " %d " + AO_TELEM_RAW_MAIN " %d ", + recv_tiny.telemetry_tiny.adc.pres, + recv_tiny.telemetry_tiny.adc.temp, + recv_tiny.telemetry_tiny.adc.v_batt, + recv_tiny.telemetry_tiny.adc.sense_d, + recv_tiny.telemetry_tiny.adc.sense_m); + + /* Sensor calibration values */ + printf(AO_TELEM_CAL_BARO_GROUND " %d ", + recv_tiny.telemetry_tiny.ground_pres); + +#if 1 + /* Kalman state values */ + printf(AO_TELEM_KALMAN_HEIGHT " %d " + AO_TELEM_KALMAN_SPEED " %d " + AO_TELEM_KALMAN_ACCEL " %d\n", + recv_tiny.telemetry_tiny.height, + recv_tiny.telemetry_tiny.speed, + recv_tiny.telemetry_tiny.accel); +#else + /* Ad-hoc flight values */ + printf(AO_TELEM_ADHOC_ACCEL " %d " + AO_TELEM_ADHOC_SPEED " %ld " + AO_TELEM_ADHOC_BARO " %d\n", + recv_tiny.telemetry_tiny.flight_accel, + recv_tiny.telemetry_tiny.flight_vel, + recv_tiny.telemetry_tiny.flight_pres); +#endif + ao_rssi_set(rssi); + } else { + printf("CRC INVALID RSSI %3d\n", rssi); + } + break; + default: + printf ("TELEM %02x", ao_monitoring + 2); + sum = 0x5a; + for (state = 0; state < ao_monitoring + 2; state++) { + byte = recv_raw.packet[state]; + sum += byte; + printf("%02x", byte); + } + printf("%02x\n", sum); + break; + } + ao_usb_flush(); + } +} + +__xdata struct ao_task ao_monitor_get_task; +__xdata struct ao_task ao_monitor_put_task; + +void +ao_set_monitor(uint8_t monitoring) +{ + if (ao_monitoring) + ao_radio_recv_abort(); + ao_monitoring = monitoring; + ao_wakeup(&ao_monitoring); +} + +static void +set_monitor(void) +{ + ao_cmd_hex(); + ao_set_monitor(ao_cmd_lex_i); +} + +__code struct ao_cmds ao_monitor_cmds[] = { + { set_monitor, "m <0 off, 1 full, 2 tiny>\0Enable/disable radio monitoring" }, + { 0, NULL }, +}; + +void +ao_monitor_init(uint8_t monitor_led, uint8_t monitoring) __reentrant +{ + ao_monitor_led = monitor_led; + ao_monitoring = monitoring; + ao_cmd_register(&ao_monitor_cmds[0]); + ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get"); + ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put"); +} diff --git a/src/core/ao_mutex.c b/src/core/ao_mutex.c new file mode 100644 index 00000000..c82a7d57 --- /dev/null +++ b/src/core/ao_mutex.c @@ -0,0 +1,41 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +void +ao_mutex_get(__xdata uint8_t *mutex) __reentrant +{ + if (*mutex == ao_cur_task->task_id) + ao_panic(AO_PANIC_MUTEX); + __critical { + while (*mutex) + ao_sleep(mutex); + *mutex = ao_cur_task->task_id; + } +} + +void +ao_mutex_put(__xdata uint8_t *mutex) __reentrant +{ + if (*mutex != ao_cur_task->task_id) + ao_panic(AO_PANIC_MUTEX); + __critical { + *mutex = 0; + ao_wakeup(mutex); + } +} diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c new file mode 100644 index 00000000..fdada201 --- /dev/null +++ b/src/core/ao_panic.c @@ -0,0 +1,66 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +#ifndef HAS_BEEP +#error Please define HAS_BEEP +#endif + +#if !HAS_BEEP +#define ao_beep(x) +#endif + +static void +ao_panic_delay(uint8_t n) +{ + uint8_t i = 0, j = 0; + + while (n--) + while (--j) + while (--i) + _asm nop _endasm; +} + +void +ao_panic(uint8_t reason) +{ + uint8_t n; + + __critical for (;;) { + ao_panic_delay(20); + for (n = 0; n < 5; n++) { + ao_led_on(AO_LED_RED); + ao_beep(AO_BEEP_HIGH); + ao_panic_delay(1); + ao_led_off(AO_LED_RED); + ao_beep(AO_BEEP_LOW); + ao_panic_delay(1); + } + ao_beep(AO_BEEP_OFF); + ao_panic_delay(2); +#pragma disable_warning 126 + for (n = 0; n < reason; n++) { + ao_led_on(AO_LED_RED); + ao_beep(AO_BEEP_MID); + ao_panic_delay(10); + ao_led_off(AO_LED_RED); + ao_beep(AO_BEEP_OFF); + ao_panic_delay(10); + } + } +} diff --git a/src/core/ao_pins.h b/src/core/ao_pins.h new file mode 100644 index 00000000..e1f5459f --- /dev/null +++ b/src/core/ao_pins.h @@ -0,0 +1,408 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#if defined(TELEMETRUM_V_1_0) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define HAS_ADC 1 + #define USE_SERIAL_STDIN 0 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 0 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEMETRUM_V_1_1) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 1 + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ + #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEDONGLE_V_0_2) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 1 + #define AO_LED_GREEN 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEMINI_V_1_0) + #define HAS_FLIGHT 1 + #define HAS_USB 0 + #define HAS_BEEP 0 + #define HAS_GPS 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 1 + #define HAS_DBG 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 1 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + #define USE_FAST_ASCENT_LOG 1 + + #define AO_LED_GREEN 1 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL 0 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELENANO_V_0_1) + #define HAS_FLIGHT 1 + #define HAS_USB 0 + #define HAS_BEEP 0 + #define HAS_GPS 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 1 + #define HAS_DBG 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 1 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define AO_LED_GREEN 1 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL 0 + #define HAS_IGNITE 0 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEMETRUM_V_0_1) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_DBG 0 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define HAS_EXTERNAL_TEMP 1 + #define HAS_ACCEL_REF 0 + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + +#if defined(TELEDONGLE_V_0_1) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 0 + #define HAS_EEPROM 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 0 + #define SPI_CS_ON_P0 1 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TIDONGLE) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 0 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define LEDS_AVAILABLE (AO_LED_RED) + #define SPI_CS_ON_P1 0 + #define SPI_CS_ON_P0 1 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEBT_V_0_0) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 1 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 0 + #define HAS_BTM 1 + #define DBG_ON_P1 0 + #define DBG_ON_P0 1 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 2 + #define AO_LED_GREEN 1 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define HAS_IGNITE 0 + #define BT_LINK_ON_P2 1 + #define BT_LINK_ON_P1 0 + #define BT_LINK_PIN_INDEX 7 + #define BT_LINK_PIN P2_1 + #define HAS_MONITOR 1 +#endif + +#if defined(TELEBT_V_0_1) + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_SERIAL_1 1 + #define HAS_SERIAL_1_ALT_1 1 + #define HAS_SERIAL_1_ALT_2 0 + #define HAS_SERIAL_1_HW_FLOW 1 + #define USE_SERIAL_STDIN 1 + #define HAS_ADC 0 + #define HAS_DBG 1 + #define HAS_EEPROM 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_BTM 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + #define AO_LED_RED 1 + #define AO_LED_GREEN 2 + #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define M25_CS_MASK 0x04 /* CS0 is P1_2 */ + #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 0 + #define HAS_IGNITE 0 + #define BT_LINK_ON_P2 0 + #define BT_LINK_ON_P1 1 + #define BT_LINK_PIN_INDEX 7 + #define BT_LINK_PIN P1_7 + #define HAS_MONITOR 1 +#endif + +#if DBG_ON_P1 + + #define DBG_CLOCK (1 << 4) /* mi0 */ + #define DBG_DATA (1 << 5) /* mo0 */ + #define DBG_RESET_N (1 << 3) /* c0 */ + + #define DBG_CLOCK_PIN (P1_4) + #define DBG_DATA_PIN (P1_5) + #define DBG_RESET_N_PIN (P1_3) + + #define DBG_PORT_NUM 1 + #define DBG_PORT P1 + #define DBG_PORT_SEL P1SEL + #define DBG_PORT_INP P1INP + #define DBG_PORT_DIR P1DIR + +#endif /* DBG_ON_P1 */ + +#if DBG_ON_P0 + + #define DBG_CLOCK (1 << 3) + #define DBG_DATA (1 << 4) + #define DBG_RESET_N (1 << 5) + + #define DBG_CLOCK_PIN (P0_3) + #define DBG_DATA_PIN (P0_4) + #define DBG_RESET_N_PIN (P0_5) + + #define DBG_PORT_NUM 0 + #define DBG_PORT P0 + #define DBG_PORT_SEL P0SEL + #define DBG_PORT_INP P0INP + #define DBG_PORT_DIR P0DIR + +#endif /* DBG_ON_P0 */ + +#if COMPANION_CS_ON_P1 + #define COMPANION_CS_PORT P1 + #define COMPANION_CS_SEL P1SEL + #define COMPANION_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P1 + #define SPI_CS_PORT P1 + #define SPI_CS_SEL P1SEL + #define SPI_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P0 + #define SPI_CS_PORT P0 + #define SPI_CS_SEL P0SEL + #define SPI_CS_DIR P0DIR +#endif + +#ifndef IGNITE_ON_P2 +#error Please define IGNITE_ON_P2 +#endif + +#ifndef IGNITE_ON_P0 +#error Please define IGNITE_ON_P0 +#endif + +#ifndef HAS_SERIAL_1 +#error Please define HAS_SERIAL_1 +#endif + +#ifndef USE_SERIAL_STDIN +#error Please define USE_SERIAL_STDIN +#endif + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#ifndef HAS_EEPROM +#error Please define HAS_EEPROM +#endif + +#if HAS_EEPROM +#ifndef USE_INTERNAL_FLASH +#error Please define USE_INTERNAL_FLASH +#endif +#endif + +#ifndef HAS_DBG +#error Please define HAS_DBG +#endif + +#ifndef HAS_IGNITE +#error Please define HAS_IGNITE +#endif + +#ifndef PACKET_HAS_MASTER +#error Please define PACKET_HAS_MASTER +#endif + +#ifndef PACKET_HAS_SLAVE +#error Please define PACKET_HAS_SLAVE +#endif + +#ifndef HAS_MONITOR +#error Please define HAS_MONITOR +#endif +#endif /* _AO_PINS_H_ */ diff --git a/src/core/ao_product.c b/src/core/ao_product.c new file mode 100644 index 00000000..fb59580b --- /dev/null +++ b/src/core/ao_product.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_product.h" + +/* Defines which mark this particular AltOS product */ + +const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING; +const char ao_manufacturer[] = AO_iManufacturer_STRING; +const char ao_product[] = AO_iProduct_STRING; + +#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) + +#if HAS_USB +#include "ao_usb.h" +/* USB descriptors in one giant block of bytes */ +__code __at(0x00aa) uint8_t ao_usb_descriptors [] = +{ + /* Device descriptor */ + 0x12, + AO_USB_DESC_DEVICE, + LE_WORD(0x0110), /* bcdUSB */ + 0x02, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + AO_USB_CONTROL_SIZE, /* bMaxPacketSize */ + LE_WORD(0xFFFE), /* idVendor */ + LE_WORD(AO_idProduct_NUMBER), /* idProduct */ + LE_WORD(0x0100), /* bcdDevice */ + 0x01, /* iManufacturer */ + 0x02, /* iProduct */ + 0x03, /* iSerialNumber */ + 0x01, /* bNumConfigurations */ + + /* Configuration descriptor */ + 0x09, + AO_USB_DESC_CONFIGURATION, + LE_WORD(67), /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xC0, /* bmAttributes */ + 0x32, /* bMaxPower */ + + /* Control class interface */ + 0x09, + AO_USB_DESC_INTERFACE, + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndPoints */ + 0x02, /* bInterfaceClass */ + 0x02, /* bInterfaceSubClass */ + 0x01, /* bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */ + 0x00, /* iInterface */ + + /* Header functional descriptor */ + 0x05, + CS_INTERFACE, + 0x00, /* bDescriptor SubType Header */ + LE_WORD(0x0110), /* CDC version 1.1 */ + + /* Call management functional descriptor */ + 0x05, + CS_INTERFACE, + 0x01, /* bDescriptor SubType Call Management */ + 0x01, /* bmCapabilities = device handles call management */ + 0x01, /* bDataInterface call management interface number */ + + /* ACM functional descriptor */ + 0x04, + CS_INTERFACE, + 0x02, /* bDescriptor SubType Abstract Control Management */ + 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */ + + /* Union functional descriptor */ + 0x05, + CS_INTERFACE, + 0x06, /* bDescriptor SubType Union Functional descriptor */ + 0x00, /* bMasterInterface */ + 0x01, /* bSlaveInterface0 */ + + /* Notification EP */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_INT_EP|0x80, /* bEndpointAddress */ + 0x03, /* bmAttributes = intr */ + LE_WORD(8), /* wMaxPacketSize */ + 0x0A, /* bInterval */ + + /* Data class interface descriptor */ + 0x09, + AO_USB_DESC_INTERFACE, + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndPoints */ + 0x0A, /* bInterfaceClass = data */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* Data EP OUT */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_OUT_EP, /* bEndpointAddress */ + 0x02, /* bmAttributes = bulk */ + LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* Data EP in */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_IN_EP|0x80, /* bEndpointAddress */ + 0x02, /* bmAttributes = bulk */ + LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ + 0x00, /* bInterval */ + + /* String descriptors */ + 0x04, + AO_USB_DESC_STRING, + LE_WORD(0x0409), + + /* iManufacturer */ + AO_iManufacturer_LEN, + AO_USB_DESC_STRING, + AO_iManufacturer_UCS2, + + /* iProduct */ + AO_iProduct_LEN, + AO_USB_DESC_STRING, + AO_iProduct_UCS2, + + /* iSerial */ + AO_iSerial_LEN, + AO_USB_DESC_STRING, + AO_iSerial_UCS2, + + /* Terminating zero */ + 0 +}; +#endif diff --git a/src/core/ao_report.c b/src/core/ao_report.c new file mode 100644 index 00000000..3cf558e1 --- /dev/null +++ b/src/core/ao_report.c @@ -0,0 +1,180 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +#define BIT(i,x) ((x) ? (1 << (i)) : 0) +#define MORSE1(a) (1 | BIT(3,a)) +#define MORSE2(a,b) (2 | BIT(3,a) | BIT(4,b)) +#define MORSE3(a,b,c) (3 | BIT(3,a) | BIT(4,b) | BIT(5,c)) +#define MORSE4(a,b,c,d) (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d)) +#define MORSE5(a,b,c,d,e) (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e)) + +static const uint8_t flight_reports[] = { + MORSE3(0,0,0), /* startup, 'S' */ + MORSE2(0,0), /* idle 'I' */ + MORSE4(0,1,1,0), /* pad 'P' */ + MORSE4(1,0,0,0), /* boost 'B' */ + MORSE4(0,0,1,0), /* fast 'F' */ + MORSE4(1,0,1,0), /* coast 'C' */ + MORSE3(1,0,0), /* drogue 'D' */ + MORSE2(1,1), /* main 'M' */ + MORSE4(0,1,0,0), /* landed 'L' */ + MORSE4(1,0,0,1), /* invalid 'X' */ +}; + +#if HAS_BEEP +#define low(time) ao_beep_for(AO_BEEP_LOW, time) +#define mid(time) ao_beep_for(AO_BEEP_MID, time) +#define high(time) ao_beep_for(AO_BEEP_HIGH, time) +#else +#define low(time) ao_led_for(AO_LED_GREEN, time) +#define mid(time) ao_led_for(AO_LED_RED, time) +#define high(time) ao_led_for(AO_LED_GREEN|AO_LED_RED, time) +#endif +#define pause(time) ao_delay(time) + +static __pdata enum ao_flight_state ao_report_state; + +static void +ao_report_beep(void) __reentrant +{ + uint8_t r = flight_reports[ao_flight_state]; + uint8_t l = r & 7; + + if (!r) + return; + while (l--) { + if (r & 8) + mid(AO_MS_TO_TICKS(600)); + else + mid(AO_MS_TO_TICKS(200)); + pause(AO_MS_TO_TICKS(200)); + r >>= 1; + } + pause(AO_MS_TO_TICKS(400)); +} + +static void +ao_report_digit(uint8_t digit) __reentrant +{ + if (!digit) { + mid(AO_MS_TO_TICKS(500)); + pause(AO_MS_TO_TICKS(200)); + } else { + while (digit--) { + mid(AO_MS_TO_TICKS(200)); + pause(AO_MS_TO_TICKS(200)); + } + } + pause(AO_MS_TO_TICKS(300)); +} + +static void +ao_report_altitude(void) +{ + __pdata int16_t agl = ao_max_height; + __xdata uint8_t digits[10]; + __pdata uint8_t ndigits, i; + + if (agl < 0) + agl = 0; + ndigits = 0; + do { + digits[ndigits++] = agl % 10; + agl /= 10; + } while (agl); + + for (;;) { + ao_report_beep(); + i = ndigits; + do + ao_report_digit(digits[--i]); + while (i != 0); + pause(AO_SEC_TO_TICKS(5)); + } +} + +#if HAS_IGNITE +static uint8_t +ao_report_igniter_ready(enum ao_igniter igniter) +{ + return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0; +} + +static void +ao_report_continuity(void) __reentrant +{ + uint8_t c = (ao_report_igniter_ready(ao_igniter_drogue) | + (ao_report_igniter_ready(ao_igniter_main) << 1)); + if (c) { + while (c--) { + high(AO_MS_TO_TICKS(25)); + pause(AO_MS_TO_TICKS(100)); + } + } else { + c = 10; + while (c--) { + high(AO_MS_TO_TICKS(20)); + low(AO_MS_TO_TICKS(20)); + } + } + if (ao_log_full()) { + pause(AO_MS_TO_TICKS(100)); + c = 2; + while (c--) { + low(AO_MS_TO_TICKS(100)); + mid(AO_MS_TO_TICKS(100)); + high(AO_MS_TO_TICKS(100)); + mid(AO_MS_TO_TICKS(100)); + } + } + c = 50; + while (c-- && ao_flight_state == ao_flight_pad) + pause(AO_MS_TO_TICKS(100)); +} +#endif + +void +ao_report(void) +{ + ao_report_state = ao_flight_state; + for(;;) { + if (ao_flight_state == ao_flight_landed) + ao_report_altitude(); + ao_report_beep(); +#if HAS_IGNITE + if (ao_flight_state == ao_flight_idle) + ao_report_continuity(); + while (ao_flight_state == ao_flight_pad) + ao_report_continuity(); +#endif + __critical { + while (ao_report_state == ao_flight_state) + ao_sleep(DATA_TO_XDATA(&ao_flight_state)); + ao_report_state = ao_flight_state; + } + } +} + +static __xdata struct ao_task ao_report_task; + +void +ao_report_init(void) +{ + ao_add_task(&ao_report_task, ao_report, "report"); +} diff --git a/src/core/ao_rssi.c b/src/core/ao_rssi.c new file mode 100644 index 00000000..e3964d2d --- /dev/null +++ b/src/core/ao_rssi.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +static __xdata volatile uint16_t ao_rssi_time; +static __pdata volatile uint16_t ao_rssi_delay; +static __pdata uint8_t ao_rssi_led; + +void +ao_rssi(void) +{ + for (;;) { + while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3)) + ao_sleep(&ao_rssi_time); + ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100)); + ao_delay(ao_rssi_delay); + } +} + +void +ao_rssi_set(int rssi_value) +{ + if (rssi_value > 0) + rssi_value = 0; + ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5); + ao_rssi_time = ao_time(); + ao_wakeup(&ao_rssi_time); +} + +__xdata struct ao_task ao_rssi_task; + +void +ao_rssi_init(uint8_t rssi_led) +{ + ao_rssi_led = rssi_led; + ao_rssi_delay = 0; + ao_add_task(&ao_rssi_task, ao_rssi, "rssi"); +} diff --git a/src/core/ao_sample.c b/src/core/ao_sample.c new file mode 100644 index 00000000..b2b8e9f6 --- /dev/null +++ b/src/core/ao_sample.c @@ -0,0 +1,209 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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. + */ + +#ifndef AO_FLIGHT_TEST +#include "ao.h" +#endif + +/* + * Current sensor values + */ + +__pdata uint16_t ao_sample_tick; /* time of last data */ +__pdata int16_t ao_sample_pres; +__pdata int16_t ao_sample_alt; +__pdata int16_t ao_sample_height; +#if HAS_ACCEL +__pdata int16_t ao_sample_accel; +#endif + +__data uint8_t ao_sample_adc; + +/* + * Sensor calibration values + */ + +__pdata int16_t ao_ground_pres; /* startup pressure */ +__pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +__pdata int16_t ao_ground_accel; /* startup acceleration */ +__pdata int16_t ao_accel_2g; /* factory accel calibration */ +__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +static __pdata uint8_t ao_preflight; /* in preflight mode */ + +static __pdata uint16_t nsamples; +__pdata int32_t ao_sample_pres_sum; +#if HAS_ACCEL +__pdata int32_t ao_sample_accel_sum; +#endif + +static void +ao_sample_preflight(void) +{ + /* startup state: + * + * Collect 512 samples of acceleration and pressure + * data and average them to find the resting values + */ + if (nsamples < 512) { +#if HAS_ACCEL + ao_sample_accel_sum += ao_sample_accel; +#endif + ao_sample_pres_sum += ao_sample_pres; + ++nsamples; + } else { + ao_config_get(); +#if HAS_ACCEL + ao_ground_accel = ao_sample_accel_sum >> 9; + ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; + ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; +#endif + ao_ground_pres = ao_sample_pres_sum >> 9; + ao_ground_height = ao_pres_to_altitude(ao_ground_pres); + ao_preflight = FALSE; + } +} + +uint8_t +ao_sample(void) +{ + ao_wakeup(DATA_TO_XDATA(&ao_sample_adc)); + ao_sleep(DATA_TO_XDATA(&ao_adc_head)); + while (ao_sample_adc != ao_adc_head) { + __xdata struct ao_adc *ao_adc; + + /* Capture a sample */ + ao_adc = &ao_adc_ring[ao_sample_adc]; + ao_sample_tick = ao_adc->tick; + ao_sample_pres = ao_adc->pres; + ao_sample_alt = ao_pres_to_altitude(ao_sample_pres); + ao_sample_height = ao_sample_alt - ao_ground_height; +#if HAS_ACCEL + ao_sample_accel = ao_adc->accel; +#if HAS_ACCEL_REF + /* + * Ok, the math here is a bit tricky. + * + * ao_sample_accel: ADC output for acceleration + * ao_accel_ref: ADC output for the 5V reference. + * ao_cook_accel: Corrected acceleration value + * Vcc: 3.3V supply to the CC1111 + * Vac: 5V supply to the accelerometer + * accel: input voltage to accelerometer ADC pin + * ref: input voltage to 5V reference ADC pin + * + * + * Measured acceleration is ratiometric to Vcc: + * + * ao_sample_accel accel + * ------------ = ----- + * 32767 Vcc + * + * Measured 5v reference is also ratiometric to Vcc: + * + * ao_accel_ref ref + * ------------ = ----- + * 32767 Vcc + * + * + * ao_accel_ref = 32767 * (ref / Vcc) + * + * Acceleration is measured ratiometric to the 5V supply, + * so what we want is: + * + * ao_cook_accel accel + * ------------- = ----- + * 32767 ref + * + * + * accel Vcc + * = ----- * --- + * Vcc ref + * + * ao_sample_accel 32767 + * = ------------ * ------------ + * 32767 ao_accel_ref + * + * Multiply through by 32767: + * + * ao_sample_accel * 32767 + * ao_cook_accel = -------------------- + * ao_accel_ref + * + * Now, the tricky part. Getting this to compile efficiently + * and keeping all of the values in-range. + * + * First off, we need to use a shift of 16 instead of * 32767 as SDCC + * does the obvious optimizations for byte-granularity shifts: + * + * ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref + * + * Next, lets check our input ranges: + * + * 0 <= ao_sample_accel <= 0x7fff (singled ended ADC conversion) + * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) + * + * Plugging in our input ranges, we get an output range of 0 - 0x12490, + * which is 17 bits. That won't work. If we take the accel ref and shift + * by a bit, we'll change its range: + * + * 0xe000 <= ao_accel_ref<<1 <= 0xfffe + * + * ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1) + * + * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It + * is, however, one bit too large for our signed computations. So, we + * take the result and shift that by a bit: + * + * ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1 + * + * This finally creates an output range of 0 - 0x4924. As the ADC only + * provides 11 bits of data, we haven't actually lost any precision, + * just dropped a bit of noise off the low end. + */ + ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1; + if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) + ao_sample_accel = 0x7fff - ao_sample_accel; + ao_adc->accel = ao_sample_accel; +#endif +#endif + + if (ao_preflight) + ao_sample_preflight(); + else + ao_kalman(); + ao_sample_adc = ao_adc_ring_next(ao_sample_adc); + } + return !ao_preflight; +} + +void +ao_sample_init(void) +{ + nsamples = 0; + ao_sample_pres_sum = 0; + ao_sample_pres = 0; +#if HAS_ACCEL + ao_sample_accel_sum = 0; + ao_sample_accel = 0; +#endif + ao_sample_adc = ao_adc_head; + ao_preflight = TRUE; +} diff --git a/src/core/ao_state.c b/src/core/ao_state.c new file mode 100644 index 00000000..ed197aa5 --- /dev/null +++ b/src/core/ao_state.c @@ -0,0 +1,23 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +const char const * const ao_state_names[] = { + "startup", "idle", "pad", "boost", "fast", + "coast", "drogue", "main", "landed", "invalid" +}; diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c new file mode 100644 index 00000000..c0138a30 --- /dev/null +++ b/src/core/ao_stdio.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +/* + * Basic I/O functions to support SDCC stdio package + */ + +#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) + +__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; +__pdata int8_t ao_cur_stdio; +__pdata int8_t ao_num_stdios; + +void +putchar(char c) +{ + if (c == '\n') + (*ao_stdios[ao_cur_stdio].putchar)('\r'); + (*ao_stdios[ao_cur_stdio].putchar)(c); +} + +void +flush(void) +{ + if (ao_stdios[ao_cur_stdio].flush) + ao_stdios[ao_cur_stdio].flush(); +} + +__xdata uint8_t ao_stdin_ready; + +char +getchar(void) __reentrant __critical +{ + char c; + int8_t stdio = ao_cur_stdio; + + for (;;) { + c = ao_stdios[stdio].pollchar(); + if (c != AO_READ_AGAIN) + break; + if (++stdio == ao_num_stdios) + stdio = 0; + if (stdio == ao_cur_stdio) + ao_sleep(&ao_stdin_ready); + } + ao_cur_stdio = stdio; + return c; +} + +uint8_t +ao_echo(void) +{ + return ao_stdios[ao_cur_stdio].echo; +} + +int8_t +ao_add_stdio(char (*pollchar)(void), + void (*putchar)(char), + void (*flush)(void)) __reentrant +{ + if (ao_num_stdios == AO_NUM_STDIOS) + ao_panic(AO_PANIC_STDIO); + ao_stdios[ao_num_stdios].pollchar = pollchar; + ao_stdios[ao_num_stdios].putchar = putchar; + ao_stdios[ao_num_stdios].flush = flush; + ao_stdios[ao_num_stdios].echo = 1; + return ao_num_stdios++; +} diff --git a/src/core/ao_storage.c b/src/core/ao_storage.c new file mode 100644 index 00000000..6ffca0e5 --- /dev/null +++ b/src/core/ao_storage.c @@ -0,0 +1,184 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +uint8_t +ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t this_len; + uint16_t this_off; + + ao_storage_setup(); + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + while (len) { + + /* Compute portion of transfer within + * a single block + */ + this_off = (uint16_t) pos & (ao_storage_unit - 1); + this_len = ao_storage_unit - this_off; + if (this_len > len) + this_len = len; + + if (!ao_storage_device_read(pos, buf, this_len)) + return 0; + + /* See how much is left */ + buf += this_len; + len -= this_len; + pos += this_len; + } + return 1; +} + +uint8_t +ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t this_len; + uint16_t this_off; + + ao_storage_setup(); + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + while (len) { + + /* Compute portion of transfer within + * a single block + */ + this_off = (uint16_t) pos & (ao_storage_unit - 1); + this_len = ao_storage_unit - this_off; + if (this_len > len) + this_len = len; + + if (!ao_storage_device_write(pos, buf, this_len)) + return 0; + + /* See how much is left */ + buf += this_len; + len -= this_len; + pos += this_len; + } + return 1; +} + +static __xdata uint8_t storage_data[8]; + +static void +ao_storage_dump(void) __reentrant +{ + uint8_t i, j; + + ao_cmd_hex(); + if (ao_cmd_status != ao_cmd_success) + return; + for (i = 0; ; i += 8) { + if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i, + storage_data, + 8)) { + ao_cmd_put16((uint16_t) i); + for (j = 0; j < 8; j++) { + putchar(' '); + ao_cmd_put8(storage_data[j]); + } + putchar ('\n'); + } + if (i == 248) + break; + } +} + +#if 0 + +/* not enough space for this today + */ +static void +ao_storage_store(void) __reentrant +{ + uint16_t block; + uint8_t i; + uint16_t len; + static __xdata uint8_t b; + uint32_t addr; + + ao_cmd_hex(); + block = ao_cmd_lex_i; + ao_cmd_hex(); + i = ao_cmd_lex_i; + addr = ((uint32_t) block << 8) | i; + ao_cmd_hex(); + len = ao_cmd_lex_i; + if (ao_cmd_status != ao_cmd_success) + return; + while (len--) { + ao_cmd_hex(); + if (ao_cmd_status != ao_cmd_success) + return; + b = ao_cmd_lex_i; + ao_storage_write(addr, &b, 1); + addr++; + } +} +#endif + +void +ao_storage_zap(void) __reentrant +{ + ao_cmd_hex(); + if (ao_cmd_status != ao_cmd_success) + return; + ao_storage_erase((uint32_t) ao_cmd_lex_i << 8); +} + +void +ao_storage_zapall(void) __reentrant +{ + uint32_t pos; + + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) + ao_storage_erase(pos); +} + +void +ao_storage_info(void) __reentrant +{ + printf("Storage size: %ld\n", ao_storage_total); + printf("Storage erase unit: %ld\n", ao_storage_block); + ao_storage_device_info(); +} + +__code struct ao_cmds ao_storage_cmds[] = { + { ao_storage_info, "f\0Show storage" }, + { ao_storage_dump, "e \0Dump flash" }, +#ifdef HAS_STORAGE_DBG + { ao_storage_store, "w ...\0Write data to flash" }, +#endif + { ao_storage_zap, "z \0Erase " }, + { ao_storage_zapall,"Z \0Erase all. is doit with D&I" }, + { 0, NULL }, +}; + +void +ao_storage_init(void) +{ + ao_storage_device_init(); + ao_cmd_register(&ao_storage_cmds[0]); +} diff --git a/src/core/ao_task.c b/src/core/ao_task.c new file mode 100644 index 00000000..f5850fa4 --- /dev/null +++ b/src/core/ao_task.c @@ -0,0 +1,275 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +#define AO_NO_TASK_INDEX 0xff + +__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS]; +__data uint8_t ao_num_tasks; +__data uint8_t ao_cur_task_index; +__xdata struct ao_task *__data ao_cur_task; + +void +ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant +{ + uint8_t __xdata *stack; + uint8_t task_id; + uint8_t t; + if (ao_num_tasks == AO_NUM_TASKS) + ao_panic(AO_PANIC_NO_TASK); + for (task_id = 1; task_id != 0; task_id++) { + for (t = 0; t < ao_num_tasks; t++) + if (ao_tasks[t]->task_id == task_id) + break; + if (t == ao_num_tasks) + break; + } + ao_tasks[ao_num_tasks++] = task; + task->task_id = task_id; + task->name = name; + /* + * Construct a stack frame so that it will 'return' + * to the start of the task + */ + stack = task->stack; + + *stack++ = ((uint16_t) start); /* 0 */ + *stack++ = ((uint16_t) start) >> 8; /* 1 */ + + /* and the stuff saved by ao_switch */ + *stack++ = 0; /* 2 acc */ + *stack++ = 0x80; /* 3 IE */ + + /* 4 DPL + * 5 DPH + * 6 B + * 7 R2 + * 8 R3 + * 9 R4 + * 10 R5 + * 11 R6 + * 12 R7 + * 13 R0 + * 14 R1 + * 15 PSW + * 16 BP + */ + for (t = 0; t < 13; t++) + *stack++ = 0; + + task->stack_count = 17; + task->wchan = NULL; +} + +/* Task switching function. This must not use any stack variables */ +void +ao_yield(void) __naked +{ + + /* Save current context */ + _asm + /* Push ACC first, as when restoring the context it must be restored + * last (it is used to set the IE register). */ + push ACC + /* Store the IE register then enable interrupts. */ + push _IEN0 + setb _EA + push DPL + push DPH + push b + push ar2 + push ar3 + push ar4 + push ar5 + push ar6 + push ar7 + push ar0 + push ar1 + push PSW + _endasm; + PSW = 0; + _asm + push _bp + _endasm; + + if (ao_cur_task_index == AO_NO_TASK_INDEX) + ao_cur_task_index = ao_num_tasks-1; + else + { + uint8_t stack_len; + __data uint8_t *stack_ptr; + __xdata uint8_t *save_ptr; + /* Save the current stack */ + stack_len = SP - (AO_STACK_START - 1); + ao_cur_task->stack_count = stack_len; + stack_ptr = (uint8_t __data *) AO_STACK_START; + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; + do + *save_ptr++ = *stack_ptr++; + while (--stack_len); + } + + /* Empty the stack; might as well let interrupts have the whole thing */ + SP = AO_STACK_START - 1; + + /* Find a task to run. If there isn't any runnable task, + * this loop will run forever, which is just fine + */ + { + __pdata uint8_t ao_next_task_index = ao_cur_task_index; + for (;;) { + ++ao_next_task_index; + if (ao_next_task_index == ao_num_tasks) + ao_next_task_index = 0; + + ao_cur_task = ao_tasks[ao_next_task_index]; + if (ao_cur_task->wchan == NULL) { + ao_cur_task_index = ao_next_task_index; + break; + } + + /* Check if the alarm is set for a time which has passed */ + if (ao_cur_task->alarm && + (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) { + ao_cur_task_index = ao_next_task_index; + break; + } + + /* Enter lower power mode when there isn't anything to do */ + if (ao_next_task_index == ao_cur_task_index) + PCON = PCON_IDLE; + } + } + + { + uint8_t stack_len; + __data uint8_t *stack_ptr; + __xdata uint8_t *save_ptr; + + /* Restore the old stack */ + stack_len = ao_cur_task->stack_count; + SP = AO_STACK_START - 1 + stack_len; + + stack_ptr = (uint8_t __data *) AO_STACK_START; + save_ptr = (uint8_t __xdata *) ao_cur_task->stack; + do + *stack_ptr++ = *save_ptr++; + while (--stack_len); + } + + _asm + pop _bp + pop PSW + pop ar1 + pop ar0 + pop ar7 + pop ar6 + pop ar5 + pop ar4 + pop ar3 + pop ar2 + pop b + pop DPH + pop DPL + /* The next byte of the stack is the IE register. Only the global + enable bit forms part of the task context. Pop off the IE then set + the global enable bit to match that of the stored IE register. */ + pop ACC + JB ACC.7,0098$ + CLR _EA + LJMP 0099$ + 0098$: + SETB _EA + 0099$: + /* Finally pop off the ACC, which was the first register saved. */ + pop ACC + ret + _endasm; +} + +uint8_t +ao_sleep(__xdata void *wchan) +{ + __critical { + ao_cur_task->wchan = wchan; + } + ao_yield(); + ao_cur_task->alarm = 0; + if (ao_cur_task->wchan) { + ao_cur_task->wchan = NULL; + return 1; + } + return 0; +} + +void +ao_wakeup(__xdata void *wchan) +{ + uint8_t i; + + for (i = 0; i < ao_num_tasks; i++) + if (ao_tasks[i]->wchan == wchan) + ao_tasks[i]->wchan = NULL; +} + +void +ao_alarm(uint16_t delay) +{ + /* Make sure we sleep *at least* delay ticks, which means adding + * one to account for the fact that we may be close to the next tick + */ + if (!(ao_cur_task->alarm = ao_time() + delay + 1)) + ao_cur_task->alarm = 1; +} + +void +ao_exit(void) __critical +{ + uint8_t i; + ao_num_tasks--; + for (i = ao_cur_task_index; i < ao_num_tasks; i++) + ao_tasks[i] = ao_tasks[i+1]; + ao_cur_task_index = AO_NO_TASK_INDEX; + ao_yield(); + /* we'll never get back here */ +} + +void +ao_task_info(void) +{ + uint8_t i; + uint8_t pc_loc; + __xdata struct ao_task *task; + + for (i = 0; i < ao_num_tasks; i++) { + task = ao_tasks[i]; + pc_loc = task->stack_count - 17; + printf("%12s: wchan %04x pc %04x\n", + task->name, + (int16_t) task->wchan, + (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8)); + } +} + +void +ao_start_scheduler(void) +{ + ao_cur_task_index = AO_NO_TASK_INDEX; + ao_cur_task = NULL; + ao_yield(); +} diff --git a/src/core/ao_telem.h b/src/core/ao_telem.h new file mode 100644 index 00000000..1a8da291 --- /dev/null +++ b/src/core/ao_telem.h @@ -0,0 +1,172 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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. + */ + +#ifndef _AO_TELEM_H_ +#define _AO_TELEM_H_ + +#define AO_TELEMETRY_VERSION 4 + +/* + * Telemetry version 4 and higher format: + * + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + */ + +#define AO_TELEM_VERSION "VERSION" +#define AO_TELEM_CALL "c" +#define AO_TELEM_SERIAL "n" +#define AO_TELEM_FLIGHT "f" +#define AO_TELEM_RSSI "r" +#define AO_TELEM_STATE "s" +#define AO_TELEM_TICK "t" + +/* + * Raw sensor values + * + * Name Value + * r_a Accelerometer reading (integer) + * r_b Barometer reading (integer) + * r_t Thermometer reading (integer) + * r_v Battery reading (integer) + * r_d Drogue continuity (integer) + * r_m Main continuity (integer) + */ + +#define AO_TELEM_RAW_ACCEL "r_a" +#define AO_TELEM_RAW_BARO "r_b" +#define AO_TELEM_RAW_THERMO "r_t" +#define AO_TELEM_RAW_BATT "r_v" +#define AO_TELEM_RAW_DROGUE "r_d" +#define AO_TELEM_RAW_MAIN "r_m" + +/* + * Sensor calibration values + * + * Name Value + * c_a Ground accelerometer reading (integer) + * c_b Ground barometer reading (integer) + * c_p Accelerometer reading for +1g + * c_m Accelerometer reading for -1g + */ + +#define AO_TELEM_CAL_ACCEL_GROUND "c_a" +#define AO_TELEM_CAL_BARO_GROUND "c_b" +#define AO_TELEM_CAL_ACCEL_PLUS "c_p" +#define AO_TELEM_CAL_ACCEL_MINUS "c_m" + +/* + * Kalman state values + * + * Name Value + * k_h Height above pad (integer, meters) + * k_s Vertical speeed (integer, m/s * 16) + * k_a Vertical acceleration (integer, m/s² * 16) + */ + +#define AO_TELEM_KALMAN_HEIGHT "k_h" +#define AO_TELEM_KALMAN_SPEED "k_s" +#define AO_TELEM_KALMAN_ACCEL "k_a" + +/* + * Ad-hoc flight values + * + * Name Value + * a_a Acceleration (integer, sensor units) + * a_s Speed (integer, integrated acceleration value) + * a_b Barometer reading (integer, sensor units) + */ + +#define AO_TELEM_ADHOC_ACCEL "a_a" +#define AO_TELEM_ADHOC_SPEED "a_s" +#define AO_TELEM_ADHOC_BARO "a_b" + +/* + * GPS values + * + * Name Value + * g GPS state (string): + * l locked + * u unlocked + * e error (missing or broken) + * g_n Number of sats used in solution + * g_ns Latitude (degrees * 10e7) + * g_ew Longitude (degrees * 10e7) + * g_a Altitude (integer meters) + * g_Y GPS year (integer) + * g_M GPS month (integer - 1-12) + * g_D GPS day (integer - 1-31) + * g_h GPS hour (integer - 0-23) + * g_m GPS minute (integer - 0-59) + * g_s GPS second (integer - 0-59) + * g_v GPS vertical speed (integer, cm/sec) + * g_g GPS horizontal speed (integer, cm/sec) + * g_c GPS course (integer, 0-359) + * g_hd GPS hdop (integer * 10) + * g_vd GPS vdop (integer * 10) + * g_he GPS h error (integer) + * g_ve GPS v error (integer) + */ + +#define AO_TELEM_GPS_STATE "g" +#define AO_TELEM_GPS_STATE_LOCKED 'l' +#define AO_TELEM_GPS_STATE_UNLOCKED 'u' +#define AO_TELEM_GPS_STATE_ERROR 'e' +#define AO_TELEM_GPS_NUM_SAT "g_n" +#define AO_TELEM_GPS_LATITUDE "g_ns" +#define AO_TELEM_GPS_LONGITUDE "g_ew" +#define AO_TELEM_GPS_ALTITUDE "g_a" +#define AO_TELEM_GPS_YEAR "g_Y" +#define AO_TELEM_GPS_MONTH "g_M" +#define AO_TELEM_GPS_DAY "g_D" +#define AO_TELEM_GPS_HOUR "g_h" +#define AO_TELEM_GPS_MINUTE "g_m" +#define AO_TELEM_GPS_SECOND "g_s" +#define AO_TELEM_GPS_VERTICAL_SPEED "g_v" +#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_g" +#define AO_TELEM_GPS_COURSE "g_c" +#define AO_TELEM_GPS_HDOP "g_hd" +#define AO_TELEM_GPS_VDOP "g_vd" +#define AO_TELEM_GPS_HERROR "g_he" +#define AO_TELEM_GPS_VERROR "g_ve" + +/* + * GPS satellite values + * + * Name Value + * s_n Number of satellites reported (integer) + * s_v0 Space vehicle ID (integer) for report 0 + * s_c0 C/N0 number (integer) for report 0 + * s_v1 Space vehicle ID (integer) for report 1 + * s_c1 C/N0 number (integer) for report 1 + * ... + */ + +#define AO_TELEM_SAT_NUM "s_n" +#define AO_TELEM_SAT_SVID "s_v" +#define AO_TELEM_SAT_C_N_0 "s_c" + +#endif /* _AO_TELEM_H_ */ diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c new file mode 100644 index 00000000..c7338a58 --- /dev/null +++ b/src/core/ao_telemetry.c @@ -0,0 +1,270 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" +#include "ao_product.h" + +static __pdata uint16_t ao_telemetry_interval; +static __pdata int8_t ao_telemetry_config_max; +static __pdata int8_t ao_telemetry_config_cur; +#if HAS_GPS +static __pdata int8_t ao_telemetry_loc_cur; +static __pdata int8_t ao_telemetry_sat_cur; +#endif +#if HAS_COMPANION +static __pdata int8_t ao_telemetry_companion_max; +static __pdata int8_t ao_telemetry_companion_cur; +#endif +static __pdata uint8_t ao_rdf = 0; +static __pdata uint16_t ao_rdf_time; + +#define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5) +#define AO_RDF_LENGTH_MS 500 + +#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) +#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM +#endif + +#if defined(TELEMINI_V_1_0) +#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMINI +#endif + +#if defined(TELENANO_V_0_1) +#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELENANO +#endif + +static __xdata union ao_telemetry_all telemetry; + +/* Send sensor packet */ +static void +ao_send_sensor(void) +{ + uint8_t sample; + sample = ao_sample_adc; + + telemetry.generic.tick = ao_adc_ring[sample].tick; + telemetry.generic.type = AO_TELEMETRY_SENSOR; + + telemetry.sensor.state = ao_flight_state; +#if HAS_ACCEL + telemetry.sensor.accel = ao_adc_ring[sample].accel; +#else + telemetry.sensor.accel = 0; +#endif + telemetry.sensor.pres = ao_adc_ring[sample].pres; + telemetry.sensor.temp = ao_adc_ring[sample].temp; + telemetry.sensor.v_batt = ao_adc_ring[sample].v_batt; +#if HAS_IGNITE + telemetry.sensor.sense_d = ao_adc_ring[sample].sense_d; + telemetry.sensor.sense_m = ao_adc_ring[sample].sense_m; +#else + telemetry.sensor.sense_d = 0; + telemetry.sensor.sense_m = 0; +#endif + + telemetry.sensor.acceleration = ao_accel; + telemetry.sensor.speed = ao_speed; + telemetry.sensor.height = ao_height; + + telemetry.sensor.ground_pres = ao_ground_pres; +#if HAS_ACCEL + telemetry.sensor.ground_accel = ao_ground_accel; + telemetry.sensor.accel_plus_g = ao_config.accel_plus_g; + telemetry.sensor.accel_minus_g = ao_config.accel_minus_g; +#else + telemetry.sensor.ground_accel = 0; + telemetry.sensor.accel_plus_g = 0; + telemetry.sensor.accel_minus_g = 0; +#endif + + ao_radio_send(&telemetry, sizeof (telemetry)); +} + +static void +ao_send_configuration(void) +{ + if (--ao_telemetry_config_cur <= 0) + { + telemetry.generic.type = AO_TELEMETRY_CONFIGURATION; + telemetry.configuration.device = AO_idProduct_NUMBER; + telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number; + telemetry.configuration.config_major = AO_CONFIG_MAJOR; + telemetry.configuration.config_minor = AO_CONFIG_MINOR; + telemetry.configuration.apogee_delay = ao_config.apogee_delay; + telemetry.configuration.main_deploy = ao_config.main_deploy; + telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10; + memcpy (telemetry.configuration.callsign, + ao_config.callsign, + AO_MAX_CALLSIGN); + memcpy (telemetry.configuration.version, + ao_version, + AO_MAX_VERSION); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_config_cur = ao_telemetry_config_max; + } +} + +#if HAS_GPS +static void +ao_send_location(void) +{ + if (--ao_telemetry_loc_cur <= 0) + { + telemetry.generic.type = AO_TELEMETRY_LOCATION; + ao_mutex_get(&ao_gps_mutex); + memcpy(&telemetry.location.flags, + &ao_gps_data.flags, + 26); + ao_mutex_put(&ao_gps_mutex); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_loc_cur = ao_telemetry_config_max; + } +} + +static void +ao_send_satellite(void) +{ + if (--ao_telemetry_sat_cur <= 0) + { + telemetry.generic.type = AO_TELEMETRY_SATELLITE; + ao_mutex_get(&ao_gps_mutex); + telemetry.satellite.channels = ao_gps_tracking_data.channels; + memcpy(&telemetry.satellite.sats, + &ao_gps_tracking_data.sats, + AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info)); + ao_mutex_put(&ao_gps_mutex); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_sat_cur = ao_telemetry_config_max; + } +} +#endif + +#if HAS_COMPANION +static void +ao_send_companion(void) +{ + if (--ao_telemetry_companion_cur <= 0) { + telemetry.generic.type = AO_TELEMETRY_COMPANION; + telemetry.companion.board_id = ao_companion_setup.board_id; + telemetry.companion.update_period = ao_companion_setup.update_period; + telemetry.companion.channels = ao_companion_setup.channels; + ao_mutex_get(&ao_companion_mutex); + memcpy(&telemetry.companion.companion_data, + ao_companion_data, + ao_companion_setup.channels * 2); + ao_mutex_put(&ao_companion_mutex); + ao_radio_send(&telemetry, sizeof (telemetry)); + ao_telemetry_companion_cur = ao_telemetry_companion_max; + } +} +#endif + +void +ao_telemetry(void) +{ + uint16_t time; + int16_t delay; + + ao_config_get(); + if (!ao_config.radio_enable) + ao_exit(); + while (!ao_flight_number) + ao_sleep(&ao_flight_number); + + telemetry.generic.serial = ao_serial_number; + for (;;) { + while (ao_telemetry_interval == 0) + ao_sleep(&telemetry); + time = ao_rdf_time = ao_time(); + while (ao_telemetry_interval) { + + + ao_send_sensor(); +#if HAS_COMPANION + if (ao_companion_running) + ao_send_companion(); +#endif + ao_send_configuration(); +#if HAS_GPS + ao_send_location(); + ao_send_satellite(); +#endif + if (ao_rdf && + (int16_t) (ao_time() - ao_rdf_time) >= 0) + { + ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS; + ao_radio_rdf(AO_RDF_LENGTH_MS); + } + time += ao_telemetry_interval; + delay = time - ao_time(); + if (delay > 0) + ao_delay(delay); + else + time = ao_time(); + } + } +} + +void +ao_telemetry_set_interval(uint16_t interval) +{ + ao_telemetry_interval = interval; + +#if HAS_COMPANION + if (!ao_companion_setup.update_period) + ao_companion_setup.update_period = AO_SEC_TO_TICKS(1); + ao_telemetry_companion_max = ao_companion_setup.update_period / interval; + ao_telemetry_companion_cur = 1; +#endif + + ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval; +#if HAS_COMPANION + ao_telemetry_config_cur = ao_telemetry_companion_cur; + if (ao_telemetry_config_max > ao_telemetry_config_cur) + ao_telemetry_config_cur++; +#else + ao_telemetry_config_cur = 1; +#endif + +#if HAS_GPS + ao_telemetry_loc_cur = ao_telemetry_config_cur; + if (ao_telemetry_config_max > ao_telemetry_loc_cur) + ao_telemetry_loc_cur++; + ao_telemetry_sat_cur = ao_telemetry_loc_cur; + if (ao_telemetry_config_max > ao_telemetry_sat_cur) + ao_telemetry_sat_cur++; +#endif + ao_wakeup(&telemetry); +} + +void +ao_rdf_set(uint8_t rdf) +{ + ao_rdf = rdf; + if (rdf == 0) + ao_radio_rdf_abort(); + else + ao_rdf_time = ao_time(); +} + +__xdata struct ao_task ao_telemetry_task; + +void +ao_telemetry_init() +{ + ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry"); +} diff --git a/src/drivers/ao_25lc1024.c b/src/drivers/ao_25lc1024.c new file mode 100644 index 00000000..738f8ce6 --- /dev/null +++ b/src/drivers/ao_25lc1024.c @@ -0,0 +1,241 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_25lc1024.h" + +#define EE_BLOCK_SIZE ((uint16_t) (256)) +#define EE_BLOCK_SHIFT 8 +#define EE_DEVICE_SIZE ((uint32_t) 128 * (uint32_t) 1024) + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +__pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +__pdata uint16_t ao_storage_unit; + +/* + * Using SPI on USART 0, with P1_2 as the chip select + */ + +#define EE_CS P1_2 +#define EE_CS_INDEX 2 + +static __xdata uint8_t ao_ee_mutex; + +#define ao_ee_delay() do { \ + _asm nop _endasm; \ + _asm nop _endasm; \ + _asm nop _endasm; \ +} while(0) + +#define ao_ee_cs_low() ao_spi_get_bit(EE_CS) + +#define ao_ee_cs_high() ao_spi_put_bit(EE_CS) + +struct ao_ee_instruction { + uint8_t instruction; + uint8_t address[3]; +} __xdata ao_ee_instruction; + +static void +ao_ee_write_enable(void) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_WREN; + ao_spi_send(&ao_ee_instruction, 1); + ao_ee_cs_high(); +} + +static uint8_t +ao_ee_rdsr(void) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_RDSR; + ao_spi_send(&ao_ee_instruction, 1); + ao_spi_recv(&ao_ee_instruction, 1); + ao_ee_cs_high(); + return ao_ee_instruction.instruction; +} + +static void +ao_ee_wrsr(uint8_t status) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_WRSR; + ao_ee_instruction.address[0] = status; + ao_spi_send(&ao_ee_instruction, 2); + ao_ee_cs_high(); +} + +#define EE_BLOCK_NONE 0xffff + +static __xdata uint8_t ao_ee_data[EE_BLOCK_SIZE]; +static __pdata uint16_t ao_ee_block = EE_BLOCK_NONE; +static __pdata uint8_t ao_ee_block_dirty; + +/* Write the current block to the EEPROM */ +static void +ao_ee_write_block(void) +{ + uint8_t status; + + status = ao_ee_rdsr(); + if (status & (EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN)) { + status &= ~(EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN); + ao_ee_wrsr(status); + } + ao_ee_write_enable(); + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_WRITE; + ao_ee_instruction.address[0] = ao_ee_block >> 8; + ao_ee_instruction.address[1] = ao_ee_block; + ao_ee_instruction.address[2] = 0; + ao_spi_send(&ao_ee_instruction, 4); + ao_spi_send(ao_ee_data, EE_BLOCK_SIZE); + ao_ee_cs_high(); + for (;;) { + uint8_t status = ao_ee_rdsr(); + if ((status & EE_STATUS_WIP) == 0) + break; + } +} + +/* Read the current block from the EEPROM */ +static void +ao_ee_read_block(void) +{ + ao_ee_cs_low(); + ao_ee_instruction.instruction = EE_READ; + ao_ee_instruction.address[0] = ao_ee_block >> 8; + ao_ee_instruction.address[1] = ao_ee_block; + ao_ee_instruction.address[2] = 0; + ao_spi_send(&ao_ee_instruction, 4); + ao_spi_recv(ao_ee_data, EE_BLOCK_SIZE); + ao_ee_cs_high(); +} + +static void +ao_ee_flush_internal(void) +{ + if (ao_ee_block_dirty) { + ao_ee_write_block(); + ao_ee_block_dirty = 0; + } +} + +static void +ao_ee_fill(uint16_t block) +{ + if (block != ao_ee_block) { + ao_ee_flush_internal(); + ao_ee_block = block; + ao_ee_read_block(); + } +} + +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); + + /* Transfer the data */ + ao_mutex_get(&ao_ee_mutex); { + if (len != EE_BLOCK_SIZE) + ao_ee_fill(block); + else { + ao_ee_flush_internal(); + ao_ee_block = block; + } + memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len); + ao_ee_block_dirty = 1; + } ao_mutex_put(&ao_ee_mutex); + return 1; +} + +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT); + + /* Transfer the data */ + ao_mutex_get(&ao_ee_mutex); { + ao_ee_fill(block); + memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len); + } ao_mutex_put(&ao_ee_mutex); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ + ao_mutex_get(&ao_ee_mutex); { + ao_ee_flush_internal(); + } ao_mutex_put(&ao_ee_mutex); +} + +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + ao_mutex_get(&ao_ee_mutex); { + ao_ee_flush_internal(); + ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT); + memset(ao_ee_data, 0xff, EE_BLOCK_SIZE); + ao_ee_block_dirty = 1; + } ao_mutex_put(&ao_ee_mutex); + return 1; +} + +static void +ee_store(void) __reentrant +{ +} + +void +ao_storage_setup(void) +{ + if (ao_storage_total == 0) { + ao_storage_total = EE_DEVICE_SIZE; + ao_storage_block = EE_BLOCK_SIZE; + ao_storage_config = EE_DEVICE_SIZE - EE_BLOCK_SIZE; + ao_storage_unit = EE_BLOCK_SIZE; + } +} + +void +ao_storage_device_info(void) __reentrant +{ +} + +/* + * To initialize the chip, set up the CS line and + * the SPI interface + */ +void +ao_storage_device_init(void) +{ + /* set up CS */ + EE_CS = 1; + P1DIR |= (1 << EE_CS_INDEX); + P1SEL &= ~(1 << EE_CS_INDEX); +} diff --git a/src/drivers/ao_25lc1024.h b/src/drivers/ao_25lc1024.h new file mode 100644 index 00000000..44e52387 --- /dev/null +++ b/src/drivers/ao_25lc1024.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +/* Defines for the 25LC1024 1Mbit SPI Bus Serial EEPROM */ + +#ifndef _25LC1024_H_ +#define _25LC1024_H_ + +#define EE_READ 0x03 +#define EE_WRITE 0x02 +#define EE_WREN 0x06 +#define EE_WRDI 0x04 +#define EE_RDSR 0x05 +#define EE_WRSR 0x01 +#define EE_PE 0x42 +#define EE_SE 0xd8 +#define EE_CE 0xc7 +#define EE_RDID 0xab +#define EE_DPD 0xb9 + +#define EE_STATUS_WIP (1 << 0) +#define EE_STATUS_WEL (1 << 1) +#define EE_STATUS_BP0 (1 << 2) +#define EE_STATUS_BP1 (1 << 3) +#define EE_STATUS_WPEN (1 << 7) + +#endif /* _25LC1024_H_ */ diff --git a/src/drivers/ao_at45db161d.c b/src/drivers/ao_at45db161d.c new file mode 100644 index 00000000..aee9877a --- /dev/null +++ b/src/drivers/ao_at45db161d.c @@ -0,0 +1,318 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_at45db161d.h" + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +__pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +__pdata uint16_t ao_storage_unit; + +#define FLASH_CS P1_1 +#define FLASH_CS_INDEX 1 + +#define FLASH_BLOCK_SIZE_MAX 512 + +__xdata uint8_t ao_flash_mutex; + +#define ao_flash_delay() do { \ + _asm nop _endasm; \ + _asm nop _endasm; \ + _asm nop _endasm; \ +} while(0) + +#define ao_flash_cs_low() ao_spi_get_bit(FLASH_CS) + +#define ao_flash_cs_high() ao_spi_put_bit(FLASH_CS) + +struct ao_flash_instruction { + uint8_t instruction; + uint8_t address[3]; +} __xdata ao_flash_instruction; + +static void +ao_flash_set_pagesize_512(void) +{ + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_SET_CONFIG; + ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0; + ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1; + ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2; + ao_spi_send(&ao_flash_instruction, 4); + ao_flash_cs_high(); +} + + +static uint8_t +ao_flash_read_status(void) +{ + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_READ_STATUS; + ao_spi_send(&ao_flash_instruction, 1); + ao_spi_recv(&ao_flash_instruction, 1); + ao_flash_cs_high(); + return ao_flash_instruction.instruction; +} + +#define FLASH_BLOCK_NONE 0xffff + +static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX]; +static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE; +static __pdata uint8_t ao_flash_block_dirty; +static __pdata uint8_t ao_flash_write_pending; +static __pdata uint8_t ao_flash_setup_done; +static __pdata uint8_t ao_flash_block_shift; +static __pdata uint16_t ao_flash_block_size; +static __pdata uint16_t ao_flash_block_mask; + +void +ao_storage_setup(void) __reentrant +{ + uint8_t status; + + if (ao_flash_setup_done) + return; + + ao_mutex_get(&ao_flash_mutex); + if (ao_flash_setup_done) { + ao_mutex_put(&ao_flash_mutex); + return; + } + + /* On first use, check to see if the flash chip has + * been programmed to use 512 byte pages. If not, do so. + * And then, because the flash part must be power cycled + * for that change to take effect, panic. + */ + status = ao_flash_read_status(); + + if (!(status & FLASH_STATUS_PAGESIZE_512)) { + ao_flash_set_pagesize_512(); + ao_panic(AO_PANIC_FLASH); + } + + switch (status & 0x3c) { + + /* AT45DB321D */ + case 0x34: + ao_flash_block_shift = 9; + ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024); + break; + + /* AT45DB161D */ + case 0x2c: + ao_flash_block_shift = 9; + ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024); + break; + + /* AT45DB081D */ + case 0x24: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024); + break; + + /* AT45DB041D */ + case 0x1c: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024); + break; + + /* AT45DB021D */ + case 0x14: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024); + break; + + /* AT45DB011D */ + case 0x0c: + ao_flash_block_shift = 8; + ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024); + break; + + default: + ao_panic(AO_PANIC_FLASH); + } + ao_flash_block_size = 1 << ao_flash_block_shift; + ao_flash_block_mask = ao_flash_block_size - 1; + + ao_storage_block = ao_flash_block_size; + ao_storage_config = ao_storage_total - ao_storage_block; + ao_storage_unit = ao_flash_block_size; + + ao_flash_setup_done = 1; + ao_mutex_put(&ao_flash_mutex); +} + +static void +ao_flash_wait_write(void) +{ + if (ao_flash_write_pending) { + for (;;) { + uint8_t status = ao_flash_read_status(); + if ((status & FLASH_STATUS_RDY)) + break; + } + ao_flash_write_pending = 0; + } +} + +/* Write the current block to the FLASHPROM */ +static void +ao_flash_write_block(void) +{ + ao_flash_wait_write(); + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_WRITE; + + /* 13/14 block bits + 9/8 byte bits (always 0) */ + ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); + ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); + ao_flash_instruction.address[2] = 0; + ao_spi_send(&ao_flash_instruction, 4); + ao_spi_send(ao_flash_data, ao_storage_block); + ao_flash_cs_high(); + ao_flash_write_pending = 1; +} + +/* Read the current block from the FLASHPROM */ +static void +ao_flash_read_block(void) +{ + ao_flash_wait_write(); + ao_flash_cs_low(); + ao_flash_instruction.instruction = FLASH_READ; + + /* 13/14 block bits + 9/8 byte bits (always 0) */ + ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift); + ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8); + ao_flash_instruction.address[2] = 0; + ao_spi_send(&ao_flash_instruction, 4); + ao_spi_recv(ao_flash_data, ao_flash_block_size); + ao_flash_cs_high(); +} + +static void +ao_flash_flush_internal(void) +{ + if (ao_flash_block_dirty) { + ao_flash_write_block(); + ao_flash_block_dirty = 0; + } +} + +static void +ao_flash_fill(uint16_t block) +{ + if (block != ao_flash_block) { + ao_flash_flush_internal(); + ao_flash_block = block; + ao_flash_read_block(); + } +} + +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); + + /* Transfer the data */ + ao_mutex_get(&ao_flash_mutex); { + if (len != ao_flash_block_size) + ao_flash_fill(block); + else { + ao_flash_flush_internal(); + ao_flash_block = block; + } + memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), + buf, + len); + ao_flash_block_dirty = 1; + } ao_mutex_put(&ao_flash_mutex); + return 1; +} + +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant +{ + uint16_t block = (uint16_t) (pos >> ao_flash_block_shift); + + /* Transfer the data */ + ao_mutex_get(&ao_flash_mutex); { + ao_flash_fill(block); + memcpy(buf, + ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), + len); + } ao_mutex_put(&ao_flash_mutex); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ + ao_mutex_get(&ao_flash_mutex); { + ao_flash_flush_internal(); + } ao_mutex_put(&ao_flash_mutex); +} + +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + ao_mutex_get(&ao_flash_mutex); { + ao_flash_flush_internal(); + ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift); + memset(ao_flash_data, 0xff, ao_flash_block_size); + ao_flash_block_dirty = 1; + } ao_mutex_put(&ao_flash_mutex); + return 1; +} + +void +ao_storage_device_info(void) __reentrant +{ + uint8_t status; + + ao_storage_setup(); + ao_mutex_get(&ao_flash_mutex); { + status = ao_flash_read_status(); + printf ("Flash status: 0x%02x\n", status); + printf ("Flash block shift: %d\n", ao_flash_block_shift); + printf ("Flash block size: %d\n", ao_flash_block_size); + printf ("Flash block mask: %d\n", ao_flash_block_mask); + printf ("Flash device size: %ld\n", ao_storage_total); + } ao_mutex_put(&ao_flash_mutex); +} + +/* + * To initialize the chip, set up the CS line and + * the SPI interface + */ +void +ao_storage_device_init(void) +{ + /* set up CS */ + FLASH_CS = 1; + P1DIR |= (1 << FLASH_CS_INDEX); + P1SEL &= ~(1 << FLASH_CS_INDEX); +} diff --git a/src/drivers/ao_at45db161d.h b/src/drivers/ao_at45db161d.h new file mode 100644 index 00000000..9ee6f1b6 --- /dev/null +++ b/src/drivers/ao_at45db161d.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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. + */ + +/* Defines for the Atmel AT45DB161D 16Mbit SPI Bus DataFlash® */ + +#ifndef _AT45DB161D_H_ +#define _AT45DB161D_H_ + +/* + * We reserve the last block on the device for + * configuration space. Writes and reads in this + * area return errors. + */ + + +#define FLASH_READ 0x03 +#define FLASH_WRITE 0x82 +#define FLASH_PAGE_ERASE 0x81 +#define FLASH_READ_STATUS 0xd7 +#define FLASH_SET_CONFIG 0x3d + +#define FLASH_SET_512_BYTE_0 0x2a +#define FLASH_SET_512_BYTE_1 0x80 +#define FLASH_SET_512_BYTE_2 0xa6 + +#define FLASH_STATUS_RDY (1 << 7) +#define FLASH_STATUS_COMP (1 << 6) +#define FLASH_STATUS_PROTECT (1 << 1) +#define FLASH_STATUS_PAGESIZE_512 (1 << 0) + +#endif /* _AT45DB161D_H_ */ diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c new file mode 100644 index 00000000..44155ec1 --- /dev/null +++ b/src/drivers/ao_btm.c @@ -0,0 +1,302 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +int8_t ao_btm_stdio; +__xdata uint8_t ao_btm_connected; + +#define AO_BTM_MAX_REPLY 16 +__xdata char ao_btm_reply[AO_BTM_MAX_REPLY]; + +extern volatile __xdata struct ao_fifo ao_usart1_rx_fifo; + +/* + * Read a line of data from the serial port, truncating + * it after a few characters. + */ + +uint8_t +ao_btm_get_line(void) +{ + uint8_t ao_btm_reply_len = 0; + char c; + + for (;;) { + + while ((c = ao_serial_pollchar()) != AO_READ_AGAIN) { + if (ao_btm_reply_len < sizeof (ao_btm_reply)) + ao_btm_reply[ao_btm_reply_len++] = c; + if (c == '\r' || c == '\n') + goto done; + } + for (c = 0; c < 10; c++) { + ao_delay(AO_MS_TO_TICKS(10)); + if (!ao_fifo_empty(ao_usart1_rx_fifo)) + break; + } + if (c == 10) + goto done; + } +done: + for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);) + ao_btm_reply[c++] = '\0'; + return ao_btm_reply_len; +} + +/* + * Drain the serial port completely + */ +void +ao_btm_drain() +{ + while (ao_btm_get_line()) + ; +} + +/* + * Set the stdio echo for the bluetooth link + */ +void +ao_btm_echo(uint8_t echo) +{ + ao_stdios[ao_btm_stdio].echo = echo; +} + +/* + * Delay between command charaters; the BT module + * can't keep up with 57600 baud + */ + +void +ao_btm_putchar(char c) +{ + ao_serial_putchar(c); + ao_delay(1); +} + +/* + * Wait for the bluetooth device to return + * status from the previously executed command + */ +uint8_t +ao_btm_wait_reply(void) +{ + for (;;) { + ao_btm_get_line(); + if (!strncmp(ao_btm_reply, "OK", 2)) + return 1; + if (!strncmp(ao_btm_reply, "ERROR", 5)) + return -1; + if (ao_btm_reply[0] == '\0') + return 0; + } +} + +void +ao_btm_string(__code char *cmd) +{ + char c; + + while (c = *cmd++) + ao_btm_putchar(c); +} + +uint8_t +ao_btm_cmd(__code char *cmd) +{ + ao_btm_drain(); + ao_btm_string(cmd); + return ao_btm_wait_reply(); +} + +uint8_t +ao_btm_set_name(void) +{ + char sn[8]; + char *s = sn + 8; + char c; + int n; + ao_btm_string("ATN=TeleBT-"); + *--s = '\0'; + *--s = '\r'; + n = ao_serial_number; + do { + *--s = '0' + n % 10; + } while (n /= 10); + while ((c = *s++)) + ao_btm_putchar(c); + return ao_btm_wait_reply(); +} + +uint8_t +ao_btm_try_speed(uint8_t speed) +{ + ao_serial_set_speed(speed); + ao_btm_drain(); + (void) ao_btm_cmd("\rATE0\rATQ0\r"); + if (ao_btm_cmd("AT\r") == 1) + return 1; + return 0; +} + +/* + * A thread to initialize the bluetooth device and + * hang around to blink the LED when connected + */ +void +ao_btm(void) +{ + /* + * Wait for the bluetooth device to boot + */ + ao_delay(AO_SEC_TO_TICKS(3)); + +#if HAS_BEEP + ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); +#endif + + /* + * The first time we connect, the BTM-180 comes up at 19200 baud. + * After that, it will remember and come up at 57600 baud. So, see + * if it is already running at 57600 baud, and if that doesn't work + * then tell it to switch to 57600 from 19200 baud. + */ + while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) { + ao_delay(AO_SEC_TO_TICKS(1)); + if (ao_btm_try_speed(AO_SERIAL_SPEED_19200)) + ao_btm_cmd("ATL4\r"); + ao_delay(AO_SEC_TO_TICKS(1)); + } + + /* Disable echo */ + ao_btm_cmd("ATE0\r"); + + /* Enable flow control */ + ao_btm_cmd("ATC1\r"); + + /* Set the reported name to something we can find on the host */ + ao_btm_set_name(); + + /* Turn off status reporting */ + ao_btm_cmd("ATQ1\r"); + + ao_btm_stdio = ao_add_stdio(ao_serial_pollchar, + ao_serial_putchar, + NULL); + ao_btm_echo(0); + + for (;;) { + while (!ao_btm_connected) + ao_sleep(&ao_btm_connected); + while (ao_btm_connected) { + ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20)); + ao_delay(AO_SEC_TO_TICKS(3)); + } + } +} + +__xdata struct ao_task ao_btm_task; + +#if BT_LINK_ON_P2 +#define BT_PICTL_ICON PICTL_P2ICON +#define BT_PIFG P2IFG +#define BT_PDIR P2DIR +#define BT_PINP P2INP +#define BT_IEN2_PIE IEN2_P2IE +#endif +#if BT_LINK_ON_P1 +#define BT_PICTL_ICON PICTL_P1ICON +#define BT_PIFG P1IFG +#define BT_PDIR P1DIR +#define BT_PINP P1INP +#define BT_IEN2_PIE IEN2_P1IE +#endif + +void +ao_btm_check_link() __critical +{ + /* Check the pin and configure the interrupt detector to wait for the + * pin to flip the other way + */ + if (BT_LINK_PIN) { + ao_btm_connected = 0; + PICTL |= BT_PICTL_ICON; + } else { + ao_btm_connected = 1; + PICTL &= ~BT_PICTL_ICON; + } +} + +void +ao_btm_isr(void) +#if BT_LINK_ON_P1 + __interrupt 15 +#endif +{ +#if BT_LINK_ON_P1 + P1IF = 0; +#endif + if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) { + ao_btm_check_link(); + ao_wakeup(&ao_btm_connected); + } + BT_PIFG = 0; +} + +void +ao_btm_init (void) +{ + ao_serial_init(); + ao_serial_set_speed(AO_SERIAL_SPEED_19200); + +#if BT_LINK_ON_P1 + /* + * Configure ser reset line + */ + + P1_6 = 0; + P1DIR |= (1 << 6); +#endif + + /* + * Configure link status line + */ + + /* Set pin to input */ + BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX); + + /* Set pin to tri-state */ + BT_PINP |= (1 << BT_LINK_PIN_INDEX); + + /* Enable interrupts */ + IEN2 |= BT_IEN2_PIE; + + /* Check current pin state */ + ao_btm_check_link(); + +#if BT_LINK_ON_P2 + /* Eable the pin interrupt */ + PICTL |= PICTL_P2IEN; +#endif +#if BT_LINK_ON_P1 + /* Enable pin interrupt */ + P1IEN |= (1 << BT_LINK_PIN_INDEX); +#endif + + ao_add_task(&ao_btm_task, ao_btm, "bt"); +} diff --git a/src/drivers/ao_companion.c b/src/drivers/ao_companion.c new file mode 100644 index 00000000..4c8f4269 --- /dev/null +++ b/src/drivers/ao_companion.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +#define ao_spi_slow() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ + UxGCR_CPHA_FIRST_EDGE | \ + UxGCR_ORDER_MSB | \ + (13 << UxGCR_BAUD_E_SHIFT))) + +#define ao_spi_fast() (U0GCR = (UxGCR_CPOL_NEGATIVE | \ + UxGCR_CPHA_FIRST_EDGE | \ + UxGCR_ORDER_MSB | \ + (17 << UxGCR_BAUD_E_SHIFT))) + +#define COMPANION_SELECT() do { ao_spi_get_bit(COMPANION_CS); ao_spi_slow(); } while (0) +#define COMPANION_DESELECT() do { ao_spi_fast(); ao_spi_put_bit(COMPANION_CS); } while (0) + +static __xdata struct ao_companion_command ao_companion_command; +__xdata struct ao_companion_setup ao_companion_setup; + +__xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS]; +__pdata uint8_t ao_companion_running; +__xdata uint8_t ao_companion_mutex; + +static void +ao_companion_send_command(uint8_t command) +{ + ao_companion_command.command = command; + ao_companion_command.flight_state = ao_flight_state; + ao_companion_command.tick = ao_time(); + ao_companion_command.serial = ao_serial_number; + ao_companion_command.flight = ao_flight_number; + ao_spi_send(&ao_companion_command, sizeof (ao_companion_command)); +} + +static uint8_t +ao_companion_get_setup(void) +{ + COMPANION_SELECT(); + ao_companion_send_command(AO_COMPANION_SETUP); + ao_spi_recv(&ao_companion_setup, sizeof (ao_companion_setup)); + COMPANION_DESELECT(); + return (ao_companion_setup.board_id == + ~ao_companion_setup.board_id_inverse); +} + +static void +ao_companion_get_data(void) +{ + COMPANION_SELECT(); + ao_companion_send_command(AO_COMPANION_FETCH); + ao_mutex_get(&ao_companion_mutex); + ao_spi_recv(&ao_companion_data, ao_companion_setup.channels * 2); + ao_mutex_put(&ao_companion_mutex); + COMPANION_DESELECT(); +} + +static void +ao_companion_notify(void) +{ + COMPANION_SELECT(); + ao_companion_send_command(AO_COMPANION_NOTIFY); + COMPANION_DESELECT(); +} + +void +ao_companion(void) +{ + uint8_t i; + while (!ao_flight_number) + ao_sleep(&ao_flight_number); + for (i = 0; i < 10; i++) { + ao_delay(AO_SEC_TO_TICKS(1)); + if ((ao_companion_running = ao_companion_get_setup())) + break; + } + while (ao_companion_running) { + ao_alarm(ao_companion_setup.update_period); + if (ao_sleep(DATA_TO_XDATA(&ao_flight_state))) + ao_companion_get_data(); + else + ao_companion_notify(); + } + ao_exit(); +} + +void +ao_companion_status(void) __reentrant +{ + uint8_t i; + printf("Companion running: %d\n", ao_companion_running); + printf("device: %d\n", ao_companion_setup.board_id); + printf("update period: %d\n", ao_companion_setup.update_period); + printf("channels: %d\n", ao_companion_setup.channels); + printf("data:"); + for(i = 0; i < ao_companion_setup.channels; i++) + printf(" %5u", ao_companion_data[i]); + printf("\n"); +} + +__code struct ao_cmds ao_companion_cmds[] = { + { ao_companion_status, "L\0Companion link status" }, + { 0, NULL }, +}; + +static __xdata struct ao_task ao_companion_task; + +void +ao_companion_init(void) +{ + COMPANION_CS_PORT |= COMPANION_CS_MASK; /* raise all CS pins */ + COMPANION_CS_DIR |= COMPANION_CS_MASK; /* set CS pins as outputs */ + COMPANION_CS_SEL &= ~COMPANION_CS_MASK; /* set CS pins as GPIO */ + + ao_cmd_register(&ao_companion_cmds[0]); + ao_add_task(&ao_companion_task, ao_companion, "companion"); +} diff --git a/src/drivers/ao_gps_sirf.c b/src/drivers/ao_gps_sirf.c new file mode 100644 index 00000000..f2abbf84 --- /dev/null +++ b/src/drivers/ao_gps_sirf.c @@ -0,0 +1,442 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef AO_GPS_TEST +#include "ao.h" +#endif + +__xdata uint8_t ao_gps_mutex; +__pdata uint16_t ao_gps_tick; +__xdata struct ao_telemetry_location ao_gps_data; +__xdata struct ao_telemetry_satellite ao_gps_tracking_data; + +static const char ao_gps_set_nmea[] = "\r\n$PSRF100,0,57600,8,1,0*37\r\n"; + +const char ao_gps_config[] = { + + 0xa0, 0xa2, 0x00, 0x0e, /* length: 14 bytes */ + 136, /* mode control */ + 0, 0, /* reserved */ + 0, /* degraded mode (allow 1-SV navigation) */ + 0, 0, /* reserved */ + 0, 0, /* user specified altitude */ + 2, /* alt hold mode (disabled, require 3d fixes) */ + 0, /* alt hold source (use last computed altitude) */ + 0, /* reserved */ + 10, /* Degraded time out (10 sec) */ + 10, /* Dead Reckoning time out (10 sec) */ + 0, /* Track smoothing (disabled) */ + 0x00, 0x8e, 0xb0, 0xb3, + + 0xa0, 0xa2, 0x00, 0x08, /* length: 8 bytes */ + 166, /* Set message rate */ + 2, /* enable/disable all messages */ + 0, /* message id (ignored) */ + 0, /* update rate (0 = disable) */ + 0, 0, 0, 0, /* reserved */ + 0x00, 0xa8, 0xb0, 0xb3, + + 0xa0, 0xa2, 0x00, 0x02, /* length: 2 bytes */ + 143, /* static navigation */ + 0, /* disable */ + 0x00, 0x8f, 0xb0, 0xb3, +}; + +#define NAV_TYPE_GPS_FIX_TYPE_MASK (7 << 0) +#define NAV_TYPE_NO_FIX (0 << 0) +#define NAV_TYPE_SV_KF (1 << 0) +#define NAV_TYPE_2_SV_KF (2 << 0) +#define NAV_TYPE_3_SV_KF (3 << 0) +#define NAV_TYPE_4_SV_KF (4 << 0) +#define NAV_TYPE_2D_LEAST_SQUARES (5 << 0) +#define NAV_TYPE_3D_LEAST_SQUARES (6 << 0) +#define NAV_TYPE_DR (7 << 0) +#define NAV_TYPE_TRICKLE_POWER (1 << 3) +#define NAV_TYPE_ALTITUDE_HOLD_MASK (3 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_NONE (0 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_KF (1 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_USER (2 << 4) +#define NAV_TYPE_ALTITUDE_HOLD_ALWAYS (3 << 4) +#define NAV_TYPE_DOP_LIMIT_EXCEEDED (1 << 6) +#define NAV_TYPE_DGPS_APPLIED (1 << 7) +#define NAV_TYPE_SENSOR_DR (1 << 8) +#define NAV_TYPE_OVERDETERMINED (1 << 9) +#define NAV_TYPE_DR_TIMEOUT_EXCEEDED (1 << 10) +#define NAV_TYPE_FIX_MI_EDIT (1 << 11) +#define NAV_TYPE_INVALID_VELOCITY (1 << 12) +#define NAV_TYPE_ALTITUDE_HOLD_DISABLED (1 << 13) +#define NAV_TYPE_DR_ERROR_STATUS_MASK (3 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_GPS_ONLY (0 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_DR_FROM_GPS (1 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_DR_SENSOR_ERROR (2 << 14) +#define NAV_TYPE_DR_ERROR_STATUS_DR_IN_TEST (3 << 14) + +struct sirf_geodetic_nav_data { + uint16_t nav_type; + uint16_t utc_year; + uint8_t utc_month; + uint8_t utc_day; + uint8_t utc_hour; + uint8_t utc_minute; + uint16_t utc_second; + int32_t lat; + int32_t lon; + int32_t alt_msl; + uint16_t ground_speed; + uint16_t course; + int16_t climb_rate; + uint32_t h_error; + uint32_t v_error; + uint8_t num_sv; + uint8_t hdop; +}; + +static __xdata struct sirf_geodetic_nav_data ao_sirf_data; + +struct sirf_measured_sat_data { + uint8_t svid; + uint8_t c_n_1; +}; + +struct sirf_measured_tracker_data { + int16_t gps_week; + uint32_t gps_tow; + uint8_t channels; + struct sirf_measured_sat_data sats[12]; +}; + +static __xdata struct sirf_measured_tracker_data ao_sirf_tracker_data; + +static __pdata uint16_t ao_sirf_cksum; +static __pdata uint16_t ao_sirf_len; + +#define ao_sirf_byte() ((uint8_t) ao_serial_getchar()) + +static uint8_t data_byte(void) +{ + uint8_t c = ao_sirf_byte(); + --ao_sirf_len; + ao_sirf_cksum += c; + return c; +} + +static char __xdata *sirf_target; + +static void sirf_u16(uint8_t offset) +{ + uint16_t __xdata *ptr = (uint16_t __xdata *) (sirf_target + offset); + uint16_t val; + + val = data_byte() << 8; + val |= data_byte (); + *ptr = val; +} + +static void sirf_u8(uint8_t offset) +{ + uint8_t __xdata *ptr = (uint8_t __xdata *) (sirf_target + offset); + uint8_t val; + + val = data_byte (); + *ptr = val; +} + +static void sirf_u32(uint8_t offset) __reentrant +{ + uint32_t __xdata *ptr = (uint32_t __xdata *) (sirf_target + offset); + uint32_t val; + + val = ((uint32_t) data_byte ()) << 24; + val |= ((uint32_t) data_byte ()) << 16; + val |= ((uint32_t) data_byte ()) << 8; + val |= ((uint32_t) data_byte ()); + *ptr = val; +} + +static void sirf_discard(uint8_t len) +{ + while (len--) + data_byte(); +} + +#define SIRF_END 0 +#define SIRF_DISCARD 1 +#define SIRF_U8 2 +#define SIRF_U16 3 +#define SIRF_U32 4 +#define SIRF_U8X10 5 + +struct sirf_packet_parse { + uint8_t type; + uint8_t offset; +}; + +static void +ao_sirf_parse(void __xdata *target, const struct sirf_packet_parse *parse) __reentrant +{ + uint8_t i, offset, j; + + sirf_target = target; + for (i = 0; ; i++) { + offset = parse[i].offset; + switch (parse[i].type) { + case SIRF_END: + return; + case SIRF_DISCARD: + sirf_discard(offset); + break; + case SIRF_U8: + sirf_u8(offset); + break; + case SIRF_U16: + sirf_u16(offset); + break; + case SIRF_U32: + sirf_u32(offset); + break; + case SIRF_U8X10: + for (j = 10; j--;) + sirf_u8(offset++); + break; + } + } +} + +static const struct sirf_packet_parse geodetic_nav_data_packet[] = { + { SIRF_DISCARD, 2 }, /* 1 nav valid */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, nav_type) }, /* 3 */ + { SIRF_DISCARD, 6 }, /* 5 week number, time of week */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_year) }, /* 11 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_month) }, /* 13 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_day) }, /* 14 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_hour) }, /* 15 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_minute) }, /* 16 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_second) }, /* 17 */ + { SIRF_DISCARD, 4 }, /* satellite id list */ /* 19 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lat) }, /* 23 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lon) }, /* 27 */ + { SIRF_DISCARD, 4 }, /* altitude from ellipsoid */ /* 31 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, alt_msl) }, /* 35 */ + { SIRF_DISCARD, 1 }, /* map datum */ /* 39 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, ground_speed) }, /* 40 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, course) }, /* 42 */ + { SIRF_DISCARD, 2 }, /* magnetic variation */ /* 44 */ + { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, climb_rate) }, /* 46 */ + { SIRF_DISCARD, 2 }, /* turn rate */ /* 48 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, h_error) }, /* 50 */ + { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, v_error) }, /* 54 */ + { SIRF_DISCARD, 30 }, /* time error, h_vel error, clock_bias, + clock bias error, clock drift, + clock drift error, distance, + distance error, heading error */ /* 58 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, num_sv) }, /* 88 */ + { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, hdop) }, /* 89 */ + { SIRF_DISCARD, 1 }, /* additional mode info */ /* 90 */ + { SIRF_END, 0 }, /* 91 */ +}; + +static void +ao_sirf_parse_41(void) __reentrant +{ + ao_sirf_parse(&ao_sirf_data, geodetic_nav_data_packet); +} + +static const struct sirf_packet_parse measured_tracker_data_packet[] = { + { SIRF_U16, offsetof (struct sirf_measured_tracker_data, gps_week) }, /* 1 week */ + { SIRF_U32, offsetof (struct sirf_measured_tracker_data, gps_tow) }, /* 3 time of week */ + { SIRF_U8, offsetof (struct sirf_measured_tracker_data, channels) }, /* 7 channels */ + { SIRF_END, 0 }, +}; + +static const struct sirf_packet_parse measured_sat_data_packet[] = { + { SIRF_U8, offsetof (struct sirf_measured_sat_data, svid) }, /* 0 SV id */ + { SIRF_DISCARD, 4 }, /* 1 azimuth, 2 elevation, 3 state */ + { SIRF_U8, offsetof (struct sirf_measured_sat_data, c_n_1) }, /* C/N0 1 */ + { SIRF_DISCARD, 9 }, /* C/N0 2-10 */ + { SIRF_END, 0 }, +}; + +static void +ao_sirf_parse_4(void) __reentrant +{ + uint8_t i; + ao_sirf_parse(&ao_sirf_tracker_data, measured_tracker_data_packet); + for (i = 0; i < 12; i++) + ao_sirf_parse(&ao_sirf_tracker_data.sats[i], measured_sat_data_packet); +} + +static void +ao_gps_setup(void) __reentrant +{ + uint8_t i, k; + ao_serial_set_speed(AO_SERIAL_SPEED_4800); + for (i = 0; i < 64; i++) + ao_serial_putchar(0x00); + for (k = 0; k < 3; k++) + for (i = 0; i < sizeof (ao_gps_set_nmea); i++) + ao_serial_putchar(ao_gps_set_nmea[i]); + ao_serial_set_speed(AO_SERIAL_SPEED_57600); + for (i = 0; i < 64; i++) + ao_serial_putchar(0x00); +} + +static const char ao_gps_set_message_rate[] = { + 0xa0, 0xa2, 0x00, 0x08, + 166, + 0, +}; + +void +ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant +{ + uint16_t cksum = 0x00a6; + uint8_t i; + + for (i = 0; i < sizeof (ao_gps_set_message_rate); i++) + ao_serial_putchar(ao_gps_set_message_rate[i]); + ao_serial_putchar(msg); + ao_serial_putchar(rate); + cksum = 0xa6 + msg + rate; + for (i = 0; i < 4; i++) + ao_serial_putchar(0); + ao_serial_putchar((cksum >> 8) & 0x7f); + ao_serial_putchar(cksum & 0xff); + ao_serial_putchar(0xb0); + ao_serial_putchar(0xb3); +} + +static const uint8_t sirf_disable[] = { + 2, + 9, + 10, + 27, + 50, + 52, +}; + +void +ao_gps(void) __reentrant +{ + uint8_t i, k; + uint16_t cksum; + + ao_gps_setup(); + for (k = 0; k < 5; k++) + { + for (i = 0; i < sizeof (ao_gps_config); i++) + ao_serial_putchar(ao_gps_config[i]); + for (i = 0; i < sizeof (sirf_disable); i++) + ao_sirf_set_message_rate(sirf_disable[i], 0); + ao_sirf_set_message_rate(41, 1); + ao_sirf_set_message_rate(4, 1); + } + for (;;) { + /* Locate the begining of the next record */ + while (ao_sirf_byte() != (uint8_t) 0xa0) + ; + if (ao_sirf_byte() != (uint8_t) 0xa2) + continue; + + /* Length */ + ao_sirf_len = ao_sirf_byte() << 8; + ao_sirf_len |= ao_sirf_byte(); + if (ao_sirf_len > 1023) + continue; + + ao_sirf_cksum = 0; + + /* message ID */ + i = data_byte (); /* 0 */ + + switch (i) { + case 41: + if (ao_sirf_len < 90) + break; + ao_sirf_parse_41(); + break; + case 4: + if (ao_sirf_len < 187) + break; + ao_sirf_parse_4(); + break; + } + if (ao_sirf_len != 0) + continue; + + /* verify checksum and end sequence */ + ao_sirf_cksum &= 0x7fff; + cksum = ao_sirf_byte() << 8; + cksum |= ao_sirf_byte(); + if (ao_sirf_cksum != cksum) + continue; + if (ao_sirf_byte() != (uint8_t) 0xb0) + continue; + if (ao_sirf_byte() != (uint8_t) 0xb3) + continue; + + switch (i) { + case 41: + ao_mutex_get(&ao_gps_mutex); + ao_gps_tick = ao_time(); + ao_gps_data.hour = ao_sirf_data.utc_hour; + ao_gps_data.minute = ao_sirf_data.utc_minute; + ao_gps_data.second = ao_sirf_data.utc_second / 1000; + ao_gps_data.flags = ((ao_sirf_data.num_sv << AO_GPS_NUM_SAT_SHIFT) & AO_GPS_NUM_SAT_MASK) | AO_GPS_RUNNING; + if ((ao_sirf_data.nav_type & NAV_TYPE_GPS_FIX_TYPE_MASK) >= NAV_TYPE_4_SV_KF) + ao_gps_data.flags |= AO_GPS_VALID; + ao_gps_data.latitude = ao_sirf_data.lat; + ao_gps_data.longitude = ao_sirf_data.lon; + ao_gps_data.altitude = ao_sirf_data.alt_msl / 100; + ao_gps_data.ground_speed = ao_sirf_data.ground_speed; + ao_gps_data.course = ao_sirf_data.course / 200; + ao_gps_data.hdop = ao_sirf_data.hdop; + ao_gps_data.climb_rate = ao_sirf_data.climb_rate; + ao_gps_data.flags |= AO_GPS_COURSE_VALID; +#if 0 + if (ao_sirf_data.h_error > 6553500) + ao_gps_data.h_error = 65535; + else + ao_gps_data.h_error = ao_sirf_data.h_error / 100; + if (ao_sirf_data.v_error > 6553500) + ao_gps_data.v_error = 65535; + else + ao_gps_data.v_error = ao_sirf_data.v_error / 100; +#endif + ao_mutex_put(&ao_gps_mutex); + ao_wakeup(&ao_gps_data); + break; + case 4: + ao_mutex_get(&ao_gps_mutex); + ao_gps_tracking_data.channels = ao_sirf_tracker_data.channels; + for (i = 0; i < 12; i++) { + ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid; + ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1; + } + ao_mutex_put(&ao_gps_mutex); + ao_wakeup(&ao_gps_tracking_data); + break; + } + } +} + +__xdata struct ao_task ao_gps_task; + +void +ao_gps_init(void) +{ + ao_add_task(&ao_gps_task, ao_gps, "gps"); +} diff --git a/src/drivers/ao_gps_skytraq.c b/src/drivers/ao_gps_skytraq.c new file mode 100644 index 00000000..7ac26946 --- /dev/null +++ b/src/drivers/ao_gps_skytraq.c @@ -0,0 +1,490 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef AO_GPS_TEST +#include "ao.h" +#endif + +#define AO_GPS_LEADER 2 + +static __code char ao_gps_header[] = "GP"; + +__xdata uint8_t ao_gps_mutex; +static __data char ao_gps_char; +static __pdata uint8_t ao_gps_cksum; +static __pdata uint8_t ao_gps_error; + +__pdata uint16_t ao_gps_tick; +__xdata struct ao_telemetry_location ao_gps_data; +__xdata struct ao_telemetry_satellite ao_gps_tracking_data; + +static __pdata uint16_t ao_gps_next_tick; +static __xdata struct ao_telemetry_location ao_gps_next; +static __pdata uint8_t ao_gps_date_flags; +static __xdata struct ao_telemetry_satellite ao_gps_tracking_next; + +#define STQ_S 0xa0, 0xa1 +#define STQ_E 0x0d, 0x0a +#define SKYTRAQ_MSG_2(id,a,b) \ + STQ_S, 0, 3, id, a,b, (id^a^b), STQ_E +#define SKYTRAQ_MSG_3(id,a,b,c) \ + STQ_S, 0, 4, id, a,b,c, (id^a^b^c), STQ_E +#define SKYTRAQ_MSG_8(id,a,b,c,d,e,f,g,h) \ + STQ_S, 0, 9, id, a,b,c,d,e,f,g,h, (id^a^b^c^d^e^f^g^h), STQ_E +#define SKYTRAQ_MSG_14(id,a,b,c,d,e,f,g,h,i,j,k,l,m,n) \ + STQ_S, 0,15, id, a,b,c,d,e,f,g,h,i,j,k,l,m,n, \ + (id^a^b^c^d^e^f^g^h^i^j^k^l^m^n), STQ_E + +static __code uint8_t ao_gps_config[] = { + SKYTRAQ_MSG_8(0x08, 1, 1, 1, 1, 1, 1, 1, 0), /* configure nmea */ + /* gga interval */ + /* gsa interval */ + /* gsv interval */ + /* gll interval */ + /* rmc interval */ + /* vtg interval */ + /* zda interval */ + /* attributes (0 = update to sram, 1 = update flash too) */ + + SKYTRAQ_MSG_2(0x3c, 0x00, 0x00), /* configure navigation mode */ + /* 0 = car, 1 = pedestrian */ + /* 0 = update to sram, 1 = update sram + flash */ +}; + +static void +ao_gps_lexchar(void) +{ + if (ao_gps_error) + ao_gps_char = '\n'; + else + ao_gps_char = ao_serial_getchar(); + ao_gps_cksum ^= ao_gps_char; +} + +void +ao_gps_skip_field(void) +{ + while (ao_gps_char != ',' && ao_gps_char != '*' && ao_gps_char != '\n') + ao_gps_lexchar(); +} + +void +ao_gps_skip_sep(void) +{ + if (ao_gps_char == ',' || ao_gps_char == '.' || ao_gps_char == '*') + ao_gps_lexchar(); +} + +__pdata static uint8_t ao_gps_num_width; + +static int16_t +ao_gps_decimal(uint8_t max_width) +{ + int16_t v; + __pdata uint8_t neg = 0; + + ao_gps_skip_sep(); + if (ao_gps_char == '-') { + neg = 1; + ao_gps_lexchar(); + } + v = 0; + ao_gps_num_width = 0; + while (ao_gps_num_width < max_width) { + if (ao_gps_char < '0' || '9' < ao_gps_char) + break; + v = v * (int16_t) 10 + ao_gps_char - '0'; + ao_gps_num_width++; + ao_gps_lexchar(); + } + if (neg) + v = -v; + return v; +} + +static uint8_t +ao_gps_hex(uint8_t max_width) +{ + uint8_t v, d; + + ao_gps_skip_sep(); + v = 0; + ao_gps_num_width = 0; + while (ao_gps_num_width < max_width) { + if ('0' <= ao_gps_char && ao_gps_char <= '9') + d = ao_gps_char - '0'; + else if ('A' <= ao_gps_char && ao_gps_char <= 'F') + d = ao_gps_char - 'A' + 10; + else if ('a' <= ao_gps_char && ao_gps_char <= 'f') + d = ao_gps_char - 'a' + 10; + else + break; + v = (v << 4) | d; + ao_gps_num_width++; + ao_gps_lexchar(); + } + return v; +} + +static int32_t +ao_gps_parse_pos(uint8_t deg_width) __reentrant +{ + int32_t d; + int32_t m; + int32_t f; + + d = ao_gps_decimal(deg_width); + m = ao_gps_decimal(2); + if (ao_gps_char == '.') { + f = ao_gps_decimal(4); + while (ao_gps_num_width < 4) { + f *= 10; + ao_gps_num_width++; + } + } else { + f = 0; + if (ao_gps_char != ',') + ao_gps_error = 1; + } + d = d * 10000000l; + m = m * 10000l + f; + d = d + m * 50 / 3; + return d; +} + +static uint8_t +ao_gps_parse_flag(char no_c, char yes_c) __reentrant +{ + uint8_t ret = 0; + ao_gps_skip_sep(); + if (ao_gps_char == yes_c) + ret = 1; + else if (ao_gps_char == no_c) + ret = 0; + else + ao_gps_error = 1; + ao_gps_lexchar(); + return ret; +} + +static void +ao_nmea_gga() +{ + uint8_t i; + + /* Now read the data into the gps data record + * + * $GPGGA,025149.000,4528.1723,N,12244.2480,W,1,05,2.0,103.5,M,-19.5,M,,0000*66 + * + * Essential fix data + * + * 025149.000 time (02:51:49.000 GMT) + * 4528.1723,N Latitude 45°28.1723' N + * 12244.2480,W Longitude 122°44.2480' W + * 1 Fix quality: + * 0 = invalid + * 1 = GPS fix (SPS) + * 2 = DGPS fix + * 3 = PPS fix + * 4 = Real Time Kinematic + * 5 = Float RTK + * 6 = estimated (dead reckoning) + * 7 = Manual input mode + * 8 = Simulation mode + * 05 Number of satellites (5) + * 2.0 Horizontal dilution + * 103.5,M Altitude, 103.5M above msl + * -19.5,M Height of geoid above WGS84 ellipsoid + * ? time in seconds since last DGPS update + * 0000 DGPS station ID + * *66 checksum + */ + + ao_gps_next_tick = ao_time(); + ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags; + ao_gps_next.hour = ao_gps_decimal(2); + ao_gps_next.minute = ao_gps_decimal(2); + ao_gps_next.second = ao_gps_decimal(2); + ao_gps_skip_field(); /* skip seconds fraction */ + + ao_gps_next.latitude = ao_gps_parse_pos(2); + if (ao_gps_parse_flag('N', 'S')) + ao_gps_next.latitude = -ao_gps_next.latitude; + ao_gps_next.longitude = ao_gps_parse_pos(3); + if (ao_gps_parse_flag('E', 'W')) + ao_gps_next.longitude = -ao_gps_next.longitude; + + i = ao_gps_decimal(0xff); + if (i == 1) + ao_gps_next.flags |= AO_GPS_VALID; + + i = ao_gps_decimal(0xff) << AO_GPS_NUM_SAT_SHIFT; + if (i > AO_GPS_NUM_SAT_MASK) + i = AO_GPS_NUM_SAT_MASK; + ao_gps_next.flags |= i; + + ao_gps_lexchar(); + i = ao_gps_decimal(0xff); + if (i <= 50) { + i = (uint8_t) 5 * i; + if (ao_gps_char == '.') + i = (i + ((uint8_t) ao_gps_decimal(1) >> 1)); + } else + i = 255; + ao_gps_next.hdop = i; + ao_gps_skip_field(); + + ao_gps_next.altitude = ao_gps_decimal(0xff); + ao_gps_skip_field(); /* skip any fractional portion */ + + /* Skip remaining fields */ + while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + if (ao_gps_char == '*') { + uint8_t cksum = ao_gps_cksum ^ '*'; + if (cksum != ao_gps_hex(2)) + ao_gps_error = 1; + } else + ao_gps_error = 1; + if (!ao_gps_error) { + ao_mutex_get(&ao_gps_mutex); + ao_gps_tick = ao_gps_next_tick; + memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data)); + ao_mutex_put(&ao_gps_mutex); + ao_wakeup(&ao_gps_data); + } +} + +static void +ao_nmea_gsv(void) +{ + char c; + uint8_t i; + uint8_t done; + /* Now read the data into the GPS tracking data record + * + * $GPGSV,3,1,12,05,54,069,45,12,44,061,44,21,07,184,46,22,78,289,47*72 + * + * Satellites in view data + * + * 3 Total number of GSV messages + * 1 Sequence number of current GSV message + * 12 Total sats in view (0-12) + * 05 SVID + * 54 Elevation + * 069 Azimuth + * 45 C/N0 in dB + * ... other SVIDs + * 72 checksum + */ + c = ao_gps_decimal(1); /* total messages */ + i = ao_gps_decimal(1); /* message sequence */ + if (i == 1) { + ao_gps_tracking_next.channels = 0; + } + done = (uint8_t) c == i; + ao_gps_lexchar(); + ao_gps_skip_field(); /* sats in view */ + while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { + i = ao_gps_tracking_next.channels; + c = ao_gps_decimal(2); /* SVID */ + if (i < AO_MAX_GPS_TRACKING) + ao_gps_tracking_next.sats[i].svid = c; + ao_gps_lexchar(); + ao_gps_skip_field(); /* elevation */ + ao_gps_lexchar(); + ao_gps_skip_field(); /* azimuth */ + c = ao_gps_decimal(2); /* C/N0 */ + if (i < AO_MAX_GPS_TRACKING) { + if ((ao_gps_tracking_next.sats[i].c_n_1 = c) != 0) + ao_gps_tracking_next.channels = i + 1; + } + } + if (ao_gps_char == '*') { + uint8_t cksum = ao_gps_cksum ^ '*'; + if (cksum != ao_gps_hex(2)) + ao_gps_error = 1; + } + else + ao_gps_error = 1; + if (ao_gps_error) + ao_gps_tracking_next.channels = 0; + else if (done) { + ao_mutex_get(&ao_gps_mutex); + memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, + sizeof(ao_gps_tracking_data)); + ao_mutex_put(&ao_gps_mutex); + ao_wakeup(&ao_gps_tracking_data); + } +} + +static void +ao_nmea_rmc(void) +{ + char a, c; + uint8_t i; + /* Parse the RMC record to read out the current date */ + + /* $GPRMC,111636.932,A,2447.0949,N,12100.5223,E,000.0,000.0,030407,,,A*61 + * + * Recommended Minimum Specific GNSS Data + * + * 111636.932 UTC time 11:16:36.932 + * A Data Valid (V = receiver warning) + * 2447.0949 Latitude + * N North/south indicator + * 12100.5223 Longitude + * E East/west indicator + * 000.0 Speed over ground + * 000.0 Course over ground + * 030407 UTC date (ddmmyy format) + * A Mode indicator: + * N = data not valid + * A = autonomous mode + * D = differential mode + * E = estimated (dead reckoning) mode + * M = manual input mode + * S = simulator mode + * 61 checksum + */ + ao_gps_skip_field(); + for (i = 0; i < 8; i++) { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + a = ao_gps_decimal(2); + c = ao_gps_decimal(2); + i = ao_gps_decimal(2); + /* Skip remaining fields */ + while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + if (ao_gps_char == '*') { + uint8_t cksum = ao_gps_cksum ^ '*'; + if (cksum != ao_gps_hex(2)) + ao_gps_error = 1; + } else + ao_gps_error = 1; + if (!ao_gps_error) { + ao_gps_next.year = i; + ao_gps_next.month = c; + ao_gps_next.day = a; + ao_gps_date_flags = AO_GPS_DATE_VALID; + } +} + +#define ao_skytraq_sendstruct(s) ao_skytraq_sendbytes((s), sizeof(s)) + +static void +ao_skytraq_sendbytes(__code uint8_t *b, uint8_t l) +{ + while (l--) { + uint8_t c = *b++; + if (c == 0xa0) + ao_delay(AO_MS_TO_TICKS(500)); + ao_serial_putchar(c); + } +} + +static void +ao_gps_nmea_parse(void) +{ + uint8_t a, b, c; + + ao_gps_cksum = 0; + ao_gps_error = 0; + + for (a = 0; a < AO_GPS_LEADER; a++) { + ao_gps_lexchar(); + if (ao_gps_char != ao_gps_header[a]) + return; + } + + ao_gps_lexchar(); + a = ao_gps_char; + ao_gps_lexchar(); + b = ao_gps_char; + ao_gps_lexchar(); + c = ao_gps_char; + ao_gps_lexchar(); + + if (ao_gps_char != ',') + return; + + if (a == (uint8_t) 'G' && b == (uint8_t) 'G' && c == (uint8_t) 'A') { + ao_nmea_gga(); + } else if (a == (uint8_t) 'G' && b == (uint8_t) 'S' && c == (uint8_t) 'V') { + ao_nmea_gsv(); + } else if (a == (uint8_t) 'R' && b == (uint8_t) 'M' && c == (uint8_t) 'C') { + ao_nmea_rmc(); + } +} + +void +ao_gps(void) __reentrant +{ + ao_serial_set_speed(AO_SERIAL_SPEED_9600); + + /* give skytraq time to boot in case of cold start */ + ao_delay(AO_MS_TO_TICKS(2000)); + + ao_skytraq_sendstruct(ao_gps_config); + + for (;;) { + /* Locate the begining of the next record */ + if (ao_serial_getchar() == '$') { + ao_gps_nmea_parse(); + } + + } +} + +__xdata struct ao_task ao_gps_task; + +static void +gps_dump(void) __reentrant +{ + uint8_t i; + ao_mutex_get(&ao_gps_mutex); + printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day); + printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second); + printf ("Lat/Lon: %ld %ld\n", ao_gps_data.latitude, ao_gps_data.longitude); + printf ("Alt: %d\n", ao_gps_data.altitude); + printf ("Flags: 0x%x\n", ao_gps_data.flags); + printf ("Sats: %d", ao_gps_tracking_data.channels); + for (i = 0; i < ao_gps_tracking_data.channels; i++) + printf (" %d %d", + ao_gps_tracking_data.sats[i].svid, + ao_gps_tracking_data.sats[i].c_n_1); + printf ("\ndone\n"); + ao_mutex_put(&ao_gps_mutex); +} + +__code struct ao_cmds ao_gps_cmds[] = { + { gps_dump, "g\0Display GPS" }, + { 0, NULL }, +}; + +void +ao_gps_init(void) +{ + ao_add_task(&ao_gps_task, ao_gps, "gps"); + ao_cmd_register(&ao_gps_cmds[0]); +} diff --git a/src/drivers/ao_m25.c b/src/drivers/ao_m25.c new file mode 100644 index 00000000..d7208273 --- /dev/null +++ b/src/drivers/ao_m25.c @@ -0,0 +1,380 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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 "ao.h" + +/* Total bytes of available storage */ +__pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +__pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +__pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +__pdata uint16_t ao_storage_unit; + +/* + * Each flash chip is arranged in 64kB sectors; the + * chip cannot erase in units smaller than that. + * + * Writing happens in units of 256 byte pages and + * can only change bits from 1 to 0. So, you can rewrite + * the same contents, or append to an existing page easily enough + */ + +#define M25_WREN 0x06 /* Write Enable */ +#define M25_WRDI 0x04 /* Write Disable */ +#define M25_RDID 0x9f /* Read Identification */ +#define M25_RDSR 0x05 /* Read Status Register */ +#define M25_WRSR 0x01 /* Write Status Register */ +#define M25_READ 0x03 /* Read Data Bytes */ +#define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define M25_PP 0x02 /* Page Program */ +#define M25_SE 0xd8 /* Sector Erase */ +#define M25_BE 0xc7 /* Bulk Erase */ +#define M25_DP 0xb9 /* Deep Power-down */ + +/* RDID response */ +#define M25_MANUF_OFFSET 0 +#define M25_MEMORY_TYPE_OFFSET 1 +#define M25_CAPACITY_OFFSET 2 +#define M25_UID_OFFSET 3 +#define M25_CFI_OFFSET 4 +#define M25_RDID_LEN 4 /* that's all we need */ + +#define M25_CAPACITY_128KB 0x11 +#define M25_CAPACITY_256KB 0x12 +#define M25_CAPACITY_512KB 0x13 +#define M25_CAPACITY_1MB 0x14 +#define M25_CAPACITY_2MB 0x15 + +/* + * Status register bits + */ + +#define M25_STATUS_SRWD (1 << 7) /* Status register write disable */ +#define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */ +#define M25_STATUS_BP_SHIFT (2) +#define M25_STATUS_WEL (1 << 1) /* Write enable latch */ +#define M25_STATUS_WIP (1 << 0) /* Write in progress */ + +/* + * On teleterra, the m25 chip select pins are + * wired on P0_0 through P0_3. + */ + +#if M25_MAX_CHIPS > 1 +static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */ +static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */ +static uint8_t ao_m25_numchips; /* number of chips detected */ +#endif +static uint8_t ao_m25_total; /* total sectors available */ +static uint8_t ao_m25_wip; /* write in progress */ + +static __xdata uint8_t ao_m25_mutex; + +/* + * This little array is abused to send and receive data. A particular + * caution -- the read and write addresses are written into the last + * three bytes of the array by ao_m25_set_page_address and then the + * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither + * of which touch those last three bytes. + */ + +static __xdata uint8_t ao_m25_instruction[4]; + +#define M25_SELECT(cs) ao_spi_get_mask(SPI_CS_PORT,cs) +#define M25_DESELECT(cs) ao_spi_put_mask(SPI_CS_PORT,cs) + +#define M25_BLOCK_SHIFT 16 +#define M25_BLOCK 65536L +#define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT)) +#define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT) + +/* + * Block until the specified chip is done writing + */ +static void +ao_m25_wait_wip(uint8_t cs) +{ + if (ao_m25_wip & cs) { + M25_SELECT(cs); + ao_m25_instruction[0] = M25_RDSR; + ao_spi_send(ao_m25_instruction, 1); + do { + ao_spi_recv(ao_m25_instruction, 1); + } while (ao_m25_instruction[0] & M25_STATUS_WIP); + M25_DESELECT(cs); + ao_m25_wip &= ~cs; + } +} + +/* + * Set the write enable latch so that page program and sector + * erase commands will work. Also mark the chip as busy writing + * so that future operations will block until the WIP bit goes off + */ +static void +ao_m25_write_enable(uint8_t cs) +{ + M25_SELECT(cs); + ao_m25_instruction[0] = M25_WREN; + ao_spi_send(&ao_m25_instruction, 1); + M25_DESELECT(cs); + ao_m25_wip |= cs; +} + + +/* + * Returns the number of 64kB sectors + */ +static uint8_t +ao_m25_read_capacity(uint8_t cs) +{ + uint8_t capacity; + M25_SELECT(cs); + ao_m25_instruction[0] = M25_RDID; + ao_spi_send(ao_m25_instruction, 1); + ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); + M25_DESELECT(cs); + + /* Check to see if the chip is present */ + if (ao_m25_instruction[0] == 0xff) + return 0; + capacity = ao_m25_instruction[M25_CAPACITY_OFFSET]; + + /* Sanity check capacity number */ + if (capacity < 0x11 || 0x1f < capacity) + return 0; + return 1 << (capacity - 0x10); +} + +static uint8_t +ao_m25_set_address(uint32_t pos) +{ + uint8_t chip; +#if M25_MAX_CHIPS > 1 + uint8_t size; + + for (chip = 0; chip < ao_m25_numchips; chip++) { + size = ao_m25_size[chip]; + if (M25_POS_TO_SECTOR(pos) < size) + break; + pos -= M25_SECTOR_TO_POS(size); + } + if (chip == ao_m25_numchips) + return 0xff; + + chip = ao_m25_pin[chip]; +#else + chip = M25_CS_MASK; +#endif + ao_m25_wait_wip(chip); + + ao_m25_instruction[1] = pos >> 16; + ao_m25_instruction[2] = pos >> 8; + ao_m25_instruction[3] = pos; + return chip; +} + +/* + * Scan the possible chip select lines + * to see which flash chips are connected + */ +static uint8_t +ao_m25_scan(void) +{ +#if M25_MAX_CHIPS > 1 + uint8_t pin, size; +#endif + + if (ao_m25_total) + return 1; + +#if M25_MAX_CHIPS > 1 + ao_m25_numchips = 0; + for (pin = 1; pin != 0; pin <<= 1) { + if (M25_CS_MASK & pin) { + size = ao_m25_read_capacity(pin); + if (size != 0) { + ao_m25_size[ao_m25_numchips] = size; + ao_m25_pin[ao_m25_numchips] = pin; + ao_m25_total += size; + ao_m25_numchips++; + } + } + } +#else + ao_m25_total = ao_m25_read_capacity(M25_CS_MASK); +#endif + if (!ao_m25_total) + return 0; + ao_storage_total = M25_SECTOR_TO_POS(ao_m25_total); + ao_storage_block = M25_BLOCK; + ao_storage_config = ao_storage_total - M25_BLOCK; + ao_storage_unit = 256; + return 1; +} + +/* + * Erase the specified sector + */ +uint8_t +ao_storage_erase(uint32_t pos) __reentrant +{ + uint8_t cs; + + if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total) + return 0; + + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + + cs = ao_m25_set_address(pos); + + ao_m25_wait_wip(cs); + ao_m25_write_enable(cs); + + ao_m25_instruction[0] = M25_SE; + M25_SELECT(cs); + ao_spi_send(ao_m25_instruction, 4); + M25_DESELECT(cs); + ao_m25_wip |= cs; + + ao_mutex_put(&ao_m25_mutex); + return 1; +} + +/* + * Write to flash + */ +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant +{ + uint8_t cs; + + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + + cs = ao_m25_set_address(pos); + ao_m25_write_enable(cs); + + ao_m25_instruction[0] = M25_PP; + M25_SELECT(cs); + ao_spi_send(ao_m25_instruction, 4); + ao_spi_send(d, len); + M25_DESELECT(cs); + + ao_mutex_put(&ao_m25_mutex); + return 1; +} + +/* + * Read from flash + */ +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant +{ + uint8_t cs; + + if (pos >= ao_storage_total || pos + len > ao_storage_total) + return 0; + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + + cs = ao_m25_set_address(pos); + + /* No need to use the FAST_READ as we're running at only 8MHz */ + ao_m25_instruction[0] = M25_READ; + M25_SELECT(cs); + ao_spi_send(ao_m25_instruction, 4); + ao_spi_recv(d, len); + M25_DESELECT(cs); + + ao_mutex_put(&ao_m25_mutex); + return 1; +} + +void +ao_storage_flush(void) __reentrant +{ +} + +void +ao_storage_setup(void) +{ + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + ao_mutex_put(&ao_m25_mutex); +} + +void +ao_storage_device_info(void) __reentrant +{ + uint8_t cs; +#if M25_MAX_CHIPS > 1 + uint8_t chip; +#endif + + ao_mutex_get(&ao_m25_mutex); + ao_m25_scan(); + ao_mutex_put(&ao_m25_mutex); + +#if M25_MAX_CHIPS > 1 + printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total); + for (chip = 0; chip < ao_m25_numchips; chip++) + printf ("Flash chip %d select %02x size %d\n", + chip, ao_m25_pin[chip], ao_m25_size[chip]); +#else + printf ("Detected chips 1 size %d\n", ao_m25_total); +#endif + + printf ("Available chips:\n"); + for (cs = 1; cs != 0; cs <<= 1) { + if ((M25_CS_MASK & cs) == 0) + continue; + + ao_mutex_get(&ao_m25_mutex); + M25_SELECT(cs); + ao_m25_instruction[0] = M25_RDID; + ao_spi_send(ao_m25_instruction, 1); + ao_spi_recv(ao_m25_instruction, M25_RDID_LEN); + M25_DESELECT(cs); + + printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n", + cs, + ao_m25_instruction[M25_MANUF_OFFSET], + ao_m25_instruction[M25_MEMORY_TYPE_OFFSET], + ao_m25_instruction[M25_CAPACITY_OFFSET], + ao_m25_instruction[M25_UID_OFFSET]); + ao_mutex_put(&ao_m25_mutex); + } +} + +void +ao_storage_device_init(void) +{ + /* Set up chip select wires */ + SPI_CS_PORT |= M25_CS_MASK; /* raise all CS pins */ + SPI_CS_DIR |= M25_CS_MASK; /* set CS pins as outputs */ + SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */ +} diff --git a/src/gps-cksum b/src/gps-cksum deleted file mode 100755 index a08153bf..00000000 --- a/src/gps-cksum +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env nickle - -int checksum(string a) -{ - int c = 0; - for (int i = 0; i < String::length(a); i++) - c ^= a[i]; - return c; -} - -void main() -{ - for (int i = 1; i < dim(argv); i++) - printf ("$%s*%02x\n", argv[i], checksum(argv[i])); -} - -main(); diff --git a/src/make-altitude b/src/make-altitude deleted file mode 100644 index 716aa8a8..00000000 --- a/src/make-altitude +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/nickle -f -/* - * Pressure Sensor Model, version 1.1 - * - * written by Holly Grimes - * - * Uses the International Standard Atmosphere as described in - * "A Quick Derivation relating altitude to air pressure" (version 1.03) - * from the Portland State Aerospace Society, except that the atmosphere - * is divided into layers with each layer having a different lapse rate. - * - * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 - * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ - return 0; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted altitude */ - for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - base_pressure *= exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - base_pressure *= pow(base, exponent); - } - base_temperature += delta_z * lapse_rate[layer_number]; - } - - /* calculate the pressure at the inputted altitude */ - delta_z = altitude - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - pressure = base_pressure * exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - pressure = base_pressure * pow(base, exponent); - } - - return pressure; -} - - -/* outputs the altitude associated with the given pressure. the altitude - returned is measured with respect to the mean sea level */ -real pressure_to_altitude(real pressure) { - - real next_base_temperature = LAYER0_BASE_TEMPERATURE; - real next_base_pressure = LAYER0_BASE_PRESSURE; - - real altitude; - real base_pressure; - real base_temperature; - real base; /* base for function to determine base pressure of next layer */ - real exponent; /* exponent for function to determine base pressure - of next layer */ - real coefficient; - int layer_number; /* identifies layer in the atmosphere */ - int delta_z; /* difference between two altitudes */ - - if (pressure < 0) /* illegal pressure */ - return -1; - if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ - return MAXIMUM_ALTITUDE; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted pressure. */ - layer_number = -1; - do { - layer_number++; - base_pressure = next_base_pressure; - base_temperature = next_base_temperature; - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - next_base_pressure *= exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - next_base_pressure *= pow(base, exponent); - } - next_base_temperature += delta_z * lapse_rate[layer_number]; - } - while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); - - /* calculate the altitude associated with the inputted pressure */ - if (lapse_rate[layer_number] == 0.0) { - coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) - * base_temperature; - altitude = base_altitude[layer_number] - + coefficient * log(pressure / base_pressure); - } - else { - base = pressure / base_pressure; - exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] - / GRAVITATIONAL_ACCELERATION; - coefficient = base_temperature / lapse_rate[layer_number]; - altitude = base_altitude[layer_number] - + coefficient * (pow(base, exponent) - 1); - } - - return altitude; -} - -real feet_to_meters(real feet) -{ - return feet * (12 * 2.54 / 100); -} - -real meters_to_feet(real meters) -{ - return meters / (12 * 2.54 / 100); -} - -/* - * Values for our MP3H6115A pressure sensor - * - * From the data sheet: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * - * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa - * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa - */ - -real counts_per_kPa = 27 * 2047 / 3300; -real counts_at_101_3kPa = 1674; - -real fraction_to_kPa(real fraction) -{ - return (fraction + 0.095) / 0.009; -} - - -real count_to_kPa(real count) = fraction_to_kPa(count / 2047); - -typedef struct { - real m, b; - int m_i, b_i; -} line_t; - -line_t best_fit(real[] values, int first, int last) { - real sum_x = 0, sum_x2 = 0, sum_y = 0, sum_xy = 0; - int n = last - first + 1; - real m, b; - int m_i, b_i; - - for (int i = first; i <= last; i++) { - sum_x += i; - sum_x2 += i**2; - sum_y += values[i]; - sum_xy += values[i] * i; - } - m = (n*sum_xy - sum_y*sum_x) / (n*sum_x2 - sum_x**2); - b = sum_y/n - m*(sum_x/n); - return (line_t) { m = m, b = b }; -} - -real count_to_altitude(real count) { - return pressure_to_altitude(count_to_kPa(count) * 1000); -} - -real fraction_to_altitude(real frac) = pressure_to_altitude(fraction_to_kPa(frac) * 1000); - -int num_samples = 1024; - -real[num_samples] alt = { [n] = fraction_to_altitude(n/(num_samples - 1)) }; - -int num_part = 128; -int seg_len = num_samples / num_part; - -line_t [dim(alt) / seg_len] fit = { - [n] = best_fit(alt, n * seg_len, n * seg_len + seg_len - 1) -}; - -int[num_samples/seg_len + 1] alt_part; - -alt_part[0] = floor (fit[0].b + 0.5); -alt_part[dim(fit)] = floor(fit[dim(fit)-1].m * dim(fit) * seg_len + fit[dim(fit)-1].b + 0.5); - -for (int i = 0; i < dim(fit) - 1; i++) { - real here, there; - here = fit[i].m * (i+1) * seg_len + fit[i].b; - there = fit[i+1].m * (i+1) * seg_len + fit[i+1].b; - alt_part[i+1] = floor ((here + there) / 2 + 0.5); -} - -real count_to_fit_altitude(int count) { - int sub = count // seg_len; - int off = count % seg_len; - line_t l = fit[sub]; - real r_v; - real i_v; - - r_v = count * l.m + l.b; - i_v = (alt_part[sub] * (seg_len - off) + alt_part[sub+1] * off) / seg_len; - return i_v; -} - -real max_error = 0; -int max_error_count = 0; -real total_error = 0; - -for (int count = 0; count < num_samples; count++) { - real kPa = fraction_to_kPa(count / (num_samples - 1)); - real meters = pressure_to_altitude(kPa * 1000); - - real meters_approx = count_to_fit_altitude(count); - real error = abs(meters - meters_approx); - - total_error += error; - if (error > max_error) { - max_error = error; - max_error_count = count; - } -# printf (" %7d, /* %6.2g kPa %5d count approx %d */\n", -# floor (meters + 0.5), kPa, count, floor(count_to_fit_altitude(count) + 0.5)); -} - -printf ("/*max error %f at %7.3f%%. Average error %f*/\n", max_error, max_error_count / (num_samples - 1) * 100, total_error / num_samples); - -printf ("#define NALT %d\n", dim(alt_part)); -printf ("#define ALT_FRAC_BITS %d\n", floor (log2(32768/(dim(alt_part)-1)) + 0.1)); - -for (int i = 0; i < dim(alt_part); i++) { - real fraction = i / (dim(alt_part) - 1); - real kPa = fraction_to_kPa(fraction); - printf ("%9d, /* %6.2f kPa %7.3f%% */\n", - alt_part[i], kPa, fraction * 100); -} diff --git a/src/make-kalman b/src/make-kalman deleted file mode 100644 index 9ac35134..00000000 --- a/src/make-kalman +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -cd ../kalman - -SIGMA_BOTH="-M 2 -H 6 -A 2" -SIGMA_BARO="-M 2 -H 6 -A 2" -SIGMA_ACCEL="-M 2 -H 4 -A 4" - -nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH -nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH -nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH - -nickle kalman.5c -p AO_ACCEL -c accel -t 0.01 $SIGMA_ACCEL -nickle kalman.5c -p AO_ACCEL -c accel -t 0.1 $SIGMA_ACCEL -nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL - -nickle kalman.5c -p AO_BARO -c baro -t 0.01 $SIGMA_BARO -nickle kalman.5c -p AO_BARO -c baro -t 0.1 $SIGMA_BARO -nickle kalman.5c -p AO_BARO -c baro -t 1 $SIGMA_BARO diff --git a/src/product/Makefile.telebt b/src/product/Makefile.telebt new file mode 100644 index 00000000..99730b9f --- /dev/null +++ b/src/product/Makefile.telebt @@ -0,0 +1,97 @@ +# +# TeleBT build file +# +# Define TELEBT_VER, TELEBT_DEF, TELEBT_INC and TELEBT_SRC +# and include this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h \ + $(TELEBT_INC) + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_gps_print.c \ + ao_monitor.c \ + ao_mutex.c \ + ao_panic.c \ + ao_rssi.c \ + ao_state.c \ + ao_stdio.c \ + ao_task.c + +CC1111_SRC = \ + ao_dbg.c \ + ao_dma.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_master.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_serial.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = \ + ao_btm.c + +PRODUCT_SRC = \ + ao_telebt.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) \ + $(TELEBT_SRC) + +PROG = telebt-v$(TELEBT_VER)-$(VERSION).ihx +PRODUCT=TeleBT-v$(TELEBT_VER) +PRODUCT_DEF=-DTELEBT_V_$(TELEBT_DEF) +IDPRODUCT=0x000e + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.teledongle b/src/product/Makefile.teledongle new file mode 100644 index 00000000..f32c037f --- /dev/null +++ b/src/product/Makefile.teledongle @@ -0,0 +1,96 @@ +# +# TeleDongle build file +# +# The various teledongle versions differ only +# in minor pin variations +# so the per-board makefiles simply define +# TD_VER, TD_DEF and include +# this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_gps_print.c \ + ao_monitor.c \ + ao_mutex.c \ + ao_panic.c \ + ao_rssi.c \ + ao_state.c \ + ao_stdio.c \ + ao_task.c + +CC1111_SRC = \ + ao_dbg.c \ + ao_dma.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_master.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_teledongle.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = teledongle-v$(TD_VER)-$(VERSION).ihx +PRODUCT=TeleDongle-v$(TD_VER) +PRODUCT_DEF=-DTELEDONGLE_V_$(TD_DEF) +IDPRODUCT=0x000c + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.telemetrum b/src/product/Makefile.telemetrum new file mode 100644 index 00000000..fd958aea --- /dev/null +++ b/src/product/Makefile.telemetrum @@ -0,0 +1,111 @@ +# +# TeleMetrum build file +# +# The various telemetrum versions differ only +# in which flash and GPS drivers are included, +# so the per-board makefiles simply define +# TM_VER, TM_DEF, TM_INC and TM_SRC and include +# this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + altitude.h \ + ao_kalman.h \ + ao_product.h \ + $(TM_INC) + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_convert.c \ + ao_gps_report.c \ + ao_mutex.c \ + ao_panic.c \ + ao_stdio.c \ + ao_storage.c \ + ao_task.c \ + ao_flight.c \ + ao_sample.c \ + ao_kalman.c \ + ao_log.c \ + ao_log_big.c \ + ao_report.c \ + ao_telemetry.c + +CC1111_SRC = \ + ao_adc.c \ + ao_beep.c \ + ao_dbg.c \ + ao_dma.c \ + ao_ignite.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_slave.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_serial.c \ + ao_spi.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = \ + $(TM_SRC) + +PRODUCT_SRC = \ + ao_telemetrum.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = telemetrum-v$(TM_VER)-$(VERSION).ihx +PRODUCT=TeleMetrum-v$(TM_VER) +PRODUCT_DEF=-DTELEMETRUM_V_$(TM_DEF) +IDPRODUCT=0x000b + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.telemini b/src/product/Makefile.telemini new file mode 100644 index 00000000..3bd14226 --- /dev/null +++ b/src/product/Makefile.telemini @@ -0,0 +1,100 @@ +# +# TeleMini build file +# +# Define TELEMINI_VER and TELEMINI_DEF and then +# include this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_convert.c \ + ao_flight.c \ + ao_kalman.c \ + ao_log.c \ + ao_log_tiny.c \ + ao_mutex.c \ + ao_panic.c \ + ao_report.c \ + ao_sample.c \ + ao_stdio.c \ + ao_storage.c \ + ao_task.c \ + ao_telemetry.c + +CC1111_SRC = \ + ao_adc.c \ + ao_dma.c \ + ao_ignite.c \ + ao_intflash.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_slave.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_telemini.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = telemini-v$(TELEMINI_VER)-$(VERSION).ihx +PRODUCT=TeleMini-v$(TELEMINI_VER) +PRODUCT_DEF=-DTELEMINI_V_$(TELEMINI_DEF) +IDPRODUCT=0x000a +CODESIZE=0x6700 + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/Makefile.telenano b/src/product/Makefile.telenano new file mode 100644 index 00000000..72043044 --- /dev/null +++ b/src/product/Makefile.telenano @@ -0,0 +1,99 @@ +# +# TeleNano build file +# +# Define TELENANO_VER and TELENANO_DEF and then +# include this file + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_convert.c \ + ao_flight_nano.c \ + ao_kalman.c \ + ao_log.c \ + ao_log_tiny.c \ + ao_mutex.c \ + ao_panic.c \ + ao_report.c \ + ao_sample.c \ + ao_stdio.c \ + ao_storage.c \ + ao_task.c \ + ao_telemetry.c + +CC1111_SRC = \ + ao_adc.c \ + ao_dma.c \ + ao_intflash.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_slave.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_telenano.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = telenano-v$(TELENANO_VER)-$(VERSION).ihx +PRODUCT=TeleNano-v$(TELENANO_VER) +PRODUCT_DEF=-DTELENANO_V_$(TELENANO_DEF) +IDPRODUCT=0x000a +CODESIZE=0x6700 + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: diff --git a/src/product/ao_telebt.c b/src/product/ao_telebt.c new file mode 100644 index 00000000..85565172 --- /dev/null +++ b/src/product/ao_telebt.c @@ -0,0 +1,50 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" + +__code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ + +void +main(void) +{ + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + ao_timer_init(); +#if HAS_BEEP + ao_beep_init(); +#endif + ao_cmd_init(); +#if HAS_EEPROM + ao_spi_init(); + ao_storage_init(); +#endif + ao_usb_init(); + ao_monitor_init(AO_LED_GREEN, TRUE); + ao_rssi_init(AO_LED_RED); + ao_radio_init(); + ao_packet_master_init(); + ao_btm_init(); +#if HAS_DBG + ao_dbg_init(); +#endif + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_teledongle.c b/src/product/ao_teledongle.c new file mode 100644 index 00000000..008b200a --- /dev/null +++ b/src/product/ao_teledongle.c @@ -0,0 +1,40 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +void +main(void) +{ + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_cmd_init(); + ao_usb_init(); + ao_monitor_init(AO_LED_GREEN, TRUE); + ao_rssi_init(AO_LED_RED); + ao_radio_init(); + ao_packet_master_init(); +#if HAS_DBG + ao_dbg_init(); +#endif + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_telemetrum.c b/src/product/ao_telemetrum.c new file mode 100644 index 00000000..f560740a --- /dev/null +++ b/src/product/ao_telemetrum.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" +#include "ao_pins.h" + +void +main(void) +{ + /* + * Reduce the transient on the ignite pins at startup by + * pulling the pins low as soon as possible at power up + */ + ao_ignite_set_pins(); + + ao_clock_init(); + + /* Turn on the red LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + + /* A hack -- look at the SPI clock pin, if it's sitting at + * ground, then we force the computer to idle mode instead of + * flight mode + */ + if (P1_3 == 0) { + ao_flight_force_idle = 1; + while (P1_3 == 0) + ; + } + ao_timer_init(); + ao_adc_init(); + ao_beep_init(); + ao_cmd_init(); + ao_spi_init(); + ao_storage_init(); + ao_flight_init(); + ao_log_init(); + ao_report_init(); + ao_usb_init(); + ao_serial_init(); + ao_gps_init(); + ao_gps_report_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(TRUE); + ao_igniter_init(); +#if HAS_DBG + ao_dbg_init(); +#endif +#if HAS_COMPANION + ao_companion_init(); +#endif + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_telemini.c b/src/product/ao_telemini.c new file mode 100644 index 00000000..fa23de01 --- /dev/null +++ b/src/product/ao_telemini.c @@ -0,0 +1,49 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" +#include "ao_pins.h" + +void +main(void) +{ + /* + * Reduce the transient on the ignite pins at startup by + * pulling the pins low as soon as possible at power up + */ + ao_ignite_set_pins(); + + ao_clock_init(); + + /* Turn on the red LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + + ao_timer_init(); + ao_adc_init(); + ao_cmd_init(); + ao_storage_init(); + ao_flight_init(); + ao_log_init(); + ao_report_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(TRUE); + ao_igniter_init(); + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_telenano.c b/src/product/ao_telenano.c new file mode 100644 index 00000000..d91983d0 --- /dev/null +++ b/src/product/ao_telenano.c @@ -0,0 +1,43 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 "ao.h" +#include "ao_pins.h" + +void +main(void) +{ + ao_clock_init(); + + + /* Turn on the red LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + + ao_timer_init(); + ao_adc_init(); + ao_cmd_init(); + ao_storage_init(); + ao_flight_nano_init(); + ao_log_init(); + ao_report_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(TRUE); + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_teleterra.c b/src/product/ao_teleterra.c new file mode 100644 index 00000000..d696b914 --- /dev/null +++ b/src/product/ao_teleterra.c @@ -0,0 +1,38 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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_NO_ADC_ISR 1 +#include "ao.h" + +void +main(void) +{ + ao_clock_init(); + + /* Turn on the red LED until the system is stable */ + ao_led_init(AO_LED_RED|AO_LED_GREEN); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_beep_init(); + ao_cmd_init(); + ao_usb_init(); + ao_serial_init(); + ao_monitor_init(AO_LED_GREEN, TRUE); + ao_radio_init(); + ao_config_init(); + ao_start_scheduler(); +} diff --git a/src/product/ao_test.c b/src/product/ao_test.c new file mode 100644 index 00000000..14c2eb75 --- /dev/null +++ b/src/product/ao_test.c @@ -0,0 +1,117 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "ao.h" + +struct ao_task __xdata blink_0_task; +struct ao_task __xdata blink_1_task; +struct ao_task __xdata wakeup_task; +struct ao_task __xdata beep_task; +struct ao_task __xdata echo_task; + +void delay(int n) __reentrant +{ + uint8_t j = 0; + while (--n) + while (--j) + ao_yield(); +} + +static __xdata uint8_t blink_chan; + +void +blink_0(void) +{ + uint8_t b = 0; + for (;;) { + b = 1 - b; + if (b) + ao_led_on(AO_LED_GREEN); + else + ao_led_off(AO_LED_GREEN); + ao_sleep(&blink_chan); + } +} + +void +blink_1(void) +{ + static __xdata struct ao_adc adc; + + for (;;) { + ao_sleep(&ao_adc_head); + ao_adc_get(&adc); + if (adc.accel < 15900) + ao_led_on(AO_LED_RED); + else + ao_led_off(AO_LED_RED); + } +} + +void +wakeup(void) +{ + for (;;) { + ao_delay(AO_MS_TO_TICKS(100)); + ao_wakeup(&blink_chan); + } +} + +void +beep(void) +{ + static __xdata struct ao_adc adc; + + for (;;) { + ao_delay(AO_SEC_TO_TICKS(1)); + ao_adc_get(&adc); + if (adc.temp > 7400) + ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(50)); + } +} + +void +echo(void) +{ + char c; + for (;;) { + ao_usb_flush(); + c = ao_usb_getchar(); + ao_usb_putchar(c); + if (c == '\r') + ao_usb_putchar('\n'); + } +} + +void +main(void) +{ + ao_clock_init(); + +// ao_add_task(&blink_0_task, blink_0); +// ao_add_task(&blink_1_task, blink_1); +// ao_add_task(&wakeup_task, wakeup); +// ao_add_task(&beep_task, beep); + ao_add_task(&echo_task, echo); + ao_timer_init(); + ao_adc_init(); + ao_beep_init(); + ao_led_init(); + ao_usb_init(); + + ao_start_scheduler(); +} diff --git a/src/product/ao_tidongle.c b/src/product/ao_tidongle.c new file mode 100644 index 00000000..3b7c2733 --- /dev/null +++ b/src/product/ao_tidongle.c @@ -0,0 +1,42 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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_NO_SERIAL_ISR 1 +#define AO_NO_ADC_ISR 1 +#include "ao.h" + +void +main(void) +{ + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(AO_LED_RED); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_cmd_init(); + ao_usb_init(); + ao_monitor_init(AO_LED_RED, TRUE); + ao_rssi_init(AO_LED_RED); + ao_radio_init(); + ao_dbg_init(); + ao_config_init(); + /* Bring up the USB link */ + P1DIR |= 1; + P1 |= 1; + ao_start_scheduler(); +} diff --git a/src/sirf-cksum b/src/sirf-cksum deleted file mode 100755 index b905f318..00000000 --- a/src/sirf-cksum +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env nickle - -int checksum(int[] msg) -{ - int sum = 0; - for (int i = 0; i < dim(msg); i++) { - sum += msg[i]; - sum &= 0x7fff; - } - return sum; -} - -void main() -{ - string[...] input; - int[...] msg; - - setdim(input, 0); - while (!File::end(stdin)) { - input[dim(input)] = gets(); - } - - setdim(msg, 0); - for (int i = 0; i < dim(input); i++) { - string[*] words = String::wordsplit(input[i], " ,\t"); - for (int j = 0; j < dim(words); j++) { - if (words[j] == "/" + "*") - break; - if (String::length(words[j]) > 0 && - Ctype::isdigit(words[j][0])) { - msg[dim(msg)] = string_to_integer(words[j]); - } - } - } - printf("\t0xa0, 0xa2, 0x%02x, 0x%02x,\t/* length: %d bytes */\n", - dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); - for (int i = 0; i < dim(input); i++) - printf("%s\n", input[i]); - int csum = checksum(msg); - printf ("\t0x%02x, 0x%02x, 0xb0, 0xb3,\n", - csum >> 8, csum & 0xff); -} - -main(); diff --git a/src/skytraq-cksum b/src/skytraq-cksum deleted file mode 100644 index ab0464a7..00000000 --- a/src/skytraq-cksum +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env nickle - -int checksum(int[] msg) -{ - int sum = 0; - for (int i = 0; i < dim(msg); i++) { - sum ^= msg[i]; - sum &= 0xff; - } - return sum; -} - -void main() -{ - string[...] input; - int[...] msg; - - setdim(input, 0); - while (!File::end(stdin)) { - input[dim(input)] = gets(); - } - - setdim(msg, 0); - for (int i = 0; i < dim(input); i++) { - string[*] words = String::wordsplit(input[i], " ,\t"); - for (int j = 0; j < dim(words); j++) { - if (words[j] == "/" + "*") - break; - if (String::length(words[j]) > 0 && - Ctype::isdigit(words[j][0])) { - msg[dim(msg)] = string_to_integer(words[j]); - } - } - } - printf("\t0xa0, 0xa1, 0x%02x, 0x%02x,\t\t/* length: %d bytes */\n", - dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); - for (int i = 0; i < dim(input); i++) - printf("%s\n", input[i]); - int csum = checksum(msg); - printf ("\t0x%02x, 0x0d, 0x0a,\n", - csum); -} - -main(); diff --git a/src/telebt-v0.0/Makefile b/src/telebt-v0.0/Makefile index d8867b19..e89639ab 100644 --- a/src/telebt-v0.0/Makefile +++ b/src/telebt-v0.0/Makefile @@ -1 +1,9 @@ -include ../Makefile.proto +# +# TeleBT v0.0 build +# + +TELEBT_VER=0.0 +TELEBT_DEF=0_0 + +include ../product/Makefile.telebt + diff --git a/src/telebt-v0.0/Makefile.defs b/src/telebt-v0.0/Makefile.defs deleted file mode 100644 index f0bb5e0c..00000000 --- a/src/telebt-v0.0/Makefile.defs +++ /dev/null @@ -1,8 +0,0 @@ -PROG = telebt-v0.0-$(VERSION).ihx - -SRC = \ - $(TBT_BASE_SRC) - -PRODUCT=TeleBT-v0.0 -PRODUCT_DEF=-DTELEBT_V_0_0 -IDPRODUCT=0x000e diff --git a/src/telebt-v0.1/Makefile b/src/telebt-v0.1/Makefile index d8867b19..a34e8912 100644 --- a/src/telebt-v0.1/Makefile +++ b/src/telebt-v0.1/Makefile @@ -1 +1,19 @@ -include ../Makefile.proto +# +# TeleBT v0.1 build +# + +TELEBT_VER=0.1 +TELEBT_DEF=0_1 + +TELEBT_INC = \ + ao_25lc1024.h + +TELEBT_SRC = \ + ao_beep.c \ + ao_log_telem.c \ + ao_spi.c \ + ao_storage.c \ + ao_m25.c + +include ../product/Makefile.telebt + diff --git a/src/telebt-v0.1/Makefile.defs b/src/telebt-v0.1/Makefile.defs deleted file mode 100644 index 50657c83..00000000 --- a/src/telebt-v0.1/Makefile.defs +++ /dev/null @@ -1,8 +0,0 @@ -PROG = telebt-v0.1-$(VERSION).ihx - -SRC = \ - $(TBT_V_0_1_SRC) - -PRODUCT=TeleBT-v0.1 -PRODUCT_DEF=-DTELEBT_V_0_1 -IDPRODUCT=0x000e diff --git a/src/teledongle-v0.1/Makefile b/src/teledongle-v0.1/Makefile index d8867b19..48425107 100644 --- a/src/teledongle-v0.1/Makefile +++ b/src/teledongle-v0.1/Makefile @@ -1 +1,8 @@ -include ../Makefile.proto +# +# TeleDongle v0.2 build +# + +TD_VER=0.1 +TD_DEF=0_1 + +include ../product/Makefile.teledongle diff --git a/src/teledongle-v0.1/Makefile.defs b/src/teledongle-v0.1/Makefile.defs deleted file mode 100644 index ceb80b7a..00000000 --- a/src/teledongle-v0.1/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = teledongle-v0.1-$(VERSION).ihx - -SRC = \ - $(TD_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleDongle-v0.1 -PRODUCT_DEF=-DTELEDONGLE_V_0_1 -IDPRODUCT=0x000c diff --git a/src/teledongle-v0.2/Makefile b/src/teledongle-v0.2/Makefile index d8867b19..ce4ab437 100644 --- a/src/teledongle-v0.2/Makefile +++ b/src/teledongle-v0.2/Makefile @@ -1 +1,8 @@ -include ../Makefile.proto +# +# TeleDongle v0.2 build +# + +TD_VER=0.2 +TD_DEF=0_2 + +include ../product/Makefile.teledongle \ No newline at end of file diff --git a/src/teledongle-v0.2/Makefile.defs b/src/teledongle-v0.2/Makefile.defs deleted file mode 100644 index ea9713b6..00000000 --- a/src/teledongle-v0.2/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = teledongle-v0.2-$(VERSION).ihx - -SRC = \ - $(TD_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleDongle-v0.2 -PRODUCT_DEF=-DTELEDONGLE_V_0_2 -IDPRODUCT=0x000c diff --git a/src/telemetrum-v0.1-sirf/Makefile b/src/telemetrum-v0.1-sirf/Makefile index d8867b19..00cdc9c5 100644 --- a/src/telemetrum-v0.1-sirf/Makefile +++ b/src/telemetrum-v0.1-sirf/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# TeleMetrum v0.1 with SkyTraq GPS build +# + +TM_VER=0.1 +TM_DEF=0_1 + +TM_INC = \ + ao_25lc1024.h + +TM_SRC = \ + ao_gps_sirf.c \ + ao_25lc1024.c + +include ../product/Makefile.telemetrum + diff --git a/src/telemetrum-v0.1-sirf/Makefile.defs b/src/telemetrum-v0.1-sirf/Makefile.defs deleted file mode 100644 index ac8dcdb9..00000000 --- a/src/telemetrum-v0.1-sirf/Makefile.defs +++ /dev/null @@ -1,12 +0,0 @@ -PROG = telemetrum-v0.1-sirf-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(EE_DRIVER_SRC) \ - $(SIRF_DRIVER_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v0.1-SiRF -PRODUCT_DEF=-DTELEMETRUM_V_0_1 -IDPRODUCT=0x000b diff --git a/src/telemetrum-v0.1-sky/Makefile b/src/telemetrum-v0.1-sky/Makefile index d8867b19..e3c61db6 100644 --- a/src/telemetrum-v0.1-sky/Makefile +++ b/src/telemetrum-v0.1-sky/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# TeleMetrum v0.1 with SkyTraq GPS build +# + +TM_VER=0.1 +TM_DEF=0_1 + +TM_INC = \ + ao_25lc1024.h + +TM_SRC = \ + ao_gps_skytraq.c \ + ao_25lc1024.c + +include ../product/Makefile.telemetrum + diff --git a/src/telemetrum-v0.1-sky/Makefile.defs b/src/telemetrum-v0.1-sky/Makefile.defs deleted file mode 100644 index e032d1eb..00000000 --- a/src/telemetrum-v0.1-sky/Makefile.defs +++ /dev/null @@ -1,12 +0,0 @@ -PROG = telemetrum-v0.1-sky-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(EE_DRIVER_SRC) \ - $(SKY_DRIVER_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v0.1 -PRODUCT_DEF=-DTELEMETRUM_V_0_1 -IDPRODUCT=0x000b diff --git a/src/telemetrum-v1.0/Makefile b/src/telemetrum-v1.0/Makefile index d8867b19..4aae84c8 100644 --- a/src/telemetrum-v1.0/Makefile +++ b/src/telemetrum-v1.0/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# TeleMetrum v1.0 build +# + +TM_VER=1.0 +TM_DEF=1_0 + +TM_INC = \ + ao_at45db161d.h + +TM_SRC = \ + ao_companion.c \ + ao_gps_skytraq.c \ + ao_at45db161d.c + +include ../product/Makefile.telemetrum diff --git a/src/telemetrum-v1.0/Makefile.defs b/src/telemetrum-v1.0/Makefile.defs deleted file mode 100644 index 5eefc392..00000000 --- a/src/telemetrum-v1.0/Makefile.defs +++ /dev/null @@ -1,13 +0,0 @@ -PROG = telemetrum-v1.0-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(FLASH_DRIVER_SRC) \ - $(SKY_DRIVER_SRC) \ - $(COMPANION_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v1.0 -PRODUCT_DEF=-DTELEMETRUM_V_1_0 -IDPRODUCT=0x000b diff --git a/src/telemetrum-v1.1/Makefile b/src/telemetrum-v1.1/Makefile index d8867b19..4bea03db 100644 --- a/src/telemetrum-v1.1/Makefile +++ b/src/telemetrum-v1.1/Makefile @@ -1 +1,16 @@ -include ../Makefile.proto +# +# AltOS build +# +# + +TM_VER=1.1 +TM_DEF=1_1 + +TM_INC = + +TM_SRC = \ + ao_companion.c \ + ao_gps_skytraq.c \ + ao_m25.c + +include ../product/Makefile.telemetrum diff --git a/src/telemetrum-v1.1/Makefile.defs b/src/telemetrum-v1.1/Makefile.defs deleted file mode 100644 index 3c8b8793..00000000 --- a/src/telemetrum-v1.1/Makefile.defs +++ /dev/null @@ -1,13 +0,0 @@ -PROG = telemetrum-v1.1-$(VERSION).ihx - -SRC = \ - $(TM_BASE_SRC) \ - $(SPI_DRIVER_SRC) \ - $(M25_DRIVER_SRC) \ - $(SKY_DRIVER_SRC) \ - $(COMPANION_SRC) \ - $(DBG_SRC) - -PRODUCT=TeleMetrum-v1.1 -PRODUCT_DEF=-DTELEMETRUM_V_1_1 -IDPRODUCT=0x000b diff --git a/src/telemini-v1.0/Makefile b/src/telemini-v1.0/Makefile index d8867b19..4f1c8b51 100644 --- a/src/telemini-v1.0/Makefile +++ b/src/telemini-v1.0/Makefile @@ -1 +1,8 @@ -include ../Makefile.proto +# +# TeleMini build file +# + +TELEMINI_VER=1.0 +TELEMINI_DEF=1_0 + +include ../product/Makefile.telemini diff --git a/src/telemini-v1.0/Makefile.defs b/src/telemini-v1.0/Makefile.defs deleted file mode 100644 index 0e91f2fc..00000000 --- a/src/telemini-v1.0/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = telemini-v1.0-$(VERSION).ihx - -SRC = \ - $(TMINI_BASE_SRC) - -PRODUCT=TeleMini-v1.0 -PRODUCT_DEF=-DTELEMINI_V_1_0 -IDPRODUCT=0x000a -CODESIZE=0x6700 diff --git a/src/telenano-v0.1/Makefile b/src/telenano-v0.1/Makefile index d8867b19..2714c1e9 100644 --- a/src/telenano-v0.1/Makefile +++ b/src/telenano-v0.1/Makefile @@ -1 +1,9 @@ -include ../Makefile.proto +# +# TeleNano build file +# + +TELENANO_VER=0.1 +TELENANO_DEF=0_1 + +include ../product/Makefile.telenano + diff --git a/src/telenano-v0.1/Makefile.defs b/src/telenano-v0.1/Makefile.defs deleted file mode 100644 index 34cf69d1..00000000 --- a/src/telenano-v0.1/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = telenano-v0.1-$(VERSION).ihx - -SRC = \ - $(TNANO_BASE_SRC) - -PRODUCT=TeleNano-v0.1 -PRODUCT_DEF=-DTELENANO_V_0_1 -IDPRODUCT=0x000a -CODESIZE=0x6700 diff --git a/src/test/Makefile b/src/test/Makefile index 33203ffd..333850e4 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,9 +1,8 @@ -vpath % .. -vpath % ../kalman +vpath % ..:../core:../drivers PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test -CFLAGS=-I.. -I. +CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g all: $(PROGS) @@ -13,22 +12,19 @@ clean: 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 - cc -g -o $@ $< + cc $(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 - cc -g -o $@ -DHAS_ACCEL=0 ../ao_flight_test.c + 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 - cc -g -o $@ -DFORCE_ACCEL=1 ../ao_flight_test.c + cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h - cc -g -o $@ $< + cc $(CFLAGS) -o $@ $< ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_host.h - cc -g -o $@ $< + cc $(CFLAGS) -o $@ $< ao_convert_test: ao_convert_test.c ao_convert.c altitude.h - cc -g -o $@ $< - -../ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c - sh $< > $@ + cc $(CFLAGS) -o $@ $< diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c new file mode 100644 index 00000000..56733c89 --- /dev/null +++ b/src/test/ao_flight_test.c @@ -0,0 +1,716 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#include +#include + +#define AO_HERTZ 100 + +#define AO_ADC_RING 64 +#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) +#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + +/* + * One set of samples read from the A/D converter + */ +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + int16_t accel; /* accelerometer */ + int16_t pres; /* pressure sensor */ + int16_t pres_real; /* unclipped */ + int16_t temp; /* temperature sensor */ + int16_t v_batt; /* battery voltage */ + int16_t sense_d; /* drogue continuity sense */ + int16_t sense_m; /* main continuity sense */ +}; + +#define __pdata +#define __data +#define __xdata +#define __code +#define __reentrant + +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) +#define from_fix(x) ((x) >> 16) + +/* + * 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) + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 200 + +#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 +#define TRUE 1 + +struct ao_adc ao_adc_ring[AO_ADC_RING]; +uint8_t ao_adc_head; +int ao_summary = 0; + +#define ao_led_on(l) +#define ao_led_off(l) +#define ao_timer_set_adc_interval(i) +#define ao_wakeup(wchan) ao_dump_state() +#define ao_cmd_register(c) +#define ao_usb_disable() +#define ao_telemetry_set_interval(x) +#define ao_rdf_set(rdf) +#define ao_packet_slave_start() +#define ao_packet_slave_stop() + +enum ao_igniter { + ao_igniter_drogue = 0, + ao_igniter_main = 1 +}; + +struct ao_adc ao_adc_static; + +int drogue_height; +double drogue_time; +int main_height; +double main_time; + +int tick_offset; + +static int32_t ao_k_height; + +void +ao_ignite(enum ao_igniter igniter) +{ + double time = (double) (ao_adc_static.tick + tick_offset) / 100; + + if (igniter == ao_igniter_drogue) { + drogue_time = time; + drogue_height = ao_k_height >> 16; + } else { + main_time = time; + main_height = ao_k_height >> 16; + } +} + +struct ao_task { + int dummy; +}; + +#define ao_add_task(t,f,n) + +#define ao_log_start() +#define ao_log_stop() + +#define AO_MS_TO_TICKS(ms) ((ms) / 10) +#define AO_SEC_TO_TICKS(s) ((s) * 100) + +#define AO_FLIGHT_TEST + +int ao_flight_debug; + +FILE *emulator_in; +char *emulator_app; +char *emulator_name; +double emulator_error_max = 4; +double emulator_height_error_max = 20; /* noise in the baro sensor */ + +void +ao_dump_state(void); + +void +ao_sleep(void *wchan); + +const char const * const ao_state_names[] = { + "startup", "idle", "pad", "boost", "fast", + "coast", "drogue", "main", "landed", "invalid" +}; + +struct ao_cmds { + void (*func)(void); + const char *help; +}; + +#include "ao_convert.c" + +struct ao_config { + uint16_t main_deploy; + int16_t accel_plus_g; + int16_t accel_minus_g; + uint8_t pad_orientation; +}; + +#define AO_PAD_ORIENTATION_ANTENNA_UP 0 +#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 + +#define ao_config_get() + +struct ao_config ao_config; + +#define DATA_TO_XDATA(x) (x) + +#define HAS_FLIGHT 1 +#define HAS_ADC 1 +#define HAS_USB 1 +#define HAS_GPS 1 +#ifndef HAS_ACCEL +#define HAS_ACCEL 1 +#define HAS_ACCEL_REF 0 +#endif + +#define GRAVITY 9.80665 +extern int16_t ao_ground_accel, ao_flight_accel; +extern int16_t ao_accel_2g; + +extern uint16_t ao_sample_tick; + +extern int16_t ao_sample_height; +extern int16_t ao_sample_accel; +extern int32_t ao_accel_scale; +extern int16_t ao_ground_height; +extern int16_t ao_sample_alt; + +int ao_sample_prev_tick; +uint16_t prev_tick; + +#include "ao_kalman.c" +#include "ao_sample.c" +#include "ao_flight.c" + +#define to_double(f) ((f) / 65536.0) + +static int ao_records_read = 0; +static int ao_eof_read = 0; +static int ao_flight_ground_accel; +static int ao_flight_started = 0; +static int ao_test_max_height; +static double ao_test_max_height_time; +static int ao_test_main_height; +static double ao_test_main_height_time; +static double ao_test_landed_time; +static double ao_test_landed_height; +static double ao_test_landed_time; +static int landed_set; +static double landed_time; +static double landed_height; + +void +ao_test_exit(void) +{ + double drogue_error; + double main_error; + double landed_error; + double landed_time_error; + + if (!ao_test_main_height_time) { + ao_test_main_height_time = ao_test_max_height_time; + ao_test_main_height = ao_test_max_height; + } + drogue_error = fabs(ao_test_max_height_time - drogue_time); + main_error = fabs(ao_test_main_height_time - main_time); + landed_error = fabs(ao_test_landed_height - landed_height); + landed_time_error = ao_test_landed_time - landed_time; + if (drogue_error > emulator_error_max || main_error > emulator_error_max || + landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) { + printf ("%s %s\n", + emulator_app, emulator_name); + printf ("\tApogee error %g\n", drogue_error); + printf ("\tMain error %g\n", main_error); + printf ("\tLanded height error %g\n", landed_error); + printf ("\tLanded time error %g\n", landed_time_error); + printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", + ao_test_max_height, ao_test_max_height_time, + ao_test_main_height, ao_test_main_height_time, + ao_test_landed_height, ao_test_landed_time); + printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n", + drogue_height, drogue_time, main_height, main_time, + landed_height, landed_time); + exit (1); + } + exit(0); +} + +void +ao_insert(void) +{ + double time; + + ao_adc_ring[ao_adc_head] = ao_adc_static; + ao_adc_head = ao_adc_ring_next(ao_adc_head); + if (ao_flight_state != ao_flight_startup) { + double height = ao_pres_to_altitude(ao_adc_static.pres_real) - ao_ground_height; + double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / + (ao_config.accel_minus_g - ao_config.accel_plus_g); + + if (!tick_offset) + tick_offset = -ao_adc_static.tick; + if ((prev_tick - ao_adc_static.tick) > 0x400) + tick_offset += 65536; + prev_tick = ao_adc_static.tick; + time = (double) (ao_adc_static.tick + tick_offset) / 100; + + if (ao_test_max_height < height) { + ao_test_max_height = height; + ao_test_max_height_time = time; + ao_test_landed_height = height; + ao_test_landed_time = time; + } + if (height > ao_config.main_deploy) { + ao_test_main_height_time = time; + ao_test_main_height = height; + } + + if (ao_test_landed_height > height) { + ao_test_landed_height = height; + ao_test_landed_time = time; + } + + if (ao_flight_state == ao_flight_landed && !landed_set) { + landed_set = 1; + landed_time = time; + landed_height = height; + } + + 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", + time, + height, + accel, + ao_state_names[ao_flight_state], + ao_k_height / 65536.0, + ao_k_speed / 65536.0 / 16.0, + ao_k_accel / 65536.0 / 16.0, + ao_avg_height, + drogue_height, + main_height, + ao_error_h_sq_avg); + +// if (ao_flight_state == ao_flight_landed) +// ao_test_exit(); + } + } +} + +#define AO_MAX_CALLSIGN 8 +#define AO_MAX_VERSION 8 +#define AO_MAX_TELEMETRY 128 + +struct ao_telemetry_generic { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t payload[27]; /* 5 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 +#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 +#define AO_TELEMETRY_SENSOR_TELENANO 0x03 + +struct ao_telemetry_sensor { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t state; /* 5 flight state */ + int16_t accel; /* 6 accelerometer (TM only) */ + int16_t pres; /* 8 pressure sensor */ + int16_t temp; /* 10 temperature sensor */ + int16_t v_batt; /* 12 battery voltage */ + int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ + int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ + + int16_t acceleration; /* 18 m/s² * 16 */ + int16_t speed; /* 20 m/s * 16 */ + int16_t height; /* 22 m */ + + int16_t ground_pres; /* 24 average pres on pad */ + int16_t ground_accel; /* 26 average accel on pad */ + int16_t accel_plus_g; /* 28 accel calibration at +1g */ + int16_t accel_minus_g; /* 30 accel calibration at -1g */ + /* 32 */ +}; + +#define AO_TELEMETRY_CONFIGURATION 0x04 + +struct ao_telemetry_configuration { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t device; /* 5 device type */ + uint16_t flight; /* 6 flight number */ + uint8_t config_major; /* 8 Config major version */ + uint8_t config_minor; /* 9 Config minor version */ + uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ + uint16_t main_deploy; /* 12 Main deploy alt in meters */ + uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ + char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ + char version[AO_MAX_VERSION]; /* 24 Software version */ + /* 32 */ +}; + +#define AO_TELEMETRY_LOCATION 0x05 + +#define AO_GPS_MODE_NOT_VALID 'N' +#define AO_GPS_MODE_AUTONOMOUS 'A' +#define AO_GPS_MODE_DIFFERENTIAL 'D' +#define AO_GPS_MODE_ESTIMATED 'E' +#define AO_GPS_MODE_MANUAL 'M' +#define AO_GPS_MODE_SIMULATED 'S' + +struct ao_telemetry_location { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t flags; /* 5 Number of sats and other flags */ + int16_t altitude; /* 6 GPS reported altitude (m) */ + int32_t latitude; /* 8 latitude (degrees * 10⁷) */ + int32_t longitude; /* 12 longitude (degrees * 10⁷) */ + uint8_t year; /* 16 (- 2000) */ + uint8_t month; /* 17 (1-12) */ + uint8_t day; /* 18 (1-31) */ + uint8_t hour; /* 19 (0-23) */ + uint8_t minute; /* 20 (0-59) */ + uint8_t second; /* 21 (0-59) */ + uint8_t pdop; /* 22 (m * 5) */ + uint8_t hdop; /* 23 (m * 5) */ + uint8_t vdop; /* 24 (m * 5) */ + uint8_t mode; /* 25 */ + uint16_t ground_speed; /* 26 cm/s */ + int16_t climb_rate; /* 28 cm/s */ + uint8_t course; /* 30 degrees / 2 */ + uint8_t unused[1]; /* 31 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SATELLITE 0x06 + +struct ao_telemetry_satellite_info { + uint8_t svid; + uint8_t c_n_1; +}; + +struct ao_telemetry_satellite { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t channels; /* 5 number of reported sats */ + + struct ao_telemetry_satellite_info sats[12]; /* 6 */ + uint8_t unused[2]; /* 30 */ + /* 32 */ +}; + +union ao_telemetry_all { + struct ao_telemetry_generic generic; + struct ao_telemetry_sensor sensor; + struct ao_telemetry_configuration configuration; + struct ao_telemetry_location location; + struct ao_telemetry_satellite satellite; +}; + +uint16_t +uint16(uint8_t *bytes, int off) +{ + off++; + return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8); +} + +int16_t +int16(uint8_t *bytes, int off) +{ + return (int16_t) uint16(bytes, off); +} + +void +ao_sleep(void *wchan) +{ + if (wchan == &ao_adc_head) { + char type; + uint16_t tick; + uint16_t a, b; + int ret; + uint8_t bytes[1024]; + union ao_telemetry_all telem; + char line[1024]; + char *saveptr; + char *l; + char *words[64]; + int nword; + + for (;;) { + if (ao_records_read > 2 && ao_flight_state == ao_flight_startup) + { + ao_adc_static.accel = ao_flight_ground_accel; + ao_insert(); + return; + } + + if (!fgets(line, sizeof (line), emulator_in)) { + if (++ao_eof_read >= 1000) { + if (!ao_summary) + printf ("no more data, exiting simulation\n"); + ao_test_exit(); + } + ao_adc_static.tick += 10; + ao_insert(); + return; + } + l = line; + for (nword = 0; nword < 64; nword++) { + words[nword] = strtok_r(l, " \t\n", &saveptr); + l = NULL; + if (words[nword] == NULL) + break; + } + if (nword == 4) { + 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'; + } 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]); + } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { + ao_config.main_deploy = atoi(words[2]); + } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { + tick = atoi(words[10]); + if (!ao_flight_started) { + type = 'F'; + a = atoi(words[26]); + ao_flight_started = 1; + } else { + type = 'A'; + a = atoi(words[12]); + b = atoi(words[14]); + } + } else if (nword == 3 && strcmp(words[0], "BARO") == 0) { + tick = strtol(words[1], NULL, 16); + a = 16384 - 328; + b = strtol(words[2], NULL, 10); + type = 'A'; + if (!ao_flight_started) { + ao_flight_ground_accel = 16384 - 328; + ao_config.accel_plus_g = 16384 - 328; + ao_config.accel_minus_g = 16384 + 328; + ao_flight_started = 1; + } + } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { + char *hex = words[1]; + char elt[3]; + int i, len; + uint8_t sum; + + len = strlen(hex); + if (len > sizeof (bytes) * 2) { + len = sizeof (bytes)*2; + hex[len] = '\0'; + } + for (i = 0; i < len; i += 2) { + elt[0] = hex[i]; + elt[1] = hex[i+1]; + elt[2] = '\0'; + bytes[i/2] = (uint8_t) strtol(elt, NULL, 16); + } + len = i/2; + if (bytes[0] != len - 2) { + printf ("bad length %d != %d\n", bytes[0], len - 2); + continue; + } + sum = 0x5a; + for (i = 1; i < len-1; i++) + sum += bytes[i]; + if (sum != bytes[len-1]) { + printf ("bad checksum\n"); + continue; + } + if ((bytes[len-2] & 0x80) == 0) { + continue; + } + if (len == 36) { + memcpy(&telem, bytes + 1, 32); + tick = telem.generic.tick; + switch (telem.generic.type) { + case AO_TELEMETRY_SENSOR_TELEMETRUM: + case AO_TELEMETRY_SENSOR_TELEMINI: + case AO_TELEMETRY_SENSOR_TELENANO: + if (!ao_flight_started) { + ao_flight_ground_accel = telem.sensor.ground_accel; + ao_config.accel_plus_g = telem.sensor.accel_plus_g; + ao_config.accel_minus_g = telem.sensor.accel_minus_g; + ao_flight_started = 1; + } + type = 'A'; + a = telem.sensor.accel; + b = telem.sensor.pres; + break; + } + } 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); + type = 'A'; + a = int16(bytes, 23); + b = int16(bytes, 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); + type = 'A'; + a = int16(bytes, 22); + b = int16(bytes, 24); + } else { + printf("unknown len %d\n", len); + continue; + } + } + if (type != 'F' && !ao_flight_started) + continue; + + switch (type) { + case 'F': + ao_flight_ground_accel = a; + if (ao_config.accel_plus_g == 0) { + ao_config.accel_plus_g = a; + ao_config.accel_minus_g = a + 530; + } + if (ao_config.main_deploy == 0) + ao_config.main_deploy = 250; + ao_flight_started = 1; + break; + case 'S': + break; + case 'A': + ao_adc_static.tick = tick; + ao_adc_static.accel = a; + ao_adc_static.pres_real = b; + if (b < AO_MIN_BARO_VALUE) + b = AO_MIN_BARO_VALUE; + ao_adc_static.pres = b; + ao_records_read++; + ao_insert(); + return; + case 'T': + ao_adc_static.tick = tick; + ao_adc_static.temp = a; + ao_adc_static.v_batt = b; + break; + case 'D': + case 'G': + case 'N': + case 'W': + case 'H': + break; + } + } + + } +} +#define COUNTS_PER_G 264.8 + +void +ao_dump_state(void) +{ +} + +static const struct option options[] = { + { .name = "summary", .has_arg = 0, .val = 's' }, + { .name = "debug", .has_arg = 0, .val = 'd' }, + { 0, 0, 0, 0}, +}; + +void run_flight_fixed(char *name, FILE *f, int summary) +{ + emulator_name = name; + emulator_in = f; + ao_summary = summary; + ao_flight_init(); + ao_flight(); +} + +int +main (int argc, char **argv) +{ + int summary = 0; + int c; + int i; + +#if HAS_ACCEL + emulator_app="full"; +#else + emulator_app="baro"; +#endif + while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) { + switch (c) { + case 's': + summary = 1; + break; + case 'd': + ao_flight_debug = 1; + break; + } + } + + if (optind == argc) + run_flight_fixed("", stdin, summary); + 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); + fclose(f); + } +} diff --git a/src/test/ao_gps_test.c b/src/test/ao_gps_test.c new file mode 100644 index 00000000..93d7a9ab --- /dev/null +++ b/src/test/ao_gps_test.c @@ -0,0 +1,508 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#include +#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_gps_orig { + 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 hdop; /* * 5 */ + int16_t climb_rate; /* cm/s */ + uint16_t h_error; /* m */ + uint16_t v_error; /* m */ +}; + +#define SIRF_SAT_STATE_ACQUIRED (1 << 0) +#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1) +#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2) +#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3) +#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4) +#define SIRF_SAT_CODE_LOCKED (1 << 5) +#define SIRF_SAT_ACQUISITION_FAILED (1 << 6) +#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7) + +struct ao_gps_sat_orig { + uint8_t svid; + uint8_t c_n_1; +}; + +#define AO_MAX_GPS_TRACKING 12 + +struct ao_gps_tracking_orig { + uint8_t channels; + struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; +}; + +#define ao_telemetry_location ao_gps_orig +#define ao_telemetry_satellite ao_gps_tracking_orig +#define ao_telemetry_satellite_info ao_gps_sat_orig + +void +ao_mutex_get(uint8_t *mutex) +{ +} + +void +ao_mutex_put(uint8_t *mutex) +{ +} + +static int +ao_gps_fd; + +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)); +} + +#define QUEUE_LEN 4096 + +static char input_queue[QUEUE_LEN]; +int input_head, input_tail; + +#include + +int +get_millis(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static void +check_sirf_message(char *from, uint8_t *msg, int len) +{ + uint16_t encoded_len, encoded_cksum; + uint16_t cksum; + uint8_t id; + int i; + + if (msg[0] != 0xa0 || msg[1] != 0xa2) { + printf ("bad header\n"); + return; + } + if (len < 7) { + printf("short\n"); + return; + } + if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { + printf ("bad trailer\n"); + return; + } + encoded_len = (msg[2] << 8) | msg[3]; + id = msg[4]; +/* printf ("%9d: %3d\n", get_millis(), id); */ + if (encoded_len != len - 8) { + if (id != 52) + printf ("length mismatch (got %d, wanted %d)\n", + len - 8, encoded_len); + return; + } + encoded_cksum = (msg[len - 4] << 8) | msg[len-3]; + cksum = 0; + for (i = 4; i < len - 4; i++) + cksum = (cksum + msg[i]) & 0x7fff; + if (encoded_cksum != cksum) { + printf ("cksum mismatch (got %04x wanted %04x)\n", + cksum, encoded_cksum); + return; + } + id = msg[4]; + switch (id) { + case 41:{ + int off = 4; + + uint8_t id; + uint16_t nav_valid; + uint16_t nav_type; + uint16_t week; + uint32_t tow; + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint16_t second; + uint32_t sat_list; + int32_t lat; + int32_t lon; + int32_t alt_ell; + int32_t alt_msl; + int8_t datum; + uint16_t sog; + uint16_t cog; + int16_t mag_var; + int16_t climb_rate; + int16_t heading_rate; + uint32_t h_error; + uint32_t v_error; + uint32_t t_error; + uint16_t h_v_error; + +#define get_u8(u) u = (msg[off]); off+= 1 +#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 +#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 + + get_u8(id); + get_u16(nav_valid); + get_u16(nav_type); + get_u16(week); + get_u32(tow); + get_u16(year); + get_u8(month); + get_u8(day); + get_u8(hour); + get_u8(minute); + get_u16(second); + get_u32(sat_list); + get_u32(lat); + get_u32(lon); + get_u32(alt_ell); + get_u32(alt_msl); + get_u8(datum); + get_u16(sog); + get_u16(cog); + get_u16(mag_var); + get_u16(climb_rate); + get_u16(heading_rate); + get_u32(h_error); + get_u32(v_error); + get_u32(t_error); + get_u16(h_v_error); + + + printf ("Geodetic Navigation Data (41):\n"); + printf ("\tNav valid %04x\n", nav_valid); + printf ("\tNav type %04x\n", nav_type); + printf ("\tWeek %5d", week); + printf (" TOW %9d", tow); + printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n", + year, month, day, + hour, minute, second / 1000.0); + printf ("\tsats: %08x\n", sat_list); + printf ("\tlat: %g", lat / 1.0e7); + printf (" lon: %g", lon / 1.0e7); + printf (" alt_ell: %g", alt_ell / 100.0); + printf (" alt_msll: %g", alt_msl / 100.0); + printf (" datum: %d\n", datum); + printf ("\tground speed: %g", sog / 100.0); + printf (" course: %g", cog / 100.0); + printf (" climb: %g", climb_rate / 100.0); + printf (" heading rate: %g\n", heading_rate / 100.0); + printf ("\th error: %g", h_error / 100.0); + printf (" v error: %g", v_error / 100.0); + printf (" t error: %g", t_error / 100.0); + printf (" h vel error: %g\n", h_v_error / 100.0); + break; + } + case 4: { + int off = 4; + uint8_t id; + int16_t gps_week; + uint32_t gps_tow; + uint8_t channels; + int j, k; + + get_u8(id); + get_u16(gps_week); + get_u32(gps_tow); + get_u8(channels); + + printf ("Measured Tracker Data (4):\n"); + printf ("GPS week: %d\n", gps_week); + printf ("GPS time of week: %d\n", gps_tow); + printf ("channels: %d\n", channels); + for (j = 0; j < 12; j++) { + uint8_t svid, azimuth, elevation; + uint16_t state; + uint8_t c_n[10]; + get_u8(svid); + get_u8(azimuth); + get_u8(elevation); + get_u16(state); + for (k = 0; k < 10; k++) { + get_u8(c_n[k]); + } + printf ("Sat %3d:", svid); + printf (" aziumuth: %6.1f", azimuth * 1.5); + printf (" elevation: %6.1f", elevation * 0.5); + printf (" state: 0x%02x", state); + printf (" c_n:"); + for (k = 0; k < 10; k++) + printf(" %3d", c_n[k]); + if (state & SIRF_SAT_STATE_ACQUIRED) + printf(" acq,"); + if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID) + printf(" car,"); + if (state & SIRF_SAT_BIT_SYNC_COMPLETE) + printf(" bit,"); + if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE) + printf(" sub,"); + if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE) + printf(" pullin,"); + if (state & SIRF_SAT_CODE_LOCKED) + printf(" code,"); + if (state & SIRF_SAT_ACQUISITION_FAILED) + printf(" fail,"); + if (state & SIRF_SAT_EPHEMERIS_AVAILABLE) + printf(" ephem,"); + printf ("\n"); + } + break; + } + default: + return; + printf ("%s %4d:", from, encoded_len); + for (i = 4; i < len - 4; i++) { + if (((i - 4) & 0xf) == 0) + printf("\n "); + printf (" %3d", msg[i]); + } + printf ("\n"); + } +} + +static uint8_t sirf_message[4096]; +static int sirf_message_len; +static uint8_t sirf_in_message[4096]; +static int sirf_in_len; + +char +ao_serial_getchar(void) +{ + char c; + uint8_t uc; + + while (input_head == input_tail) { + for (;;) { + input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); + if (input_tail < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + perror ("getchar"); + exit (1); + } + input_head = 0; + break; + } + } + c = input_queue[input_head]; + input_head = (input_head + 1) % QUEUE_LEN; + uc = c; + if (sirf_in_len || uc == 0xa0) { + if (sirf_in_len < 4096) + sirf_in_message[sirf_in_len++] = uc; + if (uc == 0xb3) { + check_sirf_message("recv", sirf_in_message, sirf_in_len); + sirf_in_len = 0; + } + } + return c; +} + + +void +ao_serial_putchar(char c) +{ + int i; + uint8_t uc = (uint8_t) c; + + if (sirf_message_len || uc == 0xa0) { + if (sirf_message_len < 4096) + sirf_message[sirf_message_len++] = uc; + if (uc == 0xb3) { + check_sirf_message("send", sirf_message, sirf_message_len); + sirf_message_len = 0; + } + } + for (;;) { + i = write(ao_gps_fd, &c, 1); + if (i == 1) { + if ((uint8_t) c == 0xb3 || c == '\r') { + static const struct timespec delay = { + .tv_sec = 0, + .tv_nsec = 100 * 1000 * 1000 + }; + tcdrain(ao_gps_fd); +// nanosleep(&delay, NULL); + } + break; + } + if (i < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + perror("putchar"); + exit(1); + } +} + +#define AO_SERIAL_SPEED_4800 0 +#define AO_SERIAL_SPEED_57600 1 + +static void +ao_serial_set_speed(uint8_t speed) +{ + int fd = ao_gps_fd; + struct termios termios; + + tcdrain(fd); + tcgetattr(fd, &termios); + switch (speed) { + case AO_SERIAL_SPEED_4800: + cfsetspeed(&termios, B4800); + break; + case AO_SERIAL_SPEED_57600: + cfsetspeed(&termios, B57600); + break; + } + tcsetattr(fd, TCSAFLUSH, &termios); + tcflush(fd, TCIFLUSH); +} + +#define ao_time() 0 + +#include "ao_gps_print.c" +#include "ao_gps_sirf.c" + +void +ao_dump_state(void *wchan) +{ + double lat, lon; + int i; + if (wchan == &ao_gps_data) + ao_gps_print(&ao_gps_data); + else + ao_gps_tracking_print(&ao_gps_tracking_data); + putchar('\n'); + return; + printf ("%02d:%02d:%02d", + ao_gps_data.hour, ao_gps_data.minute, + ao_gps_data.second); + printf (" nsat %d %svalid", + ao_gps_data.flags & AO_GPS_NUM_SAT_MASK, + ao_gps_data.flags & AO_GPS_VALID ? "" : "not "); + printf (" lat %g lon %g alt %d", + ao_gps_data.latitude / 1.0e7, + ao_gps_data.longitude / 1.0e7, + ao_gps_data.altitude); + printf (" speed %g climb %g course %d", + ao_gps_data.ground_speed / 100.0, + ao_gps_data.climb_rate / 100.0, + ao_gps_data.course * 2); + printf (" hdop %g h_error %d v_error %d", + ao_gps_data.hdop / 5.0, + ao_gps_data.h_error, ao_gps_data.v_error); + printf("\n"); + printf ("\t"); + for (i = 0; i < 12; i++) + printf (" %2d(%02d)", + ao_gps_tracking_data.sats[i].svid, + ao_gps_tracking_data.sats[i].c_n_1); + printf ("\n"); +} + +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 + +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 ]\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_setup(); + ao_gps(); +} diff --git a/src/test/ao_gps_test_skytraq.c b/src/test/ao_gps_test_skytraq.c new file mode 100644 index 00000000..a78fae0f --- /dev/null +++ b/src/test/ao_gps_test_skytraq.c @@ -0,0 +1,490 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#include +#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_gps_orig { + 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 hdop; /* * 5 */ + int16_t climb_rate; /* cm/s */ + uint16_t h_error; /* m */ + uint16_t v_error; /* m */ +}; + +#define SIRF_SAT_STATE_ACQUIRED (1 << 0) +#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1) +#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2) +#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3) +#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4) +#define SIRF_SAT_CODE_LOCKED (1 << 5) +#define SIRF_SAT_ACQUISITION_FAILED (1 << 6) +#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7) + +struct ao_gps_sat_orig { + uint8_t svid; + uint8_t c_n_1; +}; + +#define AO_MAX_GPS_TRACKING 12 + +struct ao_gps_tracking_orig { + uint8_t channels; + struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING]; +}; + +#define ao_telemetry_location ao_gps_orig +#define ao_telemetry_satellite ao_gps_tracking_orig +#define ao_telemetry_satellite_info ao_gps_sat_orig + +void +ao_mutex_get(uint8_t *mutex) +{ +} + +void +ao_mutex_put(uint8_t *mutex) +{ +} + +static int +ao_gps_fd; + +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)); +} + +#define QUEUE_LEN 4096 + +static char input_queue[QUEUE_LEN]; +int input_head, input_tail; + +#include + +int +get_millis(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static void +check_skytraq_message(char *from, uint8_t *msg, int len) +{ + uint16_t encoded_len, encoded_cksum; + uint16_t cksum; + uint8_t id; + int i; + +// fwrite(msg, 1, len, stdout); + return; + if (msg[0] != 0xa0 || msg[1] != 0xa2) { + printf ("bad header\n"); + return; + } + if (len < 7) { + printf("short\n"); + return; + } + if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) { + printf ("bad trailer\n"); + return; + } + encoded_len = (msg[2] << 8) | msg[3]; + id = msg[4]; +/* printf ("%9d: %3d\n", get_millis(), id); */ + if (encoded_len != len - 8) { + if (id != 52) + printf ("length mismatch (got %d, wanted %d)\n", + len - 8, encoded_len); + return; + } + encoded_cksum = (msg[len - 4] << 8) | msg[len-3]; + cksum = 0; + for (i = 4; i < len - 4; i++) + cksum = (cksum + msg[i]) & 0x7fff; + if (encoded_cksum != cksum) { + printf ("cksum mismatch (got %04x wanted %04x)\n", + cksum, encoded_cksum); + return; + } + id = msg[4]; + switch (id) { + case 41:{ + int off = 4; + + uint8_t id; + uint16_t nav_valid; + uint16_t nav_type; + uint16_t week; + uint32_t tow; + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint16_t second; + uint32_t sat_list; + int32_t lat; + int32_t lon; + int32_t alt_ell; + int32_t alt_msl; + int8_t datum; + uint16_t sog; + uint16_t cog; + int16_t mag_var; + int16_t climb_rate; + int16_t heading_rate; + uint32_t h_error; + uint32_t v_error; + uint32_t t_error; + uint16_t h_v_error; + +#define get_u8(u) u = (msg[off]); off+= 1 +#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2 +#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4 + + get_u8(id); + get_u16(nav_valid); + get_u16(nav_type); + get_u16(week); + get_u32(tow); + get_u16(year); + get_u8(month); + get_u8(day); + get_u8(hour); + get_u8(minute); + get_u16(second); + get_u32(sat_list); + get_u32(lat); + get_u32(lon); + get_u32(alt_ell); + get_u32(alt_msl); + get_u8(datum); + get_u16(sog); + get_u16(cog); + get_u16(mag_var); + get_u16(climb_rate); + get_u16(heading_rate); + get_u32(h_error); + get_u32(v_error); + get_u32(t_error); + get_u16(h_v_error); + + + printf ("Geodetic Navigation Data (41):\n"); + printf ("\tNav valid %04x\n", nav_valid); + printf ("\tNav type %04x\n", nav_type); + printf ("\tWeek %5d", week); + printf (" TOW %9d", tow); + printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n", + year, month, day, + hour, minute, second / 1000.0); + printf ("\tsats: %08x\n", sat_list); + printf ("\tlat: %g", lat / 1.0e7); + printf (" lon: %g", lon / 1.0e7); + printf (" alt_ell: %g", alt_ell / 100.0); + printf (" alt_msll: %g", alt_msl / 100.0); + printf (" datum: %d\n", datum); + printf ("\tground speed: %g", sog / 100.0); + printf (" course: %g", cog / 100.0); + printf (" climb: %g", climb_rate / 100.0); + printf (" heading rate: %g\n", heading_rate / 100.0); + printf ("\th error: %g", h_error / 100.0); + printf (" v error: %g", v_error / 100.0); + printf (" t error: %g", t_error / 100.0); + printf (" h vel error: %g\n", h_v_error / 100.0); + break; + } + case 4: { + int off = 4; + uint8_t id; + int16_t gps_week; + uint32_t gps_tow; + uint8_t channels; + int j, k; + + get_u8(id); + get_u16(gps_week); + get_u32(gps_tow); + get_u8(channels); + + printf ("Measured Tracker Data (4):\n"); + printf ("GPS week: %d\n", gps_week); + printf ("GPS time of week: %d\n", gps_tow); + printf ("channels: %d\n", channels); + for (j = 0; j < 12; j++) { + uint8_t svid, azimuth, elevation; + uint16_t state; + uint8_t c_n[10]; + get_u8(svid); + get_u8(azimuth); + get_u8(elevation); + get_u16(state); + for (k = 0; k < 10; k++) { + get_u8(c_n[k]); + } + printf ("Sat %3d:", svid); + printf (" aziumuth: %6.1f", azimuth * 1.5); + printf (" elevation: %6.1f", elevation * 0.5); + printf (" state: 0x%02x", state); + printf (" c_n:"); + for (k = 0; k < 10; k++) + printf(" %3d", c_n[k]); + if (state & SIRF_SAT_STATE_ACQUIRED) + printf(" acq,"); + if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID) + printf(" car,"); + if (state & SIRF_SAT_BIT_SYNC_COMPLETE) + printf(" bit,"); + if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE) + printf(" sub,"); + if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE) + printf(" pullin,"); + if (state & SIRF_SAT_CODE_LOCKED) + printf(" code,"); + if (state & SIRF_SAT_ACQUISITION_FAILED) + printf(" fail,"); + if (state & SIRF_SAT_EPHEMERIS_AVAILABLE) + printf(" ephem,"); + printf ("\n"); + } + break; + } + default: + return; + printf ("%s %4d:", from, encoded_len); + for (i = 4; i < len - 4; i++) { + if (((i - 4) & 0xf) == 0) + printf("\n "); + printf (" %3d", msg[i]); + } + printf ("\n"); + } +} + +static uint8_t skytraq_message[4096]; +static int skytraq_message_len; +static uint8_t skytraq_in_message[4096]; +static int skytraq_in_len; + +char +ao_serial_getchar(void) +{ + char c; + uint8_t uc; + + while (input_head == input_tail) { + for (;;) { + input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN); + if (input_tail < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + perror ("getchar"); + exit (1); + } + input_head = 0; + break; + } + } + c = input_queue[input_head]; + input_head = (input_head + 1) % QUEUE_LEN; + uc = c; +// printf ("c: %02x %c\n", uc, uc); + if (skytraq_in_len || uc == '$') { + if (skytraq_in_len < 4096) + skytraq_in_message[skytraq_in_len++] = uc; + if (uc == 0x0a) { + check_skytraq_message("recv", skytraq_in_message, skytraq_in_len); + skytraq_in_len = 0; + } + } + return c; +} + + +void +ao_serial_putchar(char c) +{ + int i; + uint8_t uc = (uint8_t) c; + + if (skytraq_message_len || uc == 0xa0) { + if (skytraq_message_len < 4096) + skytraq_message[skytraq_message_len++] = uc; + if (uc == 0x0a) { + check_skytraq_message("send", skytraq_message, skytraq_message_len); + skytraq_message_len = 0; + } + } + for (;;) { + i = write(ao_gps_fd, &c, 1); + if (i == 1) { + if ((uint8_t) c == 0xb3 || c == '\r') { + static const struct timespec delay = { + .tv_sec = 0, + .tv_nsec = 100 * 1000 * 1000 + }; + tcdrain(ao_gps_fd); +// nanosleep(&delay, NULL); + } + 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 + +static void +ao_serial_set_speed(uint8_t speed) +{ + int fd = ao_gps_fd; + struct termios termios; + + tcdrain(fd); + tcgetattr(fd, &termios); + switch (speed) { + case AO_SERIAL_SPEED_4800: + cfsetspeed(&termios, B4800); + break; + case AO_SERIAL_SPEED_9600: + cfsetspeed(&termios, B38400); + break; + case AO_SERIAL_SPEED_57600: + cfsetspeed(&termios, B57600); + break; + } + tcsetattr(fd, TCSAFLUSH, &termios); + tcflush(fd, TCIFLUSH); +} + +#define ao_time() 0 + +#include "ao_gps_print.c" +#include "ao_gps_skytraq.c" + +void +ao_dump_state(void *wchan) +{ + double lat, lon; + int i; + 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 + +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 ]\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(); +} diff --git a/src/tidongle/Makefile b/src/tidongle/Makefile index d8867b19..fc8df1f4 100644 --- a/src/tidongle/Makefile +++ b/src/tidongle/Makefile @@ -1 +1,92 @@ -include ../Makefile.proto +# +# TIDongle build file +# + +vpath %.c ..:../core:../cc1111:../drivers:../product +vpath %.h ..:../core:../cc1111:../drivers:../product +vpath ao-make-product.5c ../util + +ifndef VERSION +include ../Version +endif + +INC = \ + ao.h \ + ao_pins.h \ + cc1111.h \ + ao_product.h + +CORE_SRC = \ + ao_cmd.c \ + ao_config.c \ + ao_gps_print.c \ + ao_monitor.c \ + ao_mutex.c \ + ao_panic.c \ + ao_rssi.c \ + ao_state.c \ + ao_stdio.c \ + ao_task.c + +CC1111_SRC = \ + ao_dbg.c \ + ao_dma.c \ + ao_led.c \ + ao_packet.c \ + ao_packet_master.c \ + ao_radio.c \ + ao_romconfig.c \ + ao_timer.c \ + ao_usb.c \ + _bp.c + +DRIVER_SRC = + +PRODUCT_SRC = \ + ao_tidongle.c + +SRC = \ + $(CORE_SRC) \ + $(CC1111_SRC) \ + $(DRIVER_SRC) \ + $(PRODUCT_SRC) + +PROG = tidongle-$(VERSION).ihx +PRODUCT=TIDongle +PRODUCT_DEF=-DTIDONGLE +IDPRODUCT=0x000a + +include ../cc1111/Makefile.cc1111 + +NICKLE=nickle +CHECK_STACK=sh ../util/check-stack + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: ../$(PROG) + +../$(PROG): $(REL) Makefile + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. + $(call quiet,CHECK_STACK) ../core/ao.h $(PMEM) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) + rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + rm -f ao_product.h + rm -f ../$(PROG) ../$(PMAP) + +install: + +uninstall: + diff --git a/src/tidongle/Makefile.defs b/src/tidongle/Makefile.defs deleted file mode 100644 index 0e13cb20..00000000 --- a/src/tidongle/Makefile.defs +++ /dev/null @@ -1,9 +0,0 @@ -PROG = tidongle-$(VERSION).ihx - -SRC = \ - $(TI_SRC) - -PRODUCT=TIDongle - -PRODUCT_DEF=-DTIDONGLE -IDPRODUCT=0x000a diff --git a/src/util/ao-make-product.5c b/src/util/ao-make-product.5c new file mode 100644 index 00000000..5f2eb8e8 --- /dev/null +++ b/src/util/ao-make-product.5c @@ -0,0 +1,103 @@ +#!/bin/sh + +autoimport ParseArgs; + +void +write_ucs2(string a, string description) +{ + int len = String::length(a); + + printf("/* %s */\n", description); + printf("#define AO_%s_LEN 0x%02x\n", description, len * 2 + 2); + printf("#define AO_%s_STRING \"%s\"\n", description, a); + printf("#define AO_%s_UCS2", description); + for (int i = 0; i < len; i++) { + int c = a[i]; + if (i > 0) + printf(","); + if (0x20 <= c && c < 128) + printf(" '%c', 0", c); + else + printf(" LE_WORD(0x%04x),", c); + } + printf("\n\n"); +} + +void +write_string(string a, string description) +{ + printf ("/* %s */\n", description); + printf ("#define AO_%s_STRING \"%s\"\n", description, a); +} + +void +write_int(int a, string description) +{ + printf ("/* %s */\n", description); + printf ("#define AO_%s_NUMBER %d\n\n", description, a); +} + +void +write_hex(int a, string description) +{ + printf ("/* %s */\n", description); + printf ("#define AO_%s_NUMBER 0x%04x\n\n", description, a); +} + +string manufacturer = "altusmetrum.org"; +string product = "TeleMetrum"; +string version = "0.0"; +int serial = 1; +int user_argind = 0; +int id_product = 0x000a; + +argdesc argd = { + .args = { + { + .var = { .arg_string = &manufacturer }, + .abbr = 'm', + .name = "manufacturer", + .expr_name = "manf", + .desc = "Manufacturer name." }, + { + .var = { .arg_string = &product }, + .abbr = 'p', + .name = "product", + .expr_name = "prod", + .desc = "Product name." }, + { + .var = { .arg_int = &id_product }, + .abbr = 'i', + .name = "id_product", + .expr_name = "id_p", + .desc = "Product ID." }, + { + .var = { .arg_int = &serial }, + .abbr = 's', + .name = "serial", + .expr_name = "number", + .desc = "Serial number." }, + { + .var = { .arg_string = &version }, + .abbr = 'v', + .name = "version", + .expr_name = "string", + .desc = "Program version." }, + }, + .prog_name = "usb descriptors", +}; + +void +main() +{ + string[dim(argv)-1] nargv = {[n] = argv[n+1]}; + parseargs(&argd, &nargv); + write_ucs2(manufacturer, "iManufacturer"); + write_ucs2(product, "iProduct"); + write_ucs2(sprintf("%06d", serial), "iSerial"); + write_int(serial, "iSerial"); + write_hex(id_product, "idProduct"); + write_string(version, "iVersion"); +} + +main(); diff --git a/src/util/check-stack b/src/util/check-stack new file mode 100755 index 00000000..1e8044e0 --- /dev/null +++ b/src/util/check-stack @@ -0,0 +1,13 @@ +#!/bin/sh +HEADER=$1 +MEM=$2 + +HEADER_STACK=`awk '/#define AO_STACK_START/ {print strtonum($3)}' $HEADER` +MEM_STACK=`awk '/Stack starts at/ {print strtonum ($4)}' $MEM` + +if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then + echo $MEM_STACK | awk '{ printf ("Set AO_STACK_START to at least 0x%x\n", $1); }' + exit 1 +else + exit 0 +fi diff --git a/src/util/gps-cksum b/src/util/gps-cksum new file mode 100755 index 00000000..a08153bf --- /dev/null +++ b/src/util/gps-cksum @@ -0,0 +1,17 @@ +#!/usr/bin/env nickle + +int checksum(string a) +{ + int c = 0; + for (int i = 0; i < String::length(a); i++) + c ^= a[i]; + return c; +} + +void main() +{ + for (int i = 1; i < dim(argv); i++) + printf ("$%s*%02x\n", argv[i], checksum(argv[i])); +} + +main(); diff --git a/src/util/make-altitude b/src/util/make-altitude new file mode 100644 index 00000000..716aa8a8 --- /dev/null +++ b/src/util/make-altitude @@ -0,0 +1,283 @@ +#!/usr/bin/nickle -f +/* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * pow(base, exponent); + } + + return pressure; +} + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ +real pressure_to_altitude(real pressure) { + + real next_base_temperature = LAYER0_BASE_TEMPERATURE; + real next_base_pressure = LAYER0_BASE_PRESSURE; + + real altitude; + real base_pressure; + real base_temperature; + real base; /* base for function to determine base pressure of next layer */ + real exponent; /* exponent for function to determine base pressure + of next layer */ + real coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (pow(base, exponent) - 1); + } + + return altitude; +} + +real feet_to_meters(real feet) +{ + return feet * (12 * 2.54 / 100); +} + +real meters_to_feet(real meters) +{ + return meters / (12 * 2.54 / 100); +} + +/* + * Values for our MP3H6115A pressure sensor + * + * From the data sheet: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * + * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa + * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa + */ + +real counts_per_kPa = 27 * 2047 / 3300; +real counts_at_101_3kPa = 1674; + +real fraction_to_kPa(real fraction) +{ + return (fraction + 0.095) / 0.009; +} + + +real count_to_kPa(real count) = fraction_to_kPa(count / 2047); + +typedef struct { + real m, b; + int m_i, b_i; +} line_t; + +line_t best_fit(real[] values, int first, int last) { + real sum_x = 0, sum_x2 = 0, sum_y = 0, sum_xy = 0; + int n = last - first + 1; + real m, b; + int m_i, b_i; + + for (int i = first; i <= last; i++) { + sum_x += i; + sum_x2 += i**2; + sum_y += values[i]; + sum_xy += values[i] * i; + } + m = (n*sum_xy - sum_y*sum_x) / (n*sum_x2 - sum_x**2); + b = sum_y/n - m*(sum_x/n); + return (line_t) { m = m, b = b }; +} + +real count_to_altitude(real count) { + return pressure_to_altitude(count_to_kPa(count) * 1000); +} + +real fraction_to_altitude(real frac) = pressure_to_altitude(fraction_to_kPa(frac) * 1000); + +int num_samples = 1024; + +real[num_samples] alt = { [n] = fraction_to_altitude(n/(num_samples - 1)) }; + +int num_part = 128; +int seg_len = num_samples / num_part; + +line_t [dim(alt) / seg_len] fit = { + [n] = best_fit(alt, n * seg_len, n * seg_len + seg_len - 1) +}; + +int[num_samples/seg_len + 1] alt_part; + +alt_part[0] = floor (fit[0].b + 0.5); +alt_part[dim(fit)] = floor(fit[dim(fit)-1].m * dim(fit) * seg_len + fit[dim(fit)-1].b + 0.5); + +for (int i = 0; i < dim(fit) - 1; i++) { + real here, there; + here = fit[i].m * (i+1) * seg_len + fit[i].b; + there = fit[i+1].m * (i+1) * seg_len + fit[i+1].b; + alt_part[i+1] = floor ((here + there) / 2 + 0.5); +} + +real count_to_fit_altitude(int count) { + int sub = count // seg_len; + int off = count % seg_len; + line_t l = fit[sub]; + real r_v; + real i_v; + + r_v = count * l.m + l.b; + i_v = (alt_part[sub] * (seg_len - off) + alt_part[sub+1] * off) / seg_len; + return i_v; +} + +real max_error = 0; +int max_error_count = 0; +real total_error = 0; + +for (int count = 0; count < num_samples; count++) { + real kPa = fraction_to_kPa(count / (num_samples - 1)); + real meters = pressure_to_altitude(kPa * 1000); + + real meters_approx = count_to_fit_altitude(count); + real error = abs(meters - meters_approx); + + total_error += error; + if (error > max_error) { + max_error = error; + max_error_count = count; + } +# printf (" %7d, /* %6.2g kPa %5d count approx %d */\n", +# floor (meters + 0.5), kPa, count, floor(count_to_fit_altitude(count) + 0.5)); +} + +printf ("/*max error %f at %7.3f%%. Average error %f*/\n", max_error, max_error_count / (num_samples - 1) * 100, total_error / num_samples); + +printf ("#define NALT %d\n", dim(alt_part)); +printf ("#define ALT_FRAC_BITS %d\n", floor (log2(32768/(dim(alt_part)-1)) + 0.1)); + +for (int i = 0; i < dim(alt_part); i++) { + real fraction = i / (dim(alt_part) - 1); + real kPa = fraction_to_kPa(fraction); + printf ("%9d, /* %6.2f kPa %7.3f%% */\n", + alt_part[i], kPa, fraction * 100); +} diff --git a/src/util/make-kalman b/src/util/make-kalman new file mode 100644 index 00000000..f78f30a9 --- /dev/null +++ b/src/util/make-kalman @@ -0,0 +1,19 @@ +#!/bin/sh + +cd $1 >&/dev/null + +SIGMA_BOTH="-M 2 -H 6 -A 2" +SIGMA_BARO="-M 2 -H 6 -A 2" +SIGMA_ACCEL="-M 2 -H 4 -A 4" + +nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH +nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH +nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH + +nickle kalman.5c -p AO_ACCEL -c accel -t 0.01 $SIGMA_ACCEL +nickle kalman.5c -p AO_ACCEL -c accel -t 0.1 $SIGMA_ACCEL +nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL + +nickle kalman.5c -p AO_BARO -c baro -t 0.01 $SIGMA_BARO +nickle kalman.5c -p AO_BARO -c baro -t 0.1 $SIGMA_BARO +nickle kalman.5c -p AO_BARO -c baro -t 1 $SIGMA_BARO diff --git a/src/util/sirf-cksum b/src/util/sirf-cksum new file mode 100755 index 00000000..b905f318 --- /dev/null +++ b/src/util/sirf-cksum @@ -0,0 +1,44 @@ +#!/usr/bin/env nickle + +int checksum(int[] msg) +{ + int sum = 0; + for (int i = 0; i < dim(msg); i++) { + sum += msg[i]; + sum &= 0x7fff; + } + return sum; +} + +void main() +{ + string[...] input; + int[...] msg; + + setdim(input, 0); + while (!File::end(stdin)) { + input[dim(input)] = gets(); + } + + setdim(msg, 0); + for (int i = 0; i < dim(input); i++) { + string[*] words = String::wordsplit(input[i], " ,\t"); + for (int j = 0; j < dim(words); j++) { + if (words[j] == "/" + "*") + break; + if (String::length(words[j]) > 0 && + Ctype::isdigit(words[j][0])) { + msg[dim(msg)] = string_to_integer(words[j]); + } + } + } + printf("\t0xa0, 0xa2, 0x%02x, 0x%02x,\t/* length: %d bytes */\n", + dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); + for (int i = 0; i < dim(input); i++) + printf("%s\n", input[i]); + int csum = checksum(msg); + printf ("\t0x%02x, 0x%02x, 0xb0, 0xb3,\n", + csum >> 8, csum & 0xff); +} + +main(); diff --git a/src/util/skytraq-cksum b/src/util/skytraq-cksum new file mode 100644 index 00000000..ab0464a7 --- /dev/null +++ b/src/util/skytraq-cksum @@ -0,0 +1,44 @@ +#!/usr/bin/env nickle + +int checksum(int[] msg) +{ + int sum = 0; + for (int i = 0; i < dim(msg); i++) { + sum ^= msg[i]; + sum &= 0xff; + } + return sum; +} + +void main() +{ + string[...] input; + int[...] msg; + + setdim(input, 0); + while (!File::end(stdin)) { + input[dim(input)] = gets(); + } + + setdim(msg, 0); + for (int i = 0; i < dim(input); i++) { + string[*] words = String::wordsplit(input[i], " ,\t"); + for (int j = 0; j < dim(words); j++) { + if (words[j] == "/" + "*") + break; + if (String::length(words[j]) > 0 && + Ctype::isdigit(words[j][0])) { + msg[dim(msg)] = string_to_integer(words[j]); + } + } + } + printf("\t0xa0, 0xa1, 0x%02x, 0x%02x,\t\t/* length: %d bytes */\n", + dim(msg) >> 8, dim(msg) & 0xff, dim(msg)); + for (int i = 0; i < dim(input); i++) + printf("%s\n", input[i]); + int csum = checksum(msg); + printf ("\t0x%02x, 0x0d, 0x0a,\n", + csum); +} + +main(); -- cgit v1.2.3 From 258b75498916183ed250d3abb3282fe3d843e7a1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 7 Oct 2011 09:53:09 -0600 Subject: altos: Write xdata versions of memory functions These are significantly smaller than the general pointer versions from libc on the cc1111. Signed-off-by: Keith Packard Conflicts: src/Makefile.proto src/cc1111/ao_adc.c src/cc1111/ao_packet_master.c src/core/ao.h Fix up the new makefiles --- src/cc1111/ao_adc.c | 2 +- src/cc1111/ao_arch.h | 17 +++++++++++++++++ src/cc1111/ao_intflash.c | 2 +- src/cc1111/ao_packet.c | 4 ++-- src/cc1111/ao_packet_master.c | 2 +- src/cc1111/ao_packet_slave.c | 2 +- src/core/ao.h | 6 ++++++ src/core/ao_cmd.c | 4 ++-- src/core/ao_config.c | 11 ++++++----- src/core/ao_ee_fake.c | 2 +- src/core/ao_gps_report.c | 4 ++-- src/core/ao_host.h | 4 ++++ src/core/ao_monitor.c | 4 ++-- src/core/ao_telemetry.c | 10 +++++----- src/drivers/ao_25lc1024.c | 6 +++--- src/drivers/ao_at45db161d.c | 6 +++--- src/drivers/ao_gps_skytraq.c | 4 ++-- src/product/Makefile.telebt | 1 + src/product/Makefile.teledongle | 1 + src/product/Makefile.telelaunch | 1 + src/product/Makefile.telemetrum | 1 + src/product/Makefile.telemini | 1 + src/product/Makefile.telenano | 1 + src/test/ao_flight_test.c | 8 ++++++-- src/tidongle/Makefile | 1 + 25 files changed, 72 insertions(+), 33 deletions(-) (limited to 'src/test') diff --git a/src/cc1111/ao_adc.c b/src/cc1111/ao_adc.c index 6aa6e018..1688eceb 100644 --- a/src/cc1111/ao_adc.c +++ b/src/cc1111/ao_adc.c @@ -46,7 +46,7 @@ ao_adc_get(__xdata struct ao_adc *packet) #else uint8_t i = ao_adc_ring_prev(ao_adc_head); #endif - memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); + ao_xmemcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); } void diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h index 8a41791f..02e36189 100644 --- a/src/cc1111/ao_arch.h +++ b/src/cc1111/ao_arch.h @@ -204,4 +204,21 @@ struct ao_adc { #define AO_ADC_RING 32 +/* ao_string.c */ + +void +_ao_xmemcpy(__xdata uint8_t *dst, __xdata uint8_t *src, uint8_t count); + +#define ao_xmemcpy(d,s,c) _ao_xmemcpy((__xdata uint8_t *) (d), (__xdata uint8_t *) (s), (c)) + +void +_ao_xmemset(__xdata uint8_t *dst, uint8_t value, uint8_t count); + +#define ao_xmemset(d,v,c) _ao_xmemset((__xdata uint8_t *) (d), (v), (c)) + +int8_t +_ao_xmemcmp(__xdata uint8_t *a, __xdata uint8_t *b, uint8_t count); + +#define ao_xmemcmp(d,s,c) _ao_xmemcmp((__xdata uint8_t *) (d), (__xdata uint8_t *) (s), (c)) + #endif /* _AO_ARCH_H_ */ diff --git a/src/cc1111/ao_intflash.c b/src/cc1111/ao_intflash.c index d76d954e..632e2a85 100644 --- a/src/cc1111/ao_intflash.c +++ b/src/cc1111/ao_intflash.c @@ -180,7 +180,7 @@ ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant { if (pos >= ao_storage_total || pos + len > ao_storage_total) return 0; - memcpy(d, ao_intflash+pos, len); + ao_xmemcpy(d, ao_intflash+pos, len); return 1; } diff --git a/src/cc1111/ao_packet.c b/src/cc1111/ao_packet.c index f627e02b..37ba92e0 100644 --- a/src/cc1111/ao_packet.c +++ b/src/cc1111/ao_packet.c @@ -35,7 +35,7 @@ ao_packet_send(void) ao_led_on(AO_LED_RED); /* If any tx data is pending then copy it into the tx packet */ if (ao_packet_tx_used && ao_tx_packet.len == 0) { - memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); + ao_xmemcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); ao_tx_packet.len = ao_packet_tx_used; ao_tx_packet.seq++; ao_packet_tx_used = 0; @@ -80,7 +80,7 @@ ao_packet_recv(void) /* Copy data to the receive data buffer and set up the * offsets */ - memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); + ao_xmemcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); ao_packet_rx_used = 0; ao_packet_rx_len = ao_rx_packet.packet.len; diff --git a/src/cc1111/ao_packet_master.c b/src/cc1111/ao_packet_master.c index 0d0be30e..ab19f979 100644 --- a/src/cc1111/ao_packet_master.c +++ b/src/cc1111/ao_packet_master.c @@ -81,7 +81,7 @@ ao_packet_master(void) ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; while (ao_packet_enable) { uint8_t r; - memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); + ao_xmemcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); ao_packet_send(); if (ao_tx_packet.len) ao_packet_master_busy(); diff --git a/src/cc1111/ao_packet_slave.c b/src/cc1111/ao_packet_slave.c index d7cafa68..fd5d443e 100644 --- a/src/cc1111/ao_packet_slave.c +++ b/src/cc1111/ao_packet_slave.c @@ -24,7 +24,7 @@ ao_packet_slave(void) ao_tx_packet.len = AO_PACKET_SYN; while (ao_packet_enable) { if (ao_packet_recv()) { - memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); + ao_xmemcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); #if HAS_FLIGHT ao_flight_force_idle = TRUE; #endif diff --git a/src/core/ao.h b/src/core/ao.h index 04610fea..c0474729 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -1817,4 +1817,10 @@ ao_log_single(void); #define AO_TELEPYRO_NUM_ADC 9 +#ifndef ao_xmemcpy +#define ao_xmemcpy(d,s,c) memcpy(d,s,c) +#define ao_xmemset(d,v,c) memset(d,v,c) +#define ao_xmemcmp(d,s,c) memcmp(d,s,c) +#endif + #endif /* _AO_H_ */ diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c index 2b64b8ca..0c902f6b 100644 --- a/src/core/ao_cmd.c +++ b/src/core/ao_cmd.c @@ -265,8 +265,8 @@ help(void) cs = ao_cmds[cmds]; for (cmd = 0; cs[cmd].func; cmd++) printf("%-45s %s\n", - cs[cmd].help, - cs[cmd].help+1+strlen(cs[cmd].help)); + cs[cmd].help, + cs[cmd].help+1+strlen(cs[cmd].help)); } } diff --git a/src/core/ao_config.c b/src/core/ao_config.c index a653bed2..08cc79b1 100644 --- a/src/core/ao_config.c +++ b/src/core/ao_config.c @@ -78,8 +78,8 @@ _ao_config_get(void) /* Version 0 stuff */ ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY; ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL; - memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); - memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, + ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); + ao_xmemcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN, sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); ao_config_dirty = 1; } @@ -148,7 +148,7 @@ ao_config_callsign_set(void) __reentrant uint8_t c; static __xdata char callsign[AO_MAX_CALLSIGN + 1]; - memset(callsign, '\0', sizeof callsign); + ao_xmemset(callsign, '\0', sizeof callsign); ao_cmd_white(); c = 0; while (ao_cmd_lex_c != '\n') { @@ -161,7 +161,7 @@ ao_config_callsign_set(void) __reentrant if (ao_cmd_status != ao_cmd_success) return; _ao_config_edit_start(); - memcpy(&ao_config.callsign, &callsign, + ao_xmemcpy(&ao_config.callsign, &callsign, AO_MAX_CALLSIGN + 1); _ao_config_edit_finish(); } @@ -535,7 +535,8 @@ ao_config_help(void) __reentrant for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++) printf("%-20s %s\n", ao_config_vars[cmd].str, - ao_config_vars[cmd].str+1+strlen(ao_config_vars[cmd].str)); + ao_config_vars[cmd].str+1+ + strlen(ao_config_vars[cmd].str)); } static void diff --git a/src/core/ao_ee_fake.c b/src/core/ao_ee_fake.c index b0c1d61e..7fcfcab0 100644 --- a/src/core/ao_ee_fake.c +++ b/src/core/ao_ee_fake.c @@ -32,6 +32,6 @@ ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant uint8_t ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant { - memset(buf, '\0', len); + ao_xmemset(buf, '\0', len); return 1; } diff --git a/src/core/ao_gps_report.c b/src/core/ao_gps_report.c index e57f8744..c52ef621 100644 --- a/src/core/ao_gps_report.c +++ b/src/core/ao_gps_report.c @@ -27,7 +27,7 @@ ao_gps_report(void) for (;;) { ao_sleep(&ao_gps_data); ao_mutex_get(&ao_gps_mutex); - memcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data)); + ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data)); ao_mutex_put(&ao_gps_mutex); if (!(gps_data.flags & AO_GPS_VALID)) @@ -72,7 +72,7 @@ ao_gps_tracking_report(void) ao_sleep(&ao_gps_tracking_data); ao_mutex_get(&ao_gps_mutex); gps_log.tick = ao_gps_tick; - memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data)); + ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data)); ao_mutex_put(&ao_gps_mutex); if (!(n = gps_tracking_data.channels)) diff --git a/src/core/ao_host.h b/src/core/ao_host.h index 65c25fe5..f2b2f0c9 100644 --- a/src/core/ao_host.h +++ b/src/core/ao_host.h @@ -125,3 +125,7 @@ struct ao_config { #define ao_config_get() struct ao_config ao_config = { 250, 16000 }; + +#define ao_xmemcpy(d,s,c) memcpy(d,s,c) +#define ao_xmemset(d,v,c) memset(d,v,c) +#define ao_xmemcmp(d,s,c) memcmp(d,s,c) diff --git a/src/core/ao_monitor.c b/src/core/ao_monitor.c index 56d7604d..1a8bb52a 100644 --- a/src/core/ao_monitor.c +++ b/src/core/ao_monitor.c @@ -94,7 +94,7 @@ ao_monitor_put(void) /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ rssi = (int16_t) (recv_orig.rssi >> 1) - 74; - memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN); + ao_xmemcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN); if (state > ao_flight_invalid) state = ao_flight_invalid; if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) { @@ -171,7 +171,7 @@ ao_monitor_put(void) /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ rssi = (int16_t) (recv_tiny.rssi >> 1) - 74; - memcpy(callsign, recv_tiny.telemetry_tiny.callsign, AO_MAX_CALLSIGN); + ao_xmemcpy(callsign, recv_tiny.telemetry_tiny.callsign, AO_MAX_CALLSIGN); if (state > ao_flight_invalid) state = ao_flight_invalid; if (recv_tiny.status & PKT_APPEND_STATUS_1_CRC_OK) { diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c index 26e4e2a0..95e53917 100644 --- a/src/core/ao_telemetry.c +++ b/src/core/ao_telemetry.c @@ -131,10 +131,10 @@ ao_send_configuration(void) telemetry.configuration.apogee_delay = ao_config.apogee_delay; telemetry.configuration.main_deploy = ao_config.main_deploy; telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10; - memcpy (telemetry.configuration.callsign, + ao_xmemcpy (telemetry.configuration.callsign, ao_config.callsign, AO_MAX_CALLSIGN); - memcpy (telemetry.configuration.version, + ao_xmemcpy (telemetry.configuration.version, ao_version, AO_MAX_VERSION); ao_radio_send(&telemetry, sizeof (telemetry)); @@ -150,7 +150,7 @@ ao_send_location(void) { telemetry.generic.type = AO_TELEMETRY_LOCATION; ao_mutex_get(&ao_gps_mutex); - memcpy(&telemetry.location.flags, + ao_xmemcpy(&telemetry.location.flags, &ao_gps_data.flags, 26); ao_mutex_put(&ao_gps_mutex); @@ -167,7 +167,7 @@ ao_send_satellite(void) telemetry.generic.type = AO_TELEMETRY_SATELLITE; ao_mutex_get(&ao_gps_mutex); telemetry.satellite.channels = ao_gps_tracking_data.channels; - memcpy(&telemetry.satellite.sats, + ao_xmemcpy(&telemetry.satellite.sats, &ao_gps_tracking_data.sats, AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info)); ao_mutex_put(&ao_gps_mutex); @@ -187,7 +187,7 @@ ao_send_companion(void) telemetry.companion.update_period = ao_companion_setup.update_period; telemetry.companion.channels = ao_companion_setup.channels; ao_mutex_get(&ao_companion_mutex); - memcpy(&telemetry.companion.companion_data, + ao_xmemcpy(&telemetry.companion.companion_data, ao_companion_data, ao_companion_setup.channels * 2); ao_mutex_put(&ao_companion_mutex); diff --git a/src/drivers/ao_25lc1024.c b/src/drivers/ao_25lc1024.c index 738f8ce6..2d047a44 100644 --- a/src/drivers/ao_25lc1024.c +++ b/src/drivers/ao_25lc1024.c @@ -167,7 +167,7 @@ ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentra ao_ee_flush_internal(); ao_ee_block = block; } - memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len); + ao_xmemcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len); ao_ee_block_dirty = 1; } ao_mutex_put(&ao_ee_mutex); return 1; @@ -181,7 +181,7 @@ ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentran /* Transfer the data */ ao_mutex_get(&ao_ee_mutex); { ao_ee_fill(block); - memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len); + ao_xmemcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len); } ao_mutex_put(&ao_ee_mutex); return 1; } @@ -200,7 +200,7 @@ ao_storage_erase(uint32_t pos) __reentrant ao_mutex_get(&ao_ee_mutex); { ao_ee_flush_internal(); ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT); - memset(ao_ee_data, 0xff, EE_BLOCK_SIZE); + ao_xmemset(ao_ee_data, 0xff, EE_BLOCK_SIZE); ao_ee_block_dirty = 1; } ao_mutex_put(&ao_ee_mutex); return 1; diff --git a/src/drivers/ao_at45db161d.c b/src/drivers/ao_at45db161d.c index aee9877a..6cd689e5 100644 --- a/src/drivers/ao_at45db161d.c +++ b/src/drivers/ao_at45db161d.c @@ -245,7 +245,7 @@ ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentra ao_flash_flush_internal(); ao_flash_block = block; } - memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), + ao_xmemcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), buf, len); ao_flash_block_dirty = 1; @@ -261,7 +261,7 @@ ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentran /* Transfer the data */ ao_mutex_get(&ao_flash_mutex); { ao_flash_fill(block); - memcpy(buf, + ao_xmemcpy(buf, ao_flash_data + (uint16_t) (pos & ao_flash_block_mask), len); } ao_mutex_put(&ao_flash_mutex); @@ -282,7 +282,7 @@ ao_storage_erase(uint32_t pos) __reentrant ao_mutex_get(&ao_flash_mutex); { ao_flash_flush_internal(); ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift); - memset(ao_flash_data, 0xff, ao_flash_block_size); + ao_xmemset(ao_flash_data, 0xff, ao_flash_block_size); ao_flash_block_dirty = 1; } ao_mutex_put(&ao_flash_mutex); return 1; diff --git a/src/drivers/ao_gps_skytraq.c b/src/drivers/ao_gps_skytraq.c index 7ac26946..6e65d651 100644 --- a/src/drivers/ao_gps_skytraq.c +++ b/src/drivers/ao_gps_skytraq.c @@ -265,7 +265,7 @@ ao_nmea_gga() if (!ao_gps_error) { ao_mutex_get(&ao_gps_mutex); ao_gps_tick = ao_gps_next_tick; - memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data)); + ao_xmemcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data)); ao_mutex_put(&ao_gps_mutex); ao_wakeup(&ao_gps_data); } @@ -327,7 +327,7 @@ ao_nmea_gsv(void) ao_gps_tracking_next.channels = 0; else if (done) { ao_mutex_get(&ao_gps_mutex); - memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, + ao_xmemcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, sizeof(ao_gps_tracking_data)); ao_mutex_put(&ao_gps_mutex); ao_wakeup(&ao_gps_tracking_data); diff --git a/src/product/Makefile.telebt b/src/product/Makefile.telebt index 46c87db0..8f7c7429 100644 --- a/src/product/Makefile.telebt +++ b/src/product/Makefile.telebt @@ -41,6 +41,7 @@ CC1111_SRC = \ ao_radio_cmac.c \ ao_romconfig.c \ ao_serial.c \ + ao_string.c \ ao_timer.c \ ao_usb.c \ _bp.c diff --git a/src/product/Makefile.teledongle b/src/product/Makefile.teledongle index 56182b84..c1b422c0 100644 --- a/src/product/Makefile.teledongle +++ b/src/product/Makefile.teledongle @@ -43,6 +43,7 @@ CC1111_SRC = \ ao_radio.c \ ao_radio_cmac.c \ ao_romconfig.c \ + ao_string.c \ ao_timer.c \ ao_usb.c \ _bp.c diff --git a/src/product/Makefile.telelaunch b/src/product/Makefile.telelaunch index 5da42e46..b40f61a2 100644 --- a/src/product/Makefile.telelaunch +++ b/src/product/Makefile.telelaunch @@ -45,6 +45,7 @@ CC1111_SRC = \ ao_romconfig.c \ ao_serial.c \ ao_spi.c \ + ao_string.c \ ao_timer.c \ ao_usb.c \ _bp.c diff --git a/src/product/Makefile.telemetrum b/src/product/Makefile.telemetrum index 2759ac52..4f4195a9 100644 --- a/src/product/Makefile.telemetrum +++ b/src/product/Makefile.telemetrum @@ -54,6 +54,7 @@ CC1111_SRC = \ ao_radio.c \ ao_romconfig.c \ ao_serial.c \ + ao_string.c \ ao_spi.c \ ao_timer.c \ ao_usb.c \ diff --git a/src/product/Makefile.telemini b/src/product/Makefile.telemini index 7f251897..9f90b01f 100644 --- a/src/product/Makefile.telemini +++ b/src/product/Makefile.telemini @@ -45,6 +45,7 @@ CC1111_SRC = \ ao_packet_slave.c \ ao_radio.c \ ao_romconfig.c \ + ao_string.c \ ao_timer.c \ _bp.c diff --git a/src/product/Makefile.telenano b/src/product/Makefile.telenano index c47e95ff..eff3ea97 100644 --- a/src/product/Makefile.telenano +++ b/src/product/Makefile.telenano @@ -44,6 +44,7 @@ CC1111_SRC = \ ao_packet_slave.c \ ao_radio.c \ ao_romconfig.c \ + ao_string.c \ ao_timer.c \ _bp.c diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 56733c89..921d44e7 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -173,6 +173,10 @@ struct ao_cmds { const char *help; }; +#define ao_xmemcpy(d,s,c) memcpy(d,s,c) +#define ao_xmemset(d,v,c) memset(d,v,c) +#define ao_xmemcmp(d,s,c) memcmp(d,s,c) + #include "ao_convert.c" struct ao_config { @@ -542,7 +546,7 @@ ao_sleep(void *wchan) ao_flight_started = 1; } } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { - char *hex = words[1]; + __xdata char *hex = words[1]; char elt[3]; int i, len; uint8_t sum; @@ -574,7 +578,7 @@ ao_sleep(void *wchan) continue; } if (len == 36) { - memcpy(&telem, bytes + 1, 32); + ao_xmemcpy(&telem, bytes + 1, 32); tick = telem.generic.tick; switch (telem.generic.type) { case AO_TELEMETRY_SENSOR_TELEMETRUM: diff --git a/src/tidongle/Makefile b/src/tidongle/Makefile index 057e420b..58b9d735 100644 --- a/src/tidongle/Makefile +++ b/src/tidongle/Makefile @@ -38,6 +38,7 @@ CC1111_SRC = \ ao_radio.c \ ao_radio_cmac.c \ ao_romconfig.c \ + ao_string.c \ ao_timer.c \ ao_usb.c \ _bp.c -- cgit v1.2.3 From ca036c5616c3e745c0b878ed90618d4ff710c0e5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 8 Oct 2011 22:19:52 -0600 Subject: altos: Improve TM v1.0 apogee estimate v1.0 boards have noisy accelerometer data caused by interactions between RF transmission and the accelerometer measurements; this noise generates a negative bias in the accelerometer readings. The net effect is that the estimated speed is lower than the actual speed, causing early an apogee estimate. By increasing the sigma value for accelerometer data, the kalman filter 'trusts' the acceleration data less, putting more weight on the barometer data. This causes the estimated time of apogee to be closer to the correct value. This reduces the response to changes in acceleration. This new value is applied solely to TeleMetrum v1.0 boards. v1.1 boards correct for this error, and hence can use the correct sigma value for the accelerometer. Signed-off-by: Keith Packard --- src/cc1111/ao_pins.h | 1 + src/test/Makefile | 12 ++++++++++-- src/util/make-kalman | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'src/test') diff --git a/src/cc1111/ao_pins.h b/src/cc1111/ao_pins.h index 723f1500..d2fbb209 100644 --- a/src/cc1111/ao_pins.h +++ b/src/cc1111/ao_pins.h @@ -36,6 +36,7 @@ #define IGNITE_ON_P0 0 #define PACKET_HAS_MASTER 0 #define PACKET_HAS_SLAVE 1 + #define NOISY_ACCEL 1 #define HAS_COMPANION 1 #define COMPANION_CS_ON_P1 1 diff --git a/src/test/Makefile b/src/test/Makefile index 333850e4..4e403da6 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,8 @@ -vpath % ..:../core:../drivers +vpath % ..:../core:../drivers:../util -PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test +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 + +KALMAN=make-kalman CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g @@ -14,6 +16,9 @@ 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 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 + 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 cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 ao_flight_test.c @@ -28,3 +33,6 @@ ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_ho ao_convert_test: ao_convert_test.c ao_convert.c altitude.h cc $(CFLAGS) -o $@ $< + +ao_kalman.h: $(KALMAN) + (cd .. && make ao_kalman.h) \ No newline at end of file diff --git a/src/util/make-kalman b/src/util/make-kalman index 397d6020..fd33bab0 100644 --- a/src/util/make-kalman +++ b/src/util/make-kalman @@ -5,11 +5,32 @@ cd $1 2> /dev/null 1>&2 SIGMA_BOTH="-M 2 -H 6 -A 2" SIGMA_BARO="-M 2 -H 6 -A 2" SIGMA_ACCEL="-M 2 -H 4 -A 4" +SIGMA_BOTH_NOISY_ACCEL="-M 2 -H 6 -A 3" + +echo '#if NOISY_ACCEL' +echo +echo '/* TeleMetrum v1.0 boards have noisy accelerometer values' +echo ' * increase the sigma value for accel data to compensate.' +echo ' * This improves the accuracy of apogee detection.' +echo ' */' +echo + +nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH_NOISY_ACCEL +nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH_NOISY_ACCEL +nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH_NOISY_ACCEL + +echo '#endif' +echo +echo '#ifndef AO_BOTH_K00_100' +echo nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH +echo '#endif' +echo + nickle kalman.5c -p AO_ACCEL -c accel -t 0.01 $SIGMA_ACCEL nickle kalman.5c -p AO_ACCEL -c accel -t 0.1 $SIGMA_ACCEL nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL @@ -17,3 +38,4 @@ nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL nickle kalman.5c -p AO_BARO -c baro -t 0.01 $SIGMA_BARO nickle kalman.5c -p AO_BARO -c baro -t 0.1 $SIGMA_BARO nickle kalman.5c -p AO_BARO -c baro -t 1 $SIGMA_BARO + -- cgit v1.2.3 From df08b2f6de464f4546c1809b931eb4910d88b558 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 27 Oct 2011 01:01:11 -0700 Subject: altos: A bunch of missing .gitignore files (mostly) Signed-off-by: Keith Packard --- ao-tools/ao-telem/.gitignore | 1 + src/.gitignore | 1 + src/avr-demo/.gitignore | 3 + src/telepyro-v0.1/.gitignore | 2 + src/telescience-v0.1/.gitignore | 2 + src/teleterra-v0.1/.gitignore | 2 + src/teleterra-v0.1/ao_pins.h | 217 ++++++++++++++++++++++++++++++++++++++++ src/test/run-full | 31 ++++++ src/test/run-noisy | 23 +++++ 9 files changed, 282 insertions(+) create mode 100644 ao-tools/ao-telem/.gitignore create mode 100644 src/.gitignore create mode 100644 src/avr-demo/.gitignore create mode 100644 src/telepyro-v0.1/.gitignore create mode 100644 src/telescience-v0.1/.gitignore create mode 100644 src/teleterra-v0.1/.gitignore create mode 100644 src/teleterra-v0.1/ao_pins.h create mode 100755 src/test/run-full create mode 100755 src/test/run-noisy (limited to 'src/test') diff --git a/ao-tools/ao-telem/.gitignore b/ao-tools/ao-telem/.gitignore new file mode 100644 index 00000000..5ab6f649 --- /dev/null +++ b/ao-tools/ao-telem/.gitignore @@ -0,0 +1 @@ +ao-telem diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 00000000..7a5d6ef5 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +altitude.h diff --git a/src/avr-demo/.gitignore b/src/avr-demo/.gitignore new file mode 100644 index 00000000..e7d16343 --- /dev/null +++ b/src/avr-demo/.gitignore @@ -0,0 +1,3 @@ +avr-demo +avr-demo.hex +ao_product.h diff --git a/src/telepyro-v0.1/.gitignore b/src/telepyro-v0.1/.gitignore new file mode 100644 index 00000000..5166481c --- /dev/null +++ b/src/telepyro-v0.1/.gitignore @@ -0,0 +1,2 @@ +telepyro-v0.1* +ao_product.h diff --git a/src/telescience-v0.1/.gitignore b/src/telescience-v0.1/.gitignore new file mode 100644 index 00000000..dfccadf8 --- /dev/null +++ b/src/telescience-v0.1/.gitignore @@ -0,0 +1,2 @@ +telescience-v0.1* +ao_product.h diff --git a/src/teleterra-v0.1/.gitignore b/src/teleterra-v0.1/.gitignore new file mode 100644 index 00000000..447007ce --- /dev/null +++ b/src/teleterra-v0.1/.gitignore @@ -0,0 +1,2 @@ +teleterra-v0.1* +ao_product.h diff --git a/src/teleterra-v0.1/ao_pins.h b/src/teleterra-v0.1/ao_pins.h new file mode 100644 index 00000000..33de055e --- /dev/null +++ b/src/teleterra-v0.1/ao_pins.h @@ -0,0 +1,217 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#ifdef TELETERRA_V_0_1 + #define HAS_FLIGHT 0 + #define HAS_USB 1 + #define HAS_BEEP 0 + #define HAS_GPS 0 + #define HAS_SERIAL_1 0 + #define HAS_ADC 0 + #define USE_SERIAL_STDIN 0 + #define HAS_EEPROM 1 + #define HAS_LOG 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 0 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 1 + #define PACKET_HAS_SLAVE 0 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 0 + #define HAS_ACCEL 0 + #define HAS_IGNITE 0 + #define HAS_MONITOR 1 + #define HAS_RSSI 0 + #define HAS_AES 1 + + #define SPI_CS_ON_P1 0 + #define SPI_CS_ON_P0 1 + #define M25_CS_MASK 0xf + #define M25_MAX_CHIPS 4 +#endif + +#if DBG_ON_P1 + + #define DBG_CLOCK (1 << 4) /* mi0 */ + #define DBG_DATA (1 << 5) /* mo0 */ + #define DBG_RESET_N (1 << 3) /* c0 */ + + #define DBG_CLOCK_PIN (P1_4) + #define DBG_DATA_PIN (P1_5) + #define DBG_RESET_N_PIN (P1_3) + + #define DBG_PORT_NUM 1 + #define DBG_PORT P1 + #define DBG_PORT_SEL P1SEL + #define DBG_PORT_INP P1INP + #define DBG_PORT_DIR P1DIR + +#endif /* DBG_ON_P1 */ + +#if DBG_ON_P0 + + #define DBG_CLOCK (1 << 3) + #define DBG_DATA (1 << 4) + #define DBG_RESET_N (1 << 5) + + #define DBG_CLOCK_PIN (P0_3) + #define DBG_DATA_PIN (P0_4) + #define DBG_RESET_N_PIN (P0_5) + + #define DBG_PORT_NUM 0 + #define DBG_PORT P0 + #define DBG_PORT_SEL P0SEL + #define DBG_PORT_INP P0INP + #define DBG_PORT_DIR P0DIR + +#endif /* DBG_ON_P0 */ + +#if COMPANION_CS_ON_P1 + #define COMPANION_CS_PORT P1 + #define COMPANION_CS_SEL P1SEL + #define COMPANION_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P1 + #define SPI_CS_PORT P1 + #define SPI_CS_SEL P1SEL + #define SPI_CS_DIR P1DIR +#endif + +#if SPI_CS_ON_P0 + #define SPI_CS_PORT P0 + #define SPI_CS_SEL P0SEL + #define SPI_CS_DIR P0DIR +#endif + +#ifndef IGNITE_ON_P2 +#error Please define IGNITE_ON_P2 +#endif + +#ifndef IGNITE_ON_P0 +#error Please define IGNITE_ON_P0 +#endif + +#ifndef HAS_SERIAL_1 +#error Please define HAS_SERIAL_1 +#endif + +#ifndef USE_SERIAL_STDIN +#error Please define USE_SERIAL_STDIN +#endif + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#ifndef HAS_EEPROM +#error Please define HAS_EEPROM +#endif + +#ifndef HAS_LOG +#error Please define HAS_LOG +#endif + +#if HAS_EEPROM +#ifndef USE_INTERNAL_FLASH +#error Please define USE_INTERNAL_FLASH +#endif +#endif + +#ifndef HAS_DBG +#error Please define HAS_DBG +#endif + +#ifndef HAS_IGNITE +#error Please define HAS_IGNITE +#endif + +#if HAS_IGNITE +#define HAS_IGNITE_REPORT 1 +#endif + +#ifndef PACKET_HAS_MASTER +#error Please define PACKET_HAS_MASTER +#endif + +#ifndef PACKET_HAS_SLAVE +#error Please define PACKET_HAS_SLAVE +#endif + +#ifndef HAS_MONITOR +#error Please define HAS_MONITOR +#endif + +#if HAS_MONITOR +#ifndef HAS_RSSI +#error Please define HAS_RSSI +#endif +#endif + +#ifndef HAS_ADC +#error Please define HAS_ADC +#endif + +#if HAS_ADC + +#if HAS_ACCEL +#ifndef HAS_ACCEL_REF +#error Please define HAS_ACCEL_REF +#endif +#else +#define HAS_ACCEL_REF 0 +#endif + +#endif /* HAS_ADC */ + +#if IGNITE_ON_P2 +#define AO_IGNITER_DROGUE P2_3 +#define AO_IGNITER_MAIN P2_4 +#define AO_IGNITER_DIR P2DIR +#define AO_IGNITER_DROGUE_BIT (1 << 3) +#define AO_IGNITER_MAIN_BIT (1 << 4) +#endif + +#if IGNITE_ON_P0 +#define AO_IGNITER_DROGUE P0_5 +#define AO_IGNITER_MAIN P0_4 +#define AO_IGNITER_DIR P0DIR +#define AO_IGNITER_DROGUE_BIT (1 << 5) +#define AO_IGNITER_MAIN_BIT (1 << 4) +#endif + +/* test these values with real igniters */ +#define AO_IGNITER_OPEN 1000 +#define AO_IGNITER_CLOSED 7000 +#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50) +#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000) + +#endif /* _AO_PINS_H_ */ diff --git a/src/test/run-full b/src/test/run-full new file mode 100755 index 00000000..50ab7b5b --- /dev/null +++ b/src/test/run-full @@ -0,0 +1,31 @@ +#!/bin/sh + +for i in "$@"; do +./ao_flight_test "$i" > run-out.full + +#./ao_flight_test_accel "$i" > 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.full" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ +"run-out.full" using 1:5 with lines lw 2 lt 2 axes x1y2 title "raw accel",\ +"run-out.full" using 1:9 with lines lt 3 axes x1y1 title "full height",\ +"run-out.full" using 1:11 with lines lt 4 axes x1y2 title "full speed",\ +"run-out.full" using 1:13 with lines lt 5 axes x1y2 title "full accel",\ +"run-out.full" using 1:17 with lines lt 6 axes x1y1 title "full drogue",\ +"run-out.full" using 1:19 with lines lt 7 axes x1y1 title "full main" +pause mouse close +EOF +done \ No newline at end of file diff --git a/src/test/run-noisy b/src/test/run-noisy new file mode 100755 index 00000000..2e3cddc7 --- /dev/null +++ b/src/test/run-noisy @@ -0,0 +1,23 @@ +#!/bin/sh + +for i in "$@"; do +./ao_flight_test_noisy_accel "$i" > run-out.noisy + +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.noisy" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ +"run-out.noisy" using 1:5 with lines lw 2 lt 2 axes x1y2 title "raw accel",\ +"run-out.noisy" using 1:9 with lines lt 3 axes x1y1 title "noisy height",\ +"run-out.noisy" using 1:11 with lines lt 4 axes x1y2 title "noisy speed",\ +"run-out.noisy" using 1:13 with lines lt 5 axes x1y2 title "noisy accel",\ +"run-out.noisy" using 1:17 with lines lt 6 axes x1y1 title "noisy drogue",\ +"run-out.noisy" using 1:19 with lines lt 7 axes x1y1 title "noisy main" +pause mouse close +EOF +done \ No newline at end of file -- cgit v1.2.3 From 040a6eb119451026e1ec7c3a6a8e76b439c632d5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 12 Apr 2012 14:51:07 -0700 Subject: altos: Massive product config cleanup Support multiple serial ports more cleanly Split out parts of ao.h into separate feature header files Signed-off-by: Keith Packard --- src/avr/ao_arch.h | 7 - src/avr/ao_pins.h | 15 +- src/avr/ao_serial_avr.c | 62 +-- src/avr/ao_usb.h | 100 ----- src/avr/ao_usb_avr.c | 6 +- src/cc1111/ao_arch.h | 30 ++ src/cc1111/ao_pins.h | 24 +- src/cc1111/ao_serial.c | 227 +++++++++-- src/cc1111/ao_serial0.c | 152 -------- src/cc1111/ao_usb.c | 6 +- src/cc1111/ao_usb.h | 100 ----- src/core/ao.h | 704 ++--------------------------------- src/core/ao_adc.h | 62 +++ src/core/ao_beep.h | 74 ++++ src/core/ao_dbg.h | 62 +++ src/core/ao_flight.h | 59 +++ src/core/ao_led.h | 55 +++ src/core/ao_log.h | 196 ++++++++++ src/core/ao_log_telem.c | 4 +- src/core/ao_product.c | 8 +- src/core/ao_report.c | 2 + src/core/ao_sample.h | 137 +++++++ src/core/ao_serial.h | 86 +++++ src/core/ao_stdio.c | 6 + src/core/ao_storage.c | 2 +- src/core/ao_storage.h | 84 +++++ src/core/ao_usb.h | 136 +++++++ src/drivers/ao_btm.c | 30 +- src/drivers/ao_gps_sirf.c | 36 +- src/drivers/ao_gps_skytraq.c | 6 +- src/drivers/ao_science_slave.c | 1 + src/megametrum-v0.1/ao_pins.h | 2 + src/product/ao_telebt.c | 2 + src/product/ao_terraui.c | 1 + src/stm/ao_arch.h | 2 - src/stm/ao_serial_stm.c | 2 +- src/stm/ao_usb.h | 101 ----- src/stm/ao_usb_stm.c | 6 +- src/teleballoon-v1.1/ao_pins.h | 5 - src/telepyro-v0.1/Makefile | 6 +- src/telescience-v0.1/Makefile | 9 +- src/teleshield-v0.1/Makefile | 1 - src/teleshield-v0.1/ao_ardu_serial.c | 3 +- src/teleshield-v0.1/ao_pins.h | 8 +- src/teleshield-v0.1/ao_teleshield.c | 3 + src/teleterra-v0.1/ao_pins.h | 5 - src/teleterra-v0.2/ao_pins.h | 5 - src/test/ao_gps_test.c | 6 +- src/test/ao_gps_test_skytraq.c | 6 +- 49 files changed, 1342 insertions(+), 1310 deletions(-) delete mode 100644 src/avr/ao_usb.h delete mode 100644 src/cc1111/ao_serial0.c delete mode 100644 src/cc1111/ao_usb.h create mode 100644 src/core/ao_adc.h create mode 100644 src/core/ao_beep.h create mode 100644 src/core/ao_dbg.h create mode 100644 src/core/ao_flight.h create mode 100644 src/core/ao_led.h create mode 100644 src/core/ao_log.h create mode 100644 src/core/ao_sample.h create mode 100644 src/core/ao_serial.h create mode 100644 src/core/ao_storage.h create mode 100644 src/core/ao_usb.h delete mode 100644 src/stm/ao_usb.h (limited to 'src/test') diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h index b816279e..c775dab6 100644 --- a/src/avr/ao_arch.h +++ b/src/avr/ao_arch.h @@ -146,12 +146,5 @@ extern uint8_t ao_cpu_sleep_disable; #define AO_TELESCIENCE_NUM_ADC 12 -struct ao_adc { - uint16_t tick; /* tick when the sample was read */ - uint16_t adc[AO_TELESCIENCE_NUM_ADC]; /* samples */ -}; - -#define AO_ADC_RING 16 - #endif /* _AO_ARCH_H_ */ diff --git a/src/avr/ao_pins.h b/src/avr/ao_pins.h index 6a63468f..f2b40fb4 100644 --- a/src/avr/ao_pins.h +++ b/src/avr/ao_pins.h @@ -21,7 +21,7 @@ #ifdef AVR_DEMO #define AO_LED_RED (1<<7) #define LEDS_AVAILABLE (AO_LED_RED) - #define USE_SERIAL_STDIN 1 + #define USE_SERIAL_1_STDIN 1 #define HAS_USB 1 #define PACKET_HAS_SLAVE 0 #define HAS_SERIAL_1 1 @@ -37,11 +37,11 @@ #define HAS_USB 1 #define HAS_LOG 1 #define TEENSY 0 - #define USE_SERIAL_STDIN 0 #define HAS_SERIAL_1 0 #define HAS_ADC 1 #define PACKET_HAS_SLAVE 0 #define HAS_BEEP 0 + #define HAS_EEPROM 1 #define HAS_STORAGE_DEBUG 0 #define AVR_VCC_5V 0 @@ -66,7 +66,7 @@ #define HAS_USB 1 #define HAS_LOG 0 #define TEENSY 0 - #define USE_SERIAL_STDIN 1 + #define USE_SERIAL_1_STDIN 1 #define HAS_SERIAL_1 1 #define HAS_USB 1 #define HAS_ADC 1 @@ -88,4 +88,13 @@ #define AO_M25_SPI_CS_PORT SPI_CS_PORT #define AO_M25_SPI_CS_MASK M25_CS_MASK +#define AO_TELESCIENCE_NUM_ADC 12 + +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + uint16_t adc[AO_TELESCIENCE_NUM_ADC]; /* samples */ +}; + +#define AO_ADC_RING 16 + #endif /* _AO_PINS_H_ */ diff --git a/src/avr/ao_serial_avr.c b/src/avr/ao_serial_avr.c index 6885c339..dcee246c 100644 --- a/src/avr/ao_serial_avr.c +++ b/src/avr/ao_serial_avr.c @@ -17,8 +17,8 @@ #include "ao.h" -__xdata struct ao_fifo ao_usart1_rx_fifo; -__xdata struct ao_fifo ao_usart1_tx_fifo; +__xdata struct ao_fifo ao_serial1_rx_fifo; +__xdata struct ao_fifo ao_serial1_tx_fifo; void ao_debug_out(char c) @@ -31,10 +31,10 @@ ao_debug_out(char c) ISR(USART1_RX_vect) { - if (!ao_fifo_full(ao_usart1_rx_fifo)) - ao_fifo_insert(ao_usart1_rx_fifo, UDR1); - ao_wakeup(&ao_usart1_rx_fifo); -#if USE_SERIAL_STDIN + if (!ao_fifo_full(ao_serial1_rx_fifo)) + ao_fifo_insert(ao_serial1_rx_fifo, UDR1); + ao_wakeup(&ao_serial1_rx_fifo); +#if USE_SERIAL_1_STDIN ao_wakeup(&ao_stdin_ready); #endif } @@ -42,68 +42,68 @@ ISR(USART1_RX_vect) static __xdata uint8_t ao_serial_tx1_started; static void -ao_serial_tx1_start(void) +ao_serial1_tx_start(void) { - if (!ao_fifo_empty(ao_usart1_tx_fifo) && + if (!ao_fifo_empty(ao_serial1_tx_fifo) && !ao_serial_tx1_started) { ao_serial_tx1_started = 1; - ao_fifo_remove(ao_usart1_tx_fifo, UDR1); + ao_fifo_remove(ao_serial1_tx_fifo, UDR1); } } ISR(USART1_UDRE_vect) { - ao_serial_tx1_started = 0; - ao_serial_tx1_start(); - ao_wakeup(&ao_usart1_tx_fifo); + ao_serial1_tx_started = 0; + ao_serial1_tx_start(); + ao_wakeup(&ao_serial1_tx_fifo); } char -ao_serial_getchar(void) __critical +ao_serial1_getchar(void) __critical { char c; cli(); - while (ao_fifo_empty(ao_usart1_rx_fifo)) - ao_sleep(&ao_usart1_rx_fifo); - ao_fifo_remove(ao_usart1_rx_fifo, c); + while (ao_fifo_empty(ao_serial1_rx_fifo)) + ao_sleep(&ao_serial1_rx_fifo); + ao_fifo_remove(ao_serial1_rx_fifo, c); sei(); return c; } -#if USE_SERIAL_STDIN +#if USE_SERIAL_1_STDIN char -ao_serial_pollchar(void) __critical +ao_serial1_pollchar(void) __critical { char c; cli(); - if (ao_fifo_empty(ao_usart1_rx_fifo)) { + if (ao_fifo_empty(ao_serial1_rx_fifo)) { sei(); return AO_READ_AGAIN; } - ao_fifo_remove(ao_usart1_rx_fifo,c); + ao_fifo_remove(ao_serial1_rx_fifo,c); sei(); return c; } #endif void -ao_serial_putchar(char c) __critical +ao_serial1_putchar(char c) __critical { cli(); - while (ao_fifo_full(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); - ao_fifo_insert(ao_usart1_tx_fifo, c); + while (ao_fifo_full(ao_serial1_tx_fifo)) + ao_sleep(&ao_serial1_tx_fifo); + ao_fifo_insert(ao_serial1_tx_fifo, c); ao_serial_tx1_start(); sei(); } void -ao_serial_drain(void) __critical +ao_serial1_drain(void) __critical { cli(); - while (!ao_fifo_empty(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); + while (!ao_fifo_empty(ao_serial1_tx_fifo)) + ao_sleep(&ao_serial1_tx_fifo); sei(); } @@ -125,7 +125,7 @@ static const struct { }; void -ao_serial_set_speed(uint8_t speed) +ao_serial1_set_speed(uint8_t speed) { ao_serial_drain(); if (speed > AO_SERIAL_SPEED_57600) @@ -154,9 +154,9 @@ ao_serial_init(void) (1 << TXEN1) | /* Enable transmitter */ (1 << RXCIE1) | /* Enable receive interrupts */ (1 << UDRIE1)); /* Enable transmit empty interrupts */ -#if USE_SERIAL_STDIN - ao_add_stdio(ao_serial_pollchar, - ao_serial_putchar, +#if USE_SERIAL_1_STDIN + ao_add_stdio(ao_serial1_pollchar, + ao_serial1_putchar, NULL); #endif } diff --git a/src/avr/ao_usb.h b/src/avr/ao_usb.h deleted file mode 100644 index 6633dafc..00000000 --- a/src/avr/ao_usb.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef _AO_USB_H_ -#define _AO_USB_H_ - -#define AO_USB_SETUP_DIR_MASK (0x01 << 7) -#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) -#define AO_USB_SETUP_RECIP_MASK (0x1f) - -#define AO_USB_DIR_OUT 0 -#define AO_USB_DIR_IN (1 << 7) - -#define AO_USB_TYPE_STANDARD 0 -#define AO_USB_TYPE_CLASS (1 << 5) -#define AO_USB_TYPE_VENDOR (2 << 5) -#define AO_USB_TYPE_RESERVED (3 << 5) - -#define AO_USB_RECIP_DEVICE 0 -#define AO_USB_RECIP_INTERFACE 1 -#define AO_USB_RECIP_ENDPOINT 2 -#define AO_USB_RECIP_OTHER 3 - -/* standard requests */ -#define AO_USB_REQ_GET_STATUS 0x00 -#define AO_USB_REQ_CLEAR_FEATURE 0x01 -#define AO_USB_REQ_SET_FEATURE 0x03 -#define AO_USB_REQ_SET_ADDRESS 0x05 -#define AO_USB_REQ_GET_DESCRIPTOR 0x06 -#define AO_USB_REQ_SET_DESCRIPTOR 0x07 -#define AO_USB_REQ_GET_CONFIGURATION 0x08 -#define AO_USB_REQ_SET_CONFIGURATION 0x09 -#define AO_USB_REQ_GET_INTERFACE 0x0A -#define AO_USB_REQ_SET_INTERFACE 0x0B -#define AO_USB_REQ_SYNCH_FRAME 0x0C - -#define AO_USB_DESC_DEVICE 1 -#define AO_USB_DESC_CONFIGURATION 2 -#define AO_USB_DESC_STRING 3 -#define AO_USB_DESC_INTERFACE 4 -#define AO_USB_DESC_ENDPOINT 5 -#define AO_USB_DESC_DEVICE_QUALIFIER 6 -#define AO_USB_DESC_OTHER_SPEED 7 -#define AO_USB_DESC_INTERFACE_POWER 8 - -#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) -#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) - -#define AO_USB_CONTROL_EP 0 -#define AO_USB_INT_EP 1 -#define AO_USB_OUT_EP 4 -#define AO_USB_IN_EP 5 -#define AO_USB_CONTROL_SIZE 32 -/* - * Double buffer IN and OUT EPs, so each - * gets half of the available space - * - * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 - * byte sizes, so we'll use 64 for everything - */ -#define AO_USB_IN_SIZE 64 -#define AO_USB_OUT_SIZE 64 - -#define AO_USB_EP0_IDLE 0 -#define AO_USB_EP0_DATA_IN 1 -#define AO_USB_EP0_DATA_OUT 2 - -#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) - -/* CDC definitions */ -#define CS_INTERFACE 0x24 -#define CS_ENDPOINT 0x25 - -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_CONTROL_LINE_STATE 0x22 - -/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ -struct ao_usb_line_coding { - uint32_t rate; - uint8_t char_format; - uint8_t parity; - uint8_t data_bits; -} ; - -#endif /* _AO_USB_H_ */ diff --git a/src/avr/ao_usb_avr.c b/src/avr/ao_usb_avr.c index fc8899d8..23a27c73 100644 --- a/src/avr/ao_usb_avr.c +++ b/src/avr/ao_usb_avr.c @@ -330,17 +330,17 @@ ao_usb_ep0_setup(void) case AO_USB_TYPE_CLASS: debug ("Class setup packet\n"); switch (ao_usb_setup.request) { - case SET_LINE_CODING: + case AO_USB_SET_LINE_CODING: debug ("set line coding\n"); ao_usb_ep0_out_len = 7; ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; break; - case GET_LINE_CODING: + case AO_USB_GET_LINE_CODING: debug ("get line coding\n"); ao_usb_ep0_in_len = 7; ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; break; - case SET_CONTROL_LINE_STATE: + case AO_USB_SET_CONTROL_LINE_STATE: break; } break; diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h index 847ac1a6..9d0643b4 100644 --- a/src/cc1111/ao_arch.h +++ b/src/cc1111/ao_arch.h @@ -294,4 +294,34 @@ ao_dma_abort(uint8_t id); void ao_dma_isr(void) ao_arch_interrupt(8); +/* ao_adc.c */ + +#if HAS_ADC +/* The A/D interrupt handler */ +void +ao_adc_isr(void) ao_arch_interrupt(1); +#endif + +#if HAS_USB +/* USB interrupt handler */ +void +ao_usb_isr(void) ao_arch_interrupt(6); +#endif + +#if HAS_SERIAL_0 +void +ao_serial0_rx_isr(void) ao_arch_interrupt(2); + +void +ao_serial0_tx_isr(void) ao_arch_interrupt(7); +#endif + +#if HAS_SERIAL_1 +void +ao_serial1_rx_isr(void) ao_arch_interrupt(3); + +void +ao_serial1_tx_isr(void) ao_arch_interrupt(14); +#endif + #endif /* _AO_ARCH_H_ */ diff --git a/src/cc1111/ao_pins.h b/src/cc1111/ao_pins.h index 5c0cb7df..4f6edd37 100644 --- a/src/cc1111/ao_pins.h +++ b/src/cc1111/ao_pins.h @@ -25,7 +25,6 @@ #define HAS_GPS 1 #define HAS_SERIAL_1 1 #define HAS_ADC 1 - #define USE_SERIAL_STDIN 0 #define HAS_EEPROM 1 #define HAS_LOG 1 #define USE_INTERNAL_FLASH 0 @@ -58,7 +57,6 @@ #define HAS_BEEP 1 #define HAS_GPS 1 #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_LOG 1 @@ -95,7 +93,6 @@ #define HAS_BEEP 1 #define HAS_GPS 1 #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_LOG 1 @@ -131,7 +128,6 @@ #define HAS_USB 1 #define HAS_BEEP 0 #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 0 #define HAS_DBG 1 #define HAS_EEPROM 0 @@ -161,7 +157,6 @@ #define HAS_BEEP 0 #define HAS_GPS 0 #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_LOG 1 @@ -188,7 +183,6 @@ #define HAS_BEEP 0 #define HAS_GPS 0 #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_LOG 1 @@ -214,7 +208,6 @@ #define HAS_BEEP 1 #define HAS_GPS 1 #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 1 #define HAS_DBG 0 #define HAS_EEPROM 1 @@ -244,7 +237,6 @@ #define HAS_USB 1 #define HAS_BEEP 0 #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 0 #define HAS_DBG 0 #define HAS_EEPROM 0 @@ -273,7 +265,6 @@ #define HAS_USB 1 #define HAS_BEEP 0 #define HAS_SERIAL_1 0 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 0 #define HAS_DBG 1 #define HAS_EEPROM 0 @@ -301,7 +292,8 @@ #define HAS_USB 1 #define HAS_BEEP 0 #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 1 + #define USE_SERIAL_1_STDIN 1 + #define DELAY_SERIAL_1_STDIN 1 #define HAS_ADC 0 #define HAS_DBG 1 #define HAS_EEPROM 0 @@ -339,7 +331,8 @@ #define HAS_SERIAL_1_ALT_1 1 #define HAS_SERIAL_1_ALT_2 0 #define HAS_SERIAL_1_HW_FLOW 1 - #define USE_SERIAL_STDIN 1 + #define USE_SERIAL_1_STDIN 1 + #define DELAY_SERIAL_1_STDIN 1 #define HAS_ADC 0 #define HAS_DBG 1 #define HAS_EEPROM 1 @@ -379,7 +372,6 @@ #define HAS_BEEP 1 #define HAS_GPS 0 #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 1 #define HAS_DBG 0 #define HAS_EEPROM 1 @@ -468,14 +460,6 @@ #error Please define IGNITE_ON_P0 #endif -#ifndef HAS_SERIAL_1 -#error Please define HAS_SERIAL_1 -#endif - -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - #ifndef HAS_ADC #error Please define HAS_ADC #endif diff --git a/src/cc1111/ao_serial.c b/src/cc1111/ao_serial.c index 4d5b9abd..00c85ff3 100644 --- a/src/cc1111/ao_serial.c +++ b/src/cc1111/ao_serial.c @@ -17,78 +17,168 @@ #include "ao.h" -volatile __xdata struct ao_fifo ao_usart1_rx_fifo; -volatile __xdata struct ao_fifo ao_usart1_tx_fifo; +#if HAS_SERIAL_0 + +volatile __xdata struct ao_fifo ao_serial0_rx_fifo; +volatile __xdata struct ao_fifo ao_serial0_tx_fifo; + +void +ao_serial0_rx_isr(void) __interrupt 2 +{ + if (!ao_fifo_full(ao_serial0_rx_fifo)) + ao_fifo_insert(ao_serial0_rx_fifo, U0DBUF); + ao_wakeup(&ao_serial0_rx_fifo); +#if USE_SERIAL_0_STDIN + ao_wakeup(&ao_stdin_ready); +#endif +} + +static __xdata uint8_t ao_serial0_tx_started; + +static void +ao_serial0_tx_start(void) +{ + if (!ao_fifo_empty(ao_serial0_tx_fifo) && + !ao_serial0_tx_started) + { + ao_serial0_tx_started = 1; + ao_fifo_remove(ao_serial0_tx_fifo, U0DBUF); + } +} + +void +ao_serial0_tx_isr(void) __interrupt 7 +{ + UTX0IF = 0; + ao_serial0_tx_started = 0; + ao_serial0_tx_start(); + ao_wakeup(&ao_serial0_tx_fifo); +} + +char +ao_serial0_getchar(void) __critical +{ + char c; + while (ao_fifo_empty(ao_serial0_rx_fifo)) + ao_sleep(&ao_serial0_rx_fifo); + ao_fifo_remove(ao_serial0_rx_fifo, c); + return c; +} + +#if USE_SERIAL_0_STDIN +char +ao_serial0_pollchar(void) __critical +{ + char c; + if (ao_fifo_empty(ao_serial0_rx_fifo)) + return AO_READ_AGAIN; + ao_fifo_remove(ao_serial0_rx_fifo,c); + return c; +} +#endif + +void +ao_serial0_putchar(char c) __critical +{ + while (ao_fifo_full(ao_serial0_tx_fifo)) + ao_sleep(&ao_serial0_tx_fifo); + ao_fifo_insert(ao_serial0_tx_fifo, c); + ao_serial0_tx_start(); +} + +void +ao_serial0_drain(void) __critical +{ + while (!ao_fifo_empty(ao_serial0_tx_fifo)) + ao_sleep(&ao_serial0_tx_fifo); +} + +void +ao_serial0_set_speed(uint8_t speed) +{ + ao_serial0_drain(); + if (speed > AO_SERIAL_SPEED_57600) + return; + U0UCR |= UxUCR_FLUSH; + U0BAUD = ao_serial_speeds[speed].baud; + U0GCR = ao_serial_speeds[speed].gcr; +} +#endif /* HAS_SERIAL_0 */ + +#if HAS_SERIAL_1 + +volatile __xdata struct ao_fifo ao_serial1_rx_fifo; +volatile __xdata struct ao_fifo ao_serial1_tx_fifo; void -ao_serial_rx1_isr(void) __interrupt 3 +ao_serial1_rx_isr(void) __interrupt 3 { - if (!ao_fifo_full(ao_usart1_rx_fifo)) - ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF); - ao_wakeup(&ao_usart1_rx_fifo); -#if USE_SERIAL_STDIN + if (!ao_fifo_full(ao_serial1_rx_fifo)) + ao_fifo_insert(ao_serial1_rx_fifo, U1DBUF); + ao_wakeup(&ao_serial1_rx_fifo); +#if USE_SERIAL1_STDIN ao_wakeup(&ao_stdin_ready); #endif } -static __xdata uint8_t ao_serial_tx1_started; +static __xdata uint8_t ao_serial1_tx_started; static void -ao_serial_tx1_start(void) +ao_serial1_tx_start(void) { - if (!ao_fifo_empty(ao_usart1_tx_fifo) && - !ao_serial_tx1_started) + if (!ao_fifo_empty(ao_serial1_tx_fifo) && + !ao_serial1_tx_started) { - ao_serial_tx1_started = 1; - ao_fifo_remove(ao_usart1_tx_fifo, U1DBUF); + ao_serial1_tx_started = 1; + ao_fifo_remove(ao_serial1_tx_fifo, U1DBUF); } } void -ao_serial_tx1_isr(void) __interrupt 14 +ao_serial1_tx_isr(void) __interrupt 14 { UTX1IF = 0; - ao_serial_tx1_started = 0; - ao_serial_tx1_start(); - ao_wakeup(&ao_usart1_tx_fifo); + ao_serial1_tx_started = 0; + ao_serial1_tx_start(); + ao_wakeup(&ao_serial1_tx_fifo); } char -ao_serial_getchar(void) __critical +ao_serial1_getchar(void) __critical { char c; - while (ao_fifo_empty(ao_usart1_rx_fifo)) - ao_sleep(&ao_usart1_rx_fifo); - ao_fifo_remove(ao_usart1_rx_fifo, c); + while (ao_fifo_empty(ao_serial1_rx_fifo)) + ao_sleep(&ao_serial1_rx_fifo); + ao_fifo_remove(ao_serial1_rx_fifo, c); return c; } -#if USE_SERIAL_STDIN +#if USE_SERIAL_1_STDIN char -ao_serial_pollchar(void) __critical +ao_serial1_pollchar(void) __critical { char c; - if (ao_fifo_empty(ao_usart1_rx_fifo)) + if (ao_fifo_empty(ao_serial1_rx_fifo)) return AO_READ_AGAIN; - ao_fifo_remove(ao_usart1_rx_fifo,c); + ao_fifo_remove(ao_serial1_rx_fifo,c); return c; } #endif void -ao_serial_putchar(char c) __critical +ao_serial1_putchar(char c) __critical { - while (ao_fifo_full(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); - ao_fifo_insert(ao_usart1_tx_fifo, c); - ao_serial_tx1_start(); + while (ao_fifo_full(ao_serial1_tx_fifo)) + ao_sleep(&ao_serial1_tx_fifo); + ao_fifo_insert(ao_serial1_tx_fifo, c); + ao_serial1_tx_start(); } void -ao_serial_drain(void) __critical +ao_serial1_drain(void) __critical { - while (!ao_fifo_empty(ao_usart1_tx_fifo)) - ao_sleep(&ao_usart1_tx_fifo); + while (!ao_fifo_empty(ao_serial1_tx_fifo)) + ao_sleep(&ao_serial1_tx_fifo); } const __code struct ao_serial_speed ao_serial_speeds[] = { @@ -111,9 +201,9 @@ const __code struct ao_serial_speed ao_serial_speeds[] = { }; void -ao_serial_set_speed(uint8_t speed) +ao_serial1_set_speed(uint8_t speed) { - ao_serial_drain(); + ao_serial1_drain(); if (speed > AO_SERIAL_SPEED_57600) return; U1UCR |= UxUCR_FLUSH; @@ -121,9 +211,67 @@ ao_serial_set_speed(uint8_t speed) U1GCR = ao_serial_speeds[speed].gcr; } +#endif /* HAS_SERIAL_1 */ + void ao_serial_init(void) { +#if HAS_SERIAL_0 +#if HAS_SERIAL_0_ALT_1 + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_1; + + P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART0_USART1; + + /* Make the USART pins be controlled by the USART */ + P0SEL |= (1 << 2) | (1 << 3); +#if HAS_SERIAL_0_HW_FLOW + P0SEL |= (1 << 4) | (1 << 5); +#endif +#else + /* Set up the USART pin assignment */ + PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2; + + P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI0P1_MASK)) | + (P2SEL_PRI3P1_USART0 | P2SEL_PRI0P1_USART0); + + /* Make the USART pins be controlled by the USART */ + P1SEL |= (1 << 2) | (1 << 3); +#if HAS_SERIAL_0_HW_FLOW + P1SEL |= (1 << 5) | (1 << 4); +#endif +#endif + + /* UART mode with receiver enabled */ + U0CSR = (UxCSR_MODE_UART | UxCSR_RE); + + /* Pick a 9600 baud rate */ + ao_serial0_set_speed(AO_SERIAL_SPEED_9600); + + /* Reasonable serial parameters */ + U0UCR = (UxUCR_FLUSH | +#if HAS_SERIAL_0_HW_FLOW + UxUCR_FLOW_ENABLE | +#else + UxUCR_FLOW_DISABLE | +#endif + UxUCR_D9_EVEN_PARITY | + UxUCR_BIT9_8_BITS | + UxUCR_PARITY_DISABLE | + UxUCR_SPB_1_STOP_BIT | + UxUCR_STOP_HIGH | + UxUCR_START_LOW); + + IEN0 |= IEN0_URX0IE; + IEN2 |= IEN2_UTX0IE; +#if USE_SERIAL_0_STDIN && !DELAY_SERIAL_0_STDIN + ao_add_stdio(ao_serial0_pollchar, + ao_serial0_putchar, + NULL); +#endif +#endif /* HAS_SERIAL_0 */ + +#if HAS_SERIAL_1 #if HAS_SERIAL_1_ALT_1 /* Set up the USART pin assignment */ PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1; @@ -151,7 +299,7 @@ ao_serial_init(void) U1CSR = (UxCSR_MODE_UART | UxCSR_RE); /* Pick a 4800 baud rate */ - ao_serial_set_speed(AO_SERIAL_SPEED_4800); + ao_serial1_set_speed(AO_SERIAL_SPEED_4800); /* Reasonable serial parameters */ U1UCR = (UxUCR_FLUSH | @@ -169,4 +317,11 @@ ao_serial_init(void) IEN0 |= IEN0_URX1IE; IEN2 |= IEN2_UTX1IE; + +#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN + ao_add_stdio(ao_serial1_pollchar, + ao_serial1_putchar, + NULL); +#endif +#endif /* HAS_SERIAL_1 */ } diff --git a/src/cc1111/ao_serial0.c b/src/cc1111/ao_serial0.c deleted file mode 100644 index e8c1eb35..00000000 --- a/src/cc1111/ao_serial0.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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 "ao.h" - -volatile __xdata struct ao_fifo ao_usart0_rx_fifo; -volatile __xdata struct ao_fifo ao_usart0_tx_fifo; - -void -ao_serial0_rx0_isr(void) __interrupt 2 -{ - if (!ao_fifo_full(ao_usart0_rx_fifo)) - ao_fifo_insert(ao_usart0_rx_fifo, U0DBUF); - ao_wakeup(&ao_usart0_rx_fifo); -} - -static __xdata uint8_t ao_serial0_tx0_started; - -static void -ao_serial0_tx0_start(void) -{ - if (!ao_fifo_empty(ao_usart0_tx_fifo) && - !ao_serial0_tx0_started) - { - ao_serial0_tx0_started = 1; - ao_fifo_remove(ao_usart0_tx_fifo, U0DBUF); - } -} - -void -ao_serial0_tx0_isr(void) __interrupt 7 -{ - UTX0IF = 0; - ao_serial0_tx0_started = 0; - ao_serial0_tx0_start(); - ao_wakeup(&ao_usart0_tx_fifo); -} - -char -ao_serial0_getchar(void) __critical -{ - char c; - while (ao_fifo_empty(ao_usart0_rx_fifo)) - ao_sleep(&ao_usart0_rx_fifo); - ao_fifo_remove(ao_usart0_rx_fifo, c); - return c; -} - -#if USE_SERIAL_STDIN -char -ao_serial0_pollchar(void) __critical -{ - char c; - if (ao_fifo_empty(ao_usart0_rx_fifo)) - return AO_READ_AGAIN; - ao_fifo_remove(ao_usart0_rx_fifo,c); - return c; -} -#endif - -void -ao_serial0_putchar(char c) __critical -{ - while (ao_fifo_full(ao_usart0_tx_fifo)) - ao_sleep(&ao_usart0_tx_fifo); - ao_fifo_insert(ao_usart0_tx_fifo, c); - ao_serial0_tx0_start(); -} - -void -ao_serial0_drain(void) __critical -{ - while (!ao_fifo_empty(ao_usart0_tx_fifo)) - ao_sleep(&ao_usart0_tx_fifo); -} - -void -ao_serial0_set_speed(uint8_t speed) -{ - ao_serial0_drain(); - if (speed > AO_SERIAL_SPEED_57600) - return; - U0UCR |= UxUCR_FLUSH; - U0BAUD = ao_serial_speeds[speed].baud; - U0GCR = ao_serial_speeds[speed].gcr; -} - -void -ao_serial0_init(void) -{ -#if HAS_SERIAL_0_ALT_1 - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_1; - - P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART0_USART1; - - /* Make the USART pins be controlled by the USART */ - P0SEL |= (1 << 2) | (1 << 3); -#if HAS_SERIAL_0_HW_FLOW - P0SEL |= (1 << 4) | (1 << 5); -#endif -#else - /* Set up the USART pin assignment */ - PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2; - - P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI0P1_MASK)) | - (P2SEL_PRI3P1_USART0 | P2SEL_PRI0P1_USART0); - - /* Make the USART pins be controlled by the USART */ - P1SEL |= (1 << 2) | (1 << 3); -#if HAS_SERIAL_0_HW_FLOW - P1SEL |= (1 << 5) | (1 << 4); -#endif -#endif - - /* UART mode with receiver enabled */ - U0CSR = (UxCSR_MODE_UART | UxCSR_RE); - - /* Pick a 9600 baud rate */ - ao_serial0_set_speed(AO_SERIAL_SPEED_9600); - - /* Reasonable serial parameters */ - U0UCR = (UxUCR_FLUSH | -#if HAS_SERIAL_0_HW_FLOW - UxUCR_FLOW_ENABLE | -#else - UxUCR_FLOW_DISABLE | -#endif - UxUCR_D9_EVEN_PARITY | - UxUCR_BIT9_8_BITS | - UxUCR_PARITY_DISABLE | - UxUCR_SPB_1_STOP_BIT | - UxUCR_STOP_HIGH | - UxUCR_START_LOW); - - IEN0 |= IEN0_URX0IE; - IEN2 |= IEN2_UTX0IE; -} diff --git a/src/cc1111/ao_usb.c b/src/cc1111/ao_usb.c index 35c9ac20..ce26e808 100644 --- a/src/cc1111/ao_usb.c +++ b/src/cc1111/ao_usb.c @@ -261,15 +261,15 @@ ao_usb_ep0_setup(void) break; case AO_USB_TYPE_CLASS: switch (ao_usb_setup.request) { - case SET_LINE_CODING: + case AO_USB_SET_LINE_CODING: ao_usb_ep0_out_len = 7; ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; break; - case GET_LINE_CODING: + case AO_USB_GET_LINE_CODING: ao_usb_ep0_in_len = 7; ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; break; - case SET_CONTROL_LINE_STATE: + case AO_USB_SET_CONTROL_LINE_STATE: break; } break; diff --git a/src/cc1111/ao_usb.h b/src/cc1111/ao_usb.h deleted file mode 100644 index 6633dafc..00000000 --- a/src/cc1111/ao_usb.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef _AO_USB_H_ -#define _AO_USB_H_ - -#define AO_USB_SETUP_DIR_MASK (0x01 << 7) -#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) -#define AO_USB_SETUP_RECIP_MASK (0x1f) - -#define AO_USB_DIR_OUT 0 -#define AO_USB_DIR_IN (1 << 7) - -#define AO_USB_TYPE_STANDARD 0 -#define AO_USB_TYPE_CLASS (1 << 5) -#define AO_USB_TYPE_VENDOR (2 << 5) -#define AO_USB_TYPE_RESERVED (3 << 5) - -#define AO_USB_RECIP_DEVICE 0 -#define AO_USB_RECIP_INTERFACE 1 -#define AO_USB_RECIP_ENDPOINT 2 -#define AO_USB_RECIP_OTHER 3 - -/* standard requests */ -#define AO_USB_REQ_GET_STATUS 0x00 -#define AO_USB_REQ_CLEAR_FEATURE 0x01 -#define AO_USB_REQ_SET_FEATURE 0x03 -#define AO_USB_REQ_SET_ADDRESS 0x05 -#define AO_USB_REQ_GET_DESCRIPTOR 0x06 -#define AO_USB_REQ_SET_DESCRIPTOR 0x07 -#define AO_USB_REQ_GET_CONFIGURATION 0x08 -#define AO_USB_REQ_SET_CONFIGURATION 0x09 -#define AO_USB_REQ_GET_INTERFACE 0x0A -#define AO_USB_REQ_SET_INTERFACE 0x0B -#define AO_USB_REQ_SYNCH_FRAME 0x0C - -#define AO_USB_DESC_DEVICE 1 -#define AO_USB_DESC_CONFIGURATION 2 -#define AO_USB_DESC_STRING 3 -#define AO_USB_DESC_INTERFACE 4 -#define AO_USB_DESC_ENDPOINT 5 -#define AO_USB_DESC_DEVICE_QUALIFIER 6 -#define AO_USB_DESC_OTHER_SPEED 7 -#define AO_USB_DESC_INTERFACE_POWER 8 - -#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) -#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) - -#define AO_USB_CONTROL_EP 0 -#define AO_USB_INT_EP 1 -#define AO_USB_OUT_EP 4 -#define AO_USB_IN_EP 5 -#define AO_USB_CONTROL_SIZE 32 -/* - * Double buffer IN and OUT EPs, so each - * gets half of the available space - * - * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 - * byte sizes, so we'll use 64 for everything - */ -#define AO_USB_IN_SIZE 64 -#define AO_USB_OUT_SIZE 64 - -#define AO_USB_EP0_IDLE 0 -#define AO_USB_EP0_DATA_IN 1 -#define AO_USB_EP0_DATA_OUT 2 - -#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) - -/* CDC definitions */ -#define CS_INTERFACE 0x24 -#define CS_ENDPOINT 0x25 - -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_CONTROL_LINE_STATE 0x22 - -/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ -struct ao_usb_line_coding { - uint32_t rate; - uint8_t char_format; - uint8_t parity; - uint8_t data_bits; -} ; - -#endif /* _AO_USB_H_ */ diff --git a/src/core/ao.h b/src/core/ao.h index 9a3b5829..28d0ba87 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -154,182 +154,14 @@ void ao_clock_init(void); /* - * One set of samples read from the A/D converter or telemetry - */ - -#if HAS_ADC - -/* - * ao_adc.c - */ - -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) - - -/* - * A/D data is stored in a ring, with the next sample to be written - * at ao_adc_head - */ -extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -extern volatile __data uint8_t ao_adc_head; -#if HAS_ACCEL_REF -extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; -#endif - -/* Trigger a conversion sequence (called from the timer interrupt) */ -void -ao_adc_poll(void); - -/* Suspend the current task until another A/D sample is converted */ -void -ao_adc_sleep(void); - -/* Get a copy of the last complete A/D sample set */ -void -ao_adc_get(__xdata struct ao_adc *packet); - -/* The A/D interrupt handler */ - -void -ao_adc_isr(void) ao_arch_interrupt(1); - -/* Initialize the A/D converter */ -void -ao_adc_init(void); - -#endif /* HAS_ADC */ - -/* - * ao_beep.c - */ - -/* - * Various pre-defined beep frequencies - * - * frequency = 1/2 (24e6/32) / beep - */ - -#define AO_BEEP_LOW 150 /* 2500Hz */ -#define AO_BEEP_MID 94 /* 3989Hz */ -#define AO_BEEP_HIGH 75 /* 5000Hz */ -#define AO_BEEP_OFF 0 /* off */ - -#define AO_BEEP_g 240 /* 1562.5Hz */ -#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */ -#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */ -#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */ -#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */ -#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */ -#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */ -#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */ -#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */ -#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */ -#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */ -#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */ -#define AO_BEEP_gg 120 /* 3125Hz */ -#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */ -#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */ -#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */ -#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */ -#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */ -#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */ -#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */ -#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */ -#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */ -#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */ -#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */ -#define AO_BEEP_ggg 60 /* 6250Hz */ - -/* Set the beeper to the specified tone */ -void -ao_beep(uint8_t beep); - -/* Turn on the beeper for the specified time */ -void -ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant; - -/* Initialize the beeper */ -void -ao_beep_init(void); - -/* - * ao_led.c - */ - -#define AO_LED_NONE 0 - -#ifndef AO_LED_TYPE -#define AO_LED_TYPE uint8_t -#endif - -/* Turn on the specified LEDs */ -void -ao_led_on(AO_LED_TYPE colors); - -/* Turn off the specified LEDs */ -void -ao_led_off(AO_LED_TYPE colors); - -/* Set all of the LEDs to the specified state */ -void -ao_led_set(AO_LED_TYPE colors); - -/* Toggle the specified LEDs */ -void -ao_led_toggle(AO_LED_TYPE colors); - -/* Turn on the specified LEDs for the indicated interval */ -void -ao_led_for(AO_LED_TYPE colors, uint16_t ticks) __reentrant; - -/* Initialize the LEDs */ -void -ao_led_init(AO_LED_TYPE enable); - -/* - * ao_usb.c - */ - -/* Put one character to the USB output queue */ -void -ao_usb_putchar(char c); - -/* Get one character from the USB input queue */ -char -ao_usb_getchar(void); - -/* Poll for a charcter on the USB input queue. - * returns AO_READ_AGAIN if none are available + * ao_mutex.c */ -char -ao_usb_pollchar(void); - -/* Flush the USB output queue */ -void -ao_usb_flush(void); - -#if HAS_USB -/* USB interrupt handler */ -void -ao_usb_isr(void) ao_arch_interrupt(6); -#endif -/* Enable the USB controller */ void -ao_usb_enable(void); - -/* Disable the USB controller */ -void -ao_usb_disable(void); +ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant; -/* Initialize the USB system */ void -ao_usb_init(void); - -#if HAS_USB -extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; -#endif +ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant; /* * ao_cmd.c @@ -396,405 +228,36 @@ ao_cmd_filter(void); #endif /* - * ao_mutex.c - */ - -void -ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant; - -void -ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant; - -/* - * Storage interface, provided by one of the eeprom or flash - * drivers - */ - -/* Total bytes of available storage */ -extern __pdata uint32_t ao_storage_total; - -/* Block size - device is erased in these units. At least 256 bytes */ -extern __pdata uint32_t ao_storage_block; - -/* Byte offset of config block. Will be ao_storage_block bytes long */ -extern __pdata uint32_t ao_storage_config; - -/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ -extern __pdata uint16_t ao_storage_unit; - -#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE) - -/* Initialize above values. Can only be called once the OS is running */ -void -ao_storage_setup(void) __reentrant; - -/* Write data. Returns 0 on failure, 1 on success */ -uint8_t -ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Read data. Returns 0 on failure, 1 on success */ -uint8_t -ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Erase a block of storage. This always clears ao_storage_block bytes */ -uint8_t -ao_storage_erase(uint32_t pos) __reentrant; - -/* Flush any pending writes to stable storage */ -void -ao_storage_flush(void) __reentrant; - -/* Initialize the storage code */ -void -ao_storage_init(void); - -/* - * Low-level functions wrapped by ao_storage.c - */ - -/* Read data within a storage unit */ -uint8_t -ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Write data within a storage unit */ -uint8_t -ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; - -/* Initialize low-level device bits */ -void -ao_storage_device_init(void); - -/* Print out information about flash chips */ -void -ao_storage_device_info(void) __reentrant; - -/* - * ao_log.c - */ - -/* We record flight numbers in the first record of - * the log. Tasks may wait for this to be initialized - * by sleeping on this variable. - */ -extern __xdata uint16_t ao_flight_number; - -extern __pdata uint32_t ao_log_current_pos; -extern __pdata uint32_t ao_log_end_pos; -extern __pdata uint32_t ao_log_start_pos; -extern __xdata uint8_t ao_log_running; -extern __pdata enum flight_state ao_log_state; - -/* required functions from the underlying log system */ - -#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ -#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ -#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ -#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ -#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ -#define AO_LOG_FORMAT_NONE 127 /* No log at all */ - -extern __code uint8_t ao_log_format; - -/* Return the flight number from the given log slot, 0 if none */ -uint16_t -ao_log_flight(uint8_t slot); - -/* Flush the log */ -void -ao_log_flush(void); - -/* Logging thread main routine */ -void -ao_log(void); - -/* functions provided in ao_log.c */ - -/* Figure out the current flight number */ -void -ao_log_scan(void) __reentrant; - -/* Return the position of the start of the given log slot */ -uint32_t -ao_log_pos(uint8_t slot); - -/* Start logging to eeprom */ -void -ao_log_start(void); - -/* Stop logging */ -void -ao_log_stop(void); - -/* Initialize the logging system */ -void -ao_log_init(void); - -/* Write out the current flight number to the erase log */ -void -ao_log_write_erase(uint8_t pos); - -/* Returns true if there are any logs stored in eeprom */ -uint8_t -ao_log_present(void); - -/* Returns true if there is no more storage space available */ -uint8_t -ao_log_full(void); - -/* - * ao_log_big.c + * Various drivers */ - -/* - * The data log is recorded in the eeprom as a sequence - * of data packets. - * - * Each packet starts with a 4-byte header that has the - * packet type, the packet checksum and the tick count. Then - * they all contain 2 16 bit values which hold packet-specific - * data. - * - * For each flight, the first packet - * is FLIGHT packet, indicating the serial number of the - * device and a unique number marking the number of flights - * recorded by this device. - * - * During flight, data from the accelerometer and barometer - * are recorded in SENSOR packets, using the raw 16-bit values - * read from the A/D converter. - * - * Also during flight, but at a lower rate, the deployment - * sensors are recorded in DEPLOY packets. The goal here is to - * detect failure in the deployment circuits. - * - * STATE packets hold state transitions as the flight computer - * transitions through different stages of the flight. - */ -#define AO_LOG_FLIGHT 'F' -#define AO_LOG_SENSOR 'A' -#define AO_LOG_TEMP_VOLT 'T' -#define AO_LOG_DEPLOY 'D' -#define AO_LOG_STATE 'S' -#define AO_LOG_GPS_TIME 'G' -#define AO_LOG_GPS_LAT 'N' -#define AO_LOG_GPS_LON 'W' -#define AO_LOG_GPS_ALT 'H' -#define AO_LOG_GPS_SAT 'V' -#define AO_LOG_GPS_DATE 'Y' - -#define AO_LOG_POS_NONE (~0UL) - -struct ao_log_record { - char type; - uint8_t csum; - uint16_t tick; - union { - struct { - int16_t ground_accel; - uint16_t flight; - } flight; - struct { - int16_t accel; - int16_t pres; - } sensor; - struct { - int16_t temp; - int16_t v_batt; - } temp_volt; - struct { - int16_t drogue; - int16_t main; - } deploy; - struct { - uint16_t state; - uint16_t reason; - } state; - struct { - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t flags; - } gps_time; - int32_t gps_latitude; - int32_t gps_longitude; - struct { - int16_t altitude; - uint16_t unused; - } gps_altitude; - struct { - uint16_t svid; - uint8_t unused; - uint8_t c_n; - } gps_sat; - struct { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t extra; - } gps_date; - struct { - uint16_t d0; - uint16_t d1; - } anon; - } u; -}; - -/* Write a record to the eeprom log */ -uint8_t -ao_log_data(__xdata struct ao_log_record *log) __reentrant; - -/* - * ao_flight.c - */ - -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 __pdata enum ao_flight_state ao_flight_state; - -extern __pdata uint16_t ao_launch_time; -extern __pdata uint8_t ao_flight_force_idle; - -/* Flight thread */ -void -ao_flight(void); - -/* Initialize flight thread */ -void -ao_flight_init(void); - -/* - * ao_flight_nano.c - */ - -void -ao_flight_nano_init(void); - -/* - * ao_sample.c - */ - -/* - * Barometer calibration - * - * We directly sample the barometer. The specs say: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * If we want to detect launch with the barometer, we need - * a large enough bump to not be fooled by noise. At typical - * launch elevations (0-2000m), a 200Pa pressure change cooresponds - * to about a 20m elevation change. This is 5.4mV, or about 3LSB. - * As all of our calculations are done in 16 bits, we'll actually see a change - * of 16 times this though - * - * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa - */ - -/* Accelerometer calibration - * - * We're sampling the accelerometer through a resistor divider which - * consists of 5k and 10k resistors. This multiplies the values by 2/3. - * That goes into the cc1111 A/D converter, which is running at 11 bits - * of precision with the bits in the MSB of the 16 bit value. Only positive - * values are used, so values should range from 0-32752 for 0-3.3V. The - * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what - * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, - * for a final computation of: - * - * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g - * - * Zero g was measured at 16000 (we would expect 16384). - * Note that this value is only require to tell if the - * rocket is standing upright. Once that is determined, - * the value of the accelerometer is averaged for 100 samples - * to find the resting accelerometer value, which is used - * for all further flight computations - */ - -#define GRAVITY 9.80665 - -/* - * Above this height, the baro sensor doesn't work - */ -#define AO_MAX_BARO_HEIGHT 12000 - -/* - * Above this speed, baro measurements are unreliable - */ -#define AO_MAX_BARO_SPEED 200 - -#define ACCEL_NOSE_UP (ao_accel_2g >> 2) - -/* - * Speed and acceleration are scaled by 16 to provide a bit more - * resolution while still having reasonable range. Note that this - * limits speed to 2047m/s (around mach 6) and acceleration to - * 2047m/s² (over 200g) - */ - -#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) -#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) -#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) - -extern __pdata uint16_t ao_sample_tick; /* time of last data */ -extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */ -extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */ -extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */ -extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ - -#if HAS_ACCEL -extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */ +#if HAS_ADC +#include #endif -extern __pdata int16_t ao_ground_pres; /* startup pressure */ -extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ - -#if HAS_ACCEL -extern __pdata int16_t ao_ground_accel; /* startup acceleration */ -extern __pdata int16_t ao_accel_2g; /* factory accel calibration */ -extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#if HAS_BEEP +#include #endif -void ao_sample_init(void); - -/* returns FALSE in preflight mode, TRUE in flight mode */ -uint8_t ao_sample(void); - -/* - * ao_kalman.c - */ - -#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) -#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) -#define from_fix(x) ((x) >> 16) +#if LEDS_AVAILABLE +#include +#endif -extern __pdata int16_t ao_height; /* meters */ -extern __pdata int16_t ao_speed; /* m/s * 16 */ -extern __pdata int16_t ao_accel; /* m/s² * 16 */ -extern __pdata int16_t ao_max_height; /* max of ao_height */ -extern __pdata int16_t ao_avg_height; /* running average of height */ +#if HAS_USB +#include +#endif -extern __pdata int16_t ao_error_h; -extern __pdata int16_t ao_error_h_sq_avg; +#if HAS_EEPROM +#include +#endif -#if HAS_ACCEL -extern __pdata int16_t ao_error_a; +#if HAS_LOG +#include #endif -void ao_kalman(void); +#if HAS_FLIGHT +#include +#include +#endif /* * ao_report.c @@ -819,125 +282,12 @@ ao_altitude_to_pres(int16_t alt) __reentrant; int16_t ao_temp_to_dC(int16_t temp) __reentrant; -/* - * ao_dbg.c - * - * debug another telemetrum board - */ - -/* Send a byte to the dbg target */ -void -ao_dbg_send_byte(uint8_t byte); - -/* Receive a byte from the dbg target */ -uint8_t -ao_dbg_recv_byte(void); - -/* Start a bulk transfer to/from dbg target memory */ -void -ao_dbg_start_transfer(uint16_t addr); - -/* End a bulk transfer to/from dbg target memory */ -void -ao_dbg_end_transfer(void); - -/* Write a byte to dbg target memory */ -void -ao_dbg_write_byte(uint8_t byte); - -/* Read a byte from dbg target memory */ -uint8_t -ao_dbg_read_byte(void); - -/* Enable dbg mode, switching use of the pins */ -void -ao_dbg_debug_mode(void); - -/* Reset the dbg target */ -void -ao_dbg_reset(void); - -void -ao_dbg_init(void); - -/* - * ao_serial.c - */ - -#ifndef HAS_SERIAL_1 -#error Please define HAS_SERIAL_1 +#if HAS_DBG +#include #endif -#if HAS_SERIAL_1 | HAS_SERIAL_2 | HAS_SERIAL_3 -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - -void -ao_serial_rx1_isr(void) ao_arch_interrupt(3); - -void -ao_serial_tx1_isr(void) ao_arch_interrupt(14); - -char -ao_serial_getchar(void) __critical; - -#if USE_SERIAL_STDIN -char -ao_serial_pollchar(void) __critical; - -void -ao_serial_set_stdin(uint8_t in); -#endif - -void -ao_serial_putchar(char c) __critical; - -void -ao_serial_drain(void) __critical; - -#define AO_SERIAL_SPEED_4800 0 -#define AO_SERIAL_SPEED_9600 1 -#define AO_SERIAL_SPEED_19200 2 -#define AO_SERIAL_SPEED_57600 3 - -void -ao_serial_set_speed(uint8_t speed); - -void -ao_serial_init(void); -#endif - -#ifndef HAS_SERIAL_0 -#define HAS_SERIAL_0 0 -#endif - -#if HAS_SERIAL_0 - -extern volatile __xdata struct ao_fifo ao_usart0_rx_fifo; -extern volatile __xdata struct ao_fifo ao_usart0_tx_fifo; - -void -ao_serial0_rx0_isr(void) ao_arch_interrupt(2); - -void -ao_serial0_tx0_isr(void) ao_arch_interrupt(7); - -char -ao_serial0_getchar(void) __critical; - -void -ao_serial0_putchar(char c) __critical; - -void -ao_serial0_drain(void) __critical; - -void -ao_serial0_set_speed(uint8_t speed); - -void -ao_serial0_init(void); - +#if HAS_SERIAL_0 || HAS_SERIAL_1 || HAS_SERIAL_2 || HAS_SERIAL_3 +#include #endif diff --git a/src/core/ao_adc.h b/src/core/ao_adc.h new file mode 100644 index 00000000..db5bfab3 --- /dev/null +++ b/src/core/ao_adc.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_ADC_H_ +#define _AO_ADC_H_ + + + +/* + * One set of samples read from the A/D converter or telemetry + */ + + +/* + * ao_adc.c + */ + +#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) +#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) + + +/* + * A/D data is stored in a ring, with the next sample to be written + * at ao_adc_head + */ +extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; +extern volatile __data uint8_t ao_adc_head; +#if HAS_ACCEL_REF +extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; +#endif + +/* Trigger a conversion sequence (called from the timer interrupt) */ +void +ao_adc_poll(void); + +/* Suspend the current task until another A/D sample is converted */ +void +ao_adc_sleep(void); + +/* Get a copy of the last complete A/D sample set */ +void +ao_adc_get(__xdata struct ao_adc *packet); + +/* Initialize the A/D converter */ +void +ao_adc_init(void); + +#endif /* _AO_ADC_H_ */ diff --git a/src/core/ao_beep.h b/src/core/ao_beep.h new file mode 100644 index 00000000..55f61171 --- /dev/null +++ b/src/core/ao_beep.h @@ -0,0 +1,74 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_BEEP_H_ +#define _AO_BEEP_H_ + +/* + * ao_beep.c + */ + +/* + * Various pre-defined beep frequencies + * + * frequency = 1/2 (24e6/32) / beep + */ + +#define AO_BEEP_LOW 150 /* 2500Hz */ +#define AO_BEEP_MID 94 /* 3989Hz */ +#define AO_BEEP_HIGH 75 /* 5000Hz */ +#define AO_BEEP_OFF 0 /* off */ + +#define AO_BEEP_g 240 /* 1562.5Hz */ +#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */ +#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */ +#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */ +#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */ +#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */ +#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */ +#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */ +#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */ +#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */ +#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */ +#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */ +#define AO_BEEP_gg 120 /* 3125Hz */ +#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */ +#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */ +#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */ +#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */ +#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */ +#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */ +#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */ +#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */ +#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */ +#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */ +#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */ +#define AO_BEEP_ggg 60 /* 6250Hz */ + +/* Set the beeper to the specified tone */ +void +ao_beep(uint8_t beep); + +/* Turn on the beeper for the specified time */ +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant; + +/* Initialize the beeper */ +void +ao_beep_init(void); + +#endif /* _AO_BEEP_H_ */ diff --git a/src/core/ao_dbg.h b/src/core/ao_dbg.h new file mode 100644 index 00000000..181e6ec2 --- /dev/null +++ b/src/core/ao_dbg.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_DBG_H_ +#define _AO_DBG_H_ + +/* + * ao_dbg.c + * + * debug another telemetrum board + */ + +/* Send a byte to the dbg target */ +void +ao_dbg_send_byte(uint8_t byte); + +/* Receive a byte from the dbg target */ +uint8_t +ao_dbg_recv_byte(void); + +/* Start a bulk transfer to/from dbg target memory */ +void +ao_dbg_start_transfer(uint16_t addr); + +/* End a bulk transfer to/from dbg target memory */ +void +ao_dbg_end_transfer(void); + +/* Write a byte to dbg target memory */ +void +ao_dbg_write_byte(uint8_t byte); + +/* Read a byte from dbg target memory */ +uint8_t +ao_dbg_read_byte(void); + +/* Enable dbg mode, switching use of the pins */ +void +ao_dbg_debug_mode(void); + +/* Reset the dbg target */ +void +ao_dbg_reset(void); + +void +ao_dbg_init(void); + +#endif /* _AO_DBG_H_ */ diff --git a/src/core/ao_flight.h b/src/core/ao_flight.h new file mode 100644 index 00000000..aa5ab60d --- /dev/null +++ b/src/core/ao_flight.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_FLIGHT_H_ +#define _AO_FLIGHT_H_ + + +/* + * ao_flight.c + */ + +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 __pdata enum ao_flight_state ao_flight_state; + +extern __pdata uint16_t ao_launch_time; +extern __pdata uint8_t ao_flight_force_idle; + +/* Flight thread */ +void +ao_flight(void); + +/* Initialize flight thread */ +void +ao_flight_init(void); + +/* + * ao_flight_nano.c + */ + +void +ao_flight_nano_init(void); + +#endif /* _AO_FLIGHT_H_ */ diff --git a/src/core/ao_led.h b/src/core/ao_led.h new file mode 100644 index 00000000..edc5fd1f --- /dev/null +++ b/src/core/ao_led.h @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_LED_H_ +#define _AO_LED_H_ + +/* + * ao_led.c + */ + +#define AO_LED_NONE 0 + +#ifndef AO_LED_TYPE +#define AO_LED_TYPE uint8_t +#endif + +/* Turn on the specified LEDs */ +void +ao_led_on(AO_LED_TYPE colors); + +/* Turn off the specified LEDs */ +void +ao_led_off(AO_LED_TYPE colors); + +/* Set all of the LEDs to the specified state */ +void +ao_led_set(AO_LED_TYPE colors); + +/* Toggle the specified LEDs */ +void +ao_led_toggle(AO_LED_TYPE colors); + +/* Turn on the specified LEDs for the indicated interval */ +void +ao_led_for(AO_LED_TYPE colors, uint16_t ticks) __reentrant; + +/* Initialize the LEDs */ +void +ao_led_init(AO_LED_TYPE enable); + +#endif /* _AO_LED_H_ */ diff --git a/src/core/ao_log.h b/src/core/ao_log.h new file mode 100644 index 00000000..611c00d5 --- /dev/null +++ b/src/core/ao_log.h @@ -0,0 +1,196 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_LOG_H_ +#define _AO_LOG_H_ + +/* + * ao_log.c + */ + +/* We record flight numbers in the first record of + * the log. Tasks may wait for this to be initialized + * by sleeping on this variable. + */ +extern __xdata uint16_t ao_flight_number; + +extern __pdata uint32_t ao_log_current_pos; +extern __pdata uint32_t ao_log_end_pos; +extern __pdata uint32_t ao_log_start_pos; +extern __xdata uint8_t ao_log_running; +extern __pdata enum flight_state ao_log_state; + +/* required functions from the underlying log system */ + +#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ +#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ +#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ +#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ +#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ +#define AO_LOG_FORMAT_NONE 127 /* No log at all */ + +extern __code uint8_t ao_log_format; + +/* Return the flight number from the given log slot, 0 if none */ +uint16_t +ao_log_flight(uint8_t slot); + +/* Flush the log */ +void +ao_log_flush(void); + +/* Logging thread main routine */ +void +ao_log(void); + +/* functions provided in ao_log.c */ + +/* Figure out the current flight number */ +void +ao_log_scan(void) __reentrant; + +/* Return the position of the start of the given log slot */ +uint32_t +ao_log_pos(uint8_t slot); + +/* Start logging to eeprom */ +void +ao_log_start(void); + +/* Stop logging */ +void +ao_log_stop(void); + +/* Initialize the logging system */ +void +ao_log_init(void); + +/* Write out the current flight number to the erase log */ +void +ao_log_write_erase(uint8_t pos); + +/* Returns true if there are any logs stored in eeprom */ +uint8_t +ao_log_present(void); + +/* Returns true if there is no more storage space available */ +uint8_t +ao_log_full(void); + +/* + * ao_log_big.c + */ + +/* + * The data log is recorded in the eeprom as a sequence + * of data packets. + * + * Each packet starts with a 4-byte header that has the + * packet type, the packet checksum and the tick count. Then + * they all contain 2 16 bit values which hold packet-specific + * data. + * + * For each flight, the first packet + * is FLIGHT packet, indicating the serial number of the + * device and a unique number marking the number of flights + * recorded by this device. + * + * During flight, data from the accelerometer and barometer + * are recorded in SENSOR packets, using the raw 16-bit values + * read from the A/D converter. + * + * Also during flight, but at a lower rate, the deployment + * sensors are recorded in DEPLOY packets. The goal here is to + * detect failure in the deployment circuits. + * + * STATE packets hold state transitions as the flight computer + * transitions through different stages of the flight. + */ +#define AO_LOG_FLIGHT 'F' +#define AO_LOG_SENSOR 'A' +#define AO_LOG_TEMP_VOLT 'T' +#define AO_LOG_DEPLOY 'D' +#define AO_LOG_STATE 'S' +#define AO_LOG_GPS_TIME 'G' +#define AO_LOG_GPS_LAT 'N' +#define AO_LOG_GPS_LON 'W' +#define AO_LOG_GPS_ALT 'H' +#define AO_LOG_GPS_SAT 'V' +#define AO_LOG_GPS_DATE 'Y' + +#define AO_LOG_POS_NONE (~0UL) + +struct ao_log_record { + char type; + uint8_t csum; + uint16_t tick; + union { + struct { + int16_t ground_accel; + uint16_t flight; + } flight; + struct { + int16_t accel; + int16_t pres; + } sensor; + struct { + int16_t temp; + int16_t v_batt; + } temp_volt; + struct { + int16_t drogue; + int16_t main; + } deploy; + struct { + uint16_t state; + uint16_t reason; + } state; + struct { + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t flags; + } gps_time; + int32_t gps_latitude; + int32_t gps_longitude; + struct { + int16_t altitude; + uint16_t unused; + } gps_altitude; + struct { + uint16_t svid; + uint8_t unused; + uint8_t c_n; + } gps_sat; + struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t extra; + } gps_date; + struct { + uint16_t d0; + uint16_t d1; + } anon; + } u; +}; + +/* Write a record to the eeprom log */ +uint8_t +ao_log_data(__xdata struct ao_log_record *log) __reentrant; + +#endif /* _AO_LOG_H_ */ diff --git a/src/core/ao_log_telem.c b/src/core/ao_log_telem.c index 9e1b06d3..18ab85dd 100644 --- a/src/core/ao_log_telem.c +++ b/src/core/ao_log_telem.c @@ -15,7 +15,9 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include "ao.h" +#include +#include +#include __code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMETRY; diff --git a/src/core/ao_product.c b/src/core/ao_product.c index fb59580b..f79922f5 100644 --- a/src/core/ao_product.c +++ b/src/core/ao_product.c @@ -70,26 +70,26 @@ __code __at(0x00aa) uint8_t ao_usb_descriptors [] = /* Header functional descriptor */ 0x05, - CS_INTERFACE, + AO_USB_CS_INTERFACE, 0x00, /* bDescriptor SubType Header */ LE_WORD(0x0110), /* CDC version 1.1 */ /* Call management functional descriptor */ 0x05, - CS_INTERFACE, + AO_USB_CS_INTERFACE, 0x01, /* bDescriptor SubType Call Management */ 0x01, /* bmCapabilities = device handles call management */ 0x01, /* bDataInterface call management interface number */ /* ACM functional descriptor */ 0x04, - CS_INTERFACE, + AO_USB_CS_INTERFACE, 0x02, /* bDescriptor SubType Abstract Control Management */ 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */ /* Union functional descriptor */ 0x05, - CS_INTERFACE, + AO_USB_CS_INTERFACE, 0x06, /* bDescriptor SubType Union Functional descriptor */ 0x00, /* bMasterInterface */ 0x01, /* bSlaveInterface0 */ diff --git a/src/core/ao_report.c b/src/core/ao_report.c index 7c928792..eb90a4f8 100644 --- a/src/core/ao_report.c +++ b/src/core/ao_report.c @@ -16,6 +16,8 @@ */ #include "ao.h" +#include +#include #define BIT(i,x) ((x) ? (1 << (i)) : 0) #define MORSE1(a) (1 | BIT(3,a)) diff --git a/src/core/ao_sample.h b/src/core/ao_sample.h new file mode 100644 index 00000000..fb0e69e8 --- /dev/null +++ b/src/core/ao_sample.h @@ -0,0 +1,137 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_SAMPLE_H_ +#define _AO_SAMPLE_H_ + +/* + * ao_sample.c + */ + +/* + * Barometer calibration + * + * We directly sample the barometer. The specs say: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * If we want to detect launch with the barometer, we need + * a large enough bump to not be fooled by noise. At typical + * launch elevations (0-2000m), a 200Pa pressure change cooresponds + * to about a 20m elevation change. This is 5.4mV, or about 3LSB. + * As all of our calculations are done in 16 bits, we'll actually see a change + * of 16 times this though + * + * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa + */ + +/* Accelerometer calibration + * + * We're sampling the accelerometer through a resistor divider which + * consists of 5k and 10k resistors. This multiplies the values by 2/3. + * That goes into the cc1111 A/D converter, which is running at 11 bits + * of precision with the bits in the MSB of the 16 bit value. Only positive + * values are used, so values should range from 0-32752 for 0-3.3V. The + * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what + * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, + * for a final computation of: + * + * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g + * + * Zero g was measured at 16000 (we would expect 16384). + * Note that this value is only require to tell if the + * rocket is standing upright. Once that is determined, + * the value of the accelerometer is averaged for 100 samples + * to find the resting accelerometer value, which is used + * for all further flight computations + */ + +#define GRAVITY 9.80665 + +/* + * Above this height, the baro sensor doesn't work + */ +#define AO_MAX_BARO_HEIGHT 12000 + +/* + * Above this speed, baro measurements are unreliable + */ +#define AO_MAX_BARO_SPEED 200 + +#define ACCEL_NOSE_UP (ao_accel_2g >> 2) + +/* + * Speed and acceleration are scaled by 16 to provide a bit more + * resolution while still having reasonable range. Note that this + * limits speed to 2047m/s (around mach 6) and acceleration to + * 2047m/s² (over 200g) + */ + +#define AO_M_TO_HEIGHT(m) ((int16_t) (m)) +#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) +#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) + +extern __pdata uint16_t ao_sample_tick; /* time of last data */ +extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */ +extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */ +extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */ +extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ + +#if HAS_ACCEL +extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */ +#endif + +extern __pdata int16_t ao_ground_pres; /* startup pressure */ +extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +extern __pdata int16_t ao_ground_accel; /* startup acceleration */ +extern __pdata int16_t ao_accel_2g; /* factory accel calibration */ +extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +void ao_sample_init(void); + +/* returns FALSE in preflight mode, TRUE in flight mode */ +uint8_t ao_sample(void); + +/* + * ao_kalman.c + */ + +#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) +#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) +#define from_fix(x) ((x) >> 16) + +extern __pdata int16_t ao_height; /* meters */ +extern __pdata int16_t ao_speed; /* m/s * 16 */ +extern __pdata int16_t ao_accel; /* m/s² * 16 */ +extern __pdata int16_t ao_max_height; /* max of ao_height */ +extern __pdata int16_t ao_avg_height; /* running average of height */ + +extern __pdata int16_t ao_error_h; +extern __pdata int16_t ao_error_h_sq_avg; + +#if HAS_ACCEL +extern __pdata int16_t ao_error_a; +#endif + +void ao_kalman(void); + +#endif /* _AO_SAMPLE_H_ */ diff --git a/src/core/ao_serial.h b/src/core/ao_serial.h new file mode 100644 index 00000000..53aa8a89 --- /dev/null +++ b/src/core/ao_serial.h @@ -0,0 +1,86 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_SERIAL_H_ +#define _AO_SERIAL_H_ + +#define AO_SERIAL_SPEED_4800 0 +#define AO_SERIAL_SPEED_9600 1 +#define AO_SERIAL_SPEED_19200 2 +#define AO_SERIAL_SPEED_57600 3 + +#if HAS_SERIAL_0 +extern volatile __xdata struct ao_fifo ao_serial0_rx_fifo; +extern volatile __xdata struct ao_fifo ao_serial0_tx_fifo; + +char +ao_serial0_getchar(void); + +void +ao_serial0_putchar(char c); + +void +ao_serial0_drain(void); + +void +ao_serial0_set_speed(uint8_t speed); +#endif + +#if HAS_SERIAL_1 +extern volatile __xdata struct ao_fifo ao_serial1_rx_fifo; +extern volatile __xdata struct ao_fifo ao_serial1_tx_fifo; + +char +ao_serial1_getchar(void); + +char +ao_serial1_pollchar(void); + +void +ao_serial1_putchar(char c); + +void +ao_serial1_drain(void); + +void +ao_serial1_set_speed(uint8_t speed); +#endif + +#if HAS_SERIAL_2 +extern volatile __xdata struct ao_fifo ao_serial2_rx_fifo; +extern volatile __xdata struct ao_fifo ao_serial2_tx_fifo; + +char +ao_serial2_getchar(void); + +char +ao_serial2_pollchar(void); + +void +ao_serial2_putchar(char c); + +void +ao_serial2_drain(void); + +void +ao_serial2_set_speed(uint8_t speed); +#endif + +void +ao_serial_init(void); + +#endif /* _AO_SERIAL_H_ */ diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c index 2967e705..18fa913e 100644 --- a/src/core/ao_stdio.c +++ b/src/core/ao_stdio.c @@ -21,6 +21,12 @@ * Basic I/O functions to support SDCC stdio package */ +#ifdef SERIAL_STDIN_PORT +#define USE_SERIAL_STDIN 1 +#else +#define USE_SERIAL_STDIN 0 +#endif + #define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) __xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; diff --git a/src/core/ao_storage.c b/src/core/ao_storage.c index ff4747d0..66394e01 100644 --- a/src/core/ao_storage.c +++ b/src/core/ao_storage.c @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include "ao.h" +#include uint8_t ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant diff --git a/src/core/ao_storage.h b/src/core/ao_storage.h new file mode 100644 index 00000000..873fe097 --- /dev/null +++ b/src/core/ao_storage.h @@ -0,0 +1,84 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_STORAGE_H_ +#define _AO_STORAGE_H_ + +/* + * Storage interface, provided by one of the eeprom or flash + * drivers + */ + +/* Total bytes of available storage */ +extern __pdata uint32_t ao_storage_total; + +/* Block size - device is erased in these units. At least 256 bytes */ +extern __pdata uint32_t ao_storage_block; + +/* Byte offset of config block. Will be ao_storage_block bytes long */ +extern __pdata uint32_t ao_storage_config; + +/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */ +extern __pdata uint16_t ao_storage_unit; + +#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE) + +/* Initialize above values. Can only be called once the OS is running */ +void +ao_storage_setup(void) __reentrant; + +/* Write data. Returns 0 on failure, 1 on success */ +uint8_t +ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Read data. Returns 0 on failure, 1 on success */ +uint8_t +ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Erase a block of storage. This always clears ao_storage_block bytes */ +uint8_t +ao_storage_erase(uint32_t pos) __reentrant; + +/* Flush any pending writes to stable storage */ +void +ao_storage_flush(void) __reentrant; + +/* Initialize the storage code */ +void +ao_storage_init(void); + +/* + * Low-level functions wrapped by ao_storage.c + */ + +/* Read data within a storage unit */ +uint8_t +ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Write data within a storage unit */ +uint8_t +ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant; + +/* Initialize low-level device bits */ +void +ao_storage_device_init(void); + +/* Print out information about flash chips */ +void +ao_storage_device_info(void) __reentrant; + +#endif /* _AO_STORAGE_H_ */ diff --git a/src/core/ao_usb.h b/src/core/ao_usb.h new file mode 100644 index 00000000..e051db93 --- /dev/null +++ b/src/core/ao_usb.h @@ -0,0 +1,136 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_USB_H_ +#define _AO_USB_H_ + +/* + * ao_usb.c + */ + +/* Put one character to the USB output queue */ +void +ao_usb_putchar(char c); + +/* Get one character from the USB input queue */ +char +ao_usb_getchar(void); + +/* Poll for a charcter on the USB input queue. + * returns AO_READ_AGAIN if none are available + */ +char +ao_usb_pollchar(void); + +/* Flush the USB output queue */ +void +ao_usb_flush(void); + +/* Enable the USB controller */ +void +ao_usb_enable(void); + +/* Disable the USB controller */ +void +ao_usb_disable(void); + +/* Initialize the USB system */ +void +ao_usb_init(void); + +extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; + +#define AO_USB_SETUP_DIR_MASK (0x01 << 7) +#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) +#define AO_USB_SETUP_RECIP_MASK (0x1f) + +#define AO_USB_DIR_OUT 0 +#define AO_USB_DIR_IN (1 << 7) + +#define AO_USB_TYPE_STANDARD 0 +#define AO_USB_TYPE_CLASS (1 << 5) +#define AO_USB_TYPE_VENDOR (2 << 5) +#define AO_USB_TYPE_RESERVED (3 << 5) + +#define AO_USB_RECIP_DEVICE 0 +#define AO_USB_RECIP_INTERFACE 1 +#define AO_USB_RECIP_ENDPOINT 2 +#define AO_USB_RECIP_OTHER 3 + +/* standard requests */ +#define AO_USB_REQ_GET_STATUS 0x00 +#define AO_USB_REQ_CLEAR_FEATURE 0x01 +#define AO_USB_REQ_SET_FEATURE 0x03 +#define AO_USB_REQ_SET_ADDRESS 0x05 +#define AO_USB_REQ_GET_DESCRIPTOR 0x06 +#define AO_USB_REQ_SET_DESCRIPTOR 0x07 +#define AO_USB_REQ_GET_CONFIGURATION 0x08 +#define AO_USB_REQ_SET_CONFIGURATION 0x09 +#define AO_USB_REQ_GET_INTERFACE 0x0A +#define AO_USB_REQ_SET_INTERFACE 0x0B +#define AO_USB_REQ_SYNCH_FRAME 0x0C + +#define AO_USB_DESC_DEVICE 1 +#define AO_USB_DESC_CONFIGURATION 2 +#define AO_USB_DESC_STRING 3 +#define AO_USB_DESC_INTERFACE 4 +#define AO_USB_DESC_ENDPOINT 5 +#define AO_USB_DESC_DEVICE_QUALIFIER 6 +#define AO_USB_DESC_OTHER_SPEED 7 +#define AO_USB_DESC_INTERFACE_POWER 8 + +#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) +#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) + +#define AO_USB_CONTROL_EP 0 +#define AO_USB_CONTROL_SIZE 32 + +#define AO_USB_INT_EP 1 +#define AO_USB_INT_SIZE 8 + +#define AO_USB_OUT_EP 4 +#define AO_USB_IN_EP 5 +/* + * USB bulk packets can only come in 8, 16, 32 and 64 + * byte sizes, so we'll use 64 for everything + */ +#define AO_USB_IN_SIZE 64 +#define AO_USB_OUT_SIZE 64 + +#define AO_USB_EP0_IDLE 0 +#define AO_USB_EP0_DATA_IN 1 +#define AO_USB_EP0_DATA_OUT 2 + +#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) + +/* CDC definitions */ +#define AO_USB_CS_INTERFACE 0x24 +#define AO_USB_CS_ENDPOINT 0x25 + +#define AO_USB_SET_LINE_CODING 0x20 +#define AO_USB_GET_LINE_CODING 0x21 +#define AO_USB_SET_CONTROL_LINE_STATE 0x22 + +/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ +struct ao_usb_line_coding { + uint32_t rate; + uint8_t char_format; + uint8_t parity; + uint8_t data_bits; +} ; + +#endif /* _AO_USB_H_ */ diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c index 5eb78815..f193ac8e 100644 --- a/src/drivers/ao_btm.c +++ b/src/drivers/ao_btm.c @@ -17,6 +17,13 @@ #include "ao.h" +#ifndef ao_serial_btm_getchar +#define ao_serial_btm_putchar ao_serial1_putchar +#define ao_serial_btm_pollchar ao_serial1_pollchar +#define ao_serial_btm_set_speed ao_serial1_set_speed +#define ao_serial_btm_drain ao_serial1_drain +#endif + int8_t ao_btm_stdio; __xdata uint8_t ao_btm_connected; @@ -80,9 +87,9 @@ ao_btm_speed(void) { ao_cmd_decimal(); if (ao_cmd_lex_u32 == 57600) - ao_serial_set_speed(AO_SERIAL_SPEED_57600); + ao_serial_btm_set_speed(AO_SERIAL_SPEED_57600); else if (ao_cmd_lex_u32 == 19200) - ao_serial_set_speed(AO_SERIAL_SPEED_19200); + ao_serial_btm_set_speed(AO_SERIAL_SPEED_19200); else ao_cmd_status = ao_cmd_syntax_error; } @@ -104,8 +111,6 @@ __code struct ao_cmds ao_btm_cmds[] = { #define AO_BTM_MAX_REPLY 16 __xdata char ao_btm_reply[AO_BTM_MAX_REPLY]; -extern volatile __xdata struct ao_fifo ao_usart1_rx_fifo; - /* * Read a line of data from the serial port, truncating * it after a few characters. @@ -119,7 +124,7 @@ ao_btm_get_line(void) for (;;) { - while ((c = ao_serial_pollchar()) != AO_READ_AGAIN) { + while ((c = ao_serial_btm_pollchar()) != AO_READ_AGAIN) { ao_btm_log_in_char(c); if (ao_btm_reply_len < sizeof (ao_btm_reply)) ao_btm_reply[ao_btm_reply_len++] = c; @@ -128,7 +133,7 @@ ao_btm_get_line(void) } for (c = 0; c < 10; c++) { ao_delay(AO_MS_TO_TICKS(10)); - if (!ao_fifo_empty(ao_usart1_rx_fifo)) + if (!ao_fifo_empty(ao_serial1_rx_fifo)) break; } if (c == 10) @@ -168,7 +173,7 @@ void ao_btm_putchar(char c) { ao_btm_log_out_char(c); - ao_serial_putchar(c); + ao_serial_btm_putchar(c); ao_delay(1); } @@ -229,8 +234,8 @@ ao_btm_set_name(void) uint8_t ao_btm_try_speed(uint8_t speed) { - ao_serial_set_speed(speed); - ao_btm_drain(); + ao_serial_btm_set_speed(speed); + ao_serial_btm_drain(); (void) ao_btm_cmd("\rATE0\rATQ0\r"); if (ao_btm_cmd("AT\r") == 1) return 1; @@ -274,8 +279,8 @@ ao_btm(void) /* Turn off status reporting */ ao_btm_cmd("ATQ1\r"); - ao_btm_stdio = ao_add_stdio(ao_serial_pollchar, - ao_serial_putchar, + ao_btm_stdio = ao_add_stdio(ao_serial_btm_pollchar, + ao_serial_btm_putchar, NULL); ao_btm_echo(0); @@ -341,7 +346,8 @@ void ao_btm_init (void) { ao_serial_init(); - ao_serial_set_speed(AO_SERIAL_SPEED_19200); + + ao_serial_btm_set_speed(AO_SERIAL_SPEED_19200); #if BT_LINK_ON_P1 /* diff --git a/src/drivers/ao_gps_sirf.c b/src/drivers/ao_gps_sirf.c index f2abbf84..91fc948b 100644 --- a/src/drivers/ao_gps_sirf.c +++ b/src/drivers/ao_gps_sirf.c @@ -124,7 +124,13 @@ static __xdata struct sirf_measured_tracker_data ao_sirf_tracker_data; static __pdata uint16_t ao_sirf_cksum; static __pdata uint16_t ao_sirf_len; -#define ao_sirf_byte() ((uint8_t) ao_serial_getchar()) +#ifndef ao_sirf_getchar +#define ao_sirf_getchar ao_serial1_getchar +#define ao_sirf_putchar ao_serial1_putchar +#define ao_sirf_set_speed ao_serial1_set_speed +#endif + +#define ao_sirf_byte() ((uint8_t) ao_sirf_getchar()) static uint8_t data_byte(void) { @@ -283,15 +289,15 @@ static void ao_gps_setup(void) __reentrant { uint8_t i, k; - ao_serial_set_speed(AO_SERIAL_SPEED_4800); + ao_sirf_set_speed(AO_SERIAL_SPEED_4800); for (i = 0; i < 64; i++) - ao_serial_putchar(0x00); + ao_sirf_putchar(0x00); for (k = 0; k < 3; k++) for (i = 0; i < sizeof (ao_gps_set_nmea); i++) - ao_serial_putchar(ao_gps_set_nmea[i]); - ao_serial_set_speed(AO_SERIAL_SPEED_57600); + ao_sirf_putchar(ao_gps_set_nmea[i]); + ao_sirf_set_speed(AO_SERIAL_SPEED_57600); for (i = 0; i < 64; i++) - ao_serial_putchar(0x00); + ao_sirf_putchar(0x00); } static const char ao_gps_set_message_rate[] = { @@ -307,16 +313,16 @@ ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant uint8_t i; for (i = 0; i < sizeof (ao_gps_set_message_rate); i++) - ao_serial_putchar(ao_gps_set_message_rate[i]); - ao_serial_putchar(msg); - ao_serial_putchar(rate); + ao_sirf_putchar(ao_gps_set_message_rate[i]); + ao_sirf_putchar(msg); + ao_sirf_putchar(rate); cksum = 0xa6 + msg + rate; for (i = 0; i < 4; i++) - ao_serial_putchar(0); - ao_serial_putchar((cksum >> 8) & 0x7f); - ao_serial_putchar(cksum & 0xff); - ao_serial_putchar(0xb0); - ao_serial_putchar(0xb3); + ao_sirf_putchar(0); + ao_sirf_putchar((cksum >> 8) & 0x7f); + ao_sirf_putchar(cksum & 0xff); + ao_sirf_putchar(0xb0); + ao_sirf_putchar(0xb3); } static const uint8_t sirf_disable[] = { @@ -338,7 +344,7 @@ ao_gps(void) __reentrant for (k = 0; k < 5; k++) { for (i = 0; i < sizeof (ao_gps_config); i++) - ao_serial_putchar(ao_gps_config[i]); + ao_sirf_putchar(ao_gps_config[i]); for (i = 0; i < sizeof (sirf_disable); i++) ao_sirf_set_message_rate(sirf_disable[i], 0); ao_sirf_set_message_rate(41, 1); diff --git a/src/drivers/ao_gps_skytraq.c b/src/drivers/ao_gps_skytraq.c index 39e36cc8..84616a05 100644 --- a/src/drivers/ao_gps_skytraq.c +++ b/src/drivers/ao_gps_skytraq.c @@ -20,15 +20,15 @@ #endif #ifndef ao_gps_getchar -#define ao_gps_getchar ao_serial_getchar +#define ao_gps_getchar ao_serial1_getchar #endif #ifndef ao_gps_putchar -#define ao_gps_putchar ao_serial_putchar +#define ao_gps_putchar ao_serial1_putchar #endif #ifndef ao_gps_set_speed -#define ao_gps_set_speed ao_serial_set_speed +#define ao_gps_set_speed ao_serial1_set_speed #endif __xdata uint8_t ao_gps_mutex; diff --git a/src/drivers/ao_science_slave.c b/src/drivers/ao_science_slave.c index 1ebb1480..fa9db98b 100644 --- a/src/drivers/ao_science_slave.c +++ b/src/drivers/ao_science_slave.c @@ -17,6 +17,7 @@ #include "ao.h" #include "ao_product.h" +#include "ao_flight.h" struct ao_companion_command ao_companion_command; diff --git a/src/megametrum-v0.1/ao_pins.h b/src/megametrum-v0.1/ao_pins.h index e4e5def6..f761e5c3 100644 --- a/src/megametrum-v0.1/ao_pins.h +++ b/src/megametrum-v0.1/ao_pins.h @@ -61,6 +61,8 @@ #define ao_gps_putchar ao_serial3_putchar #define ao_gps_set_speed ao_serial3_set_speed +#define HAS_EEPROM 1 +#define USE_INTERNAL_FLASH 0 #define HAS_USB 1 #define HAS_BEEP 1 diff --git a/src/product/ao_telebt.c b/src/product/ao_telebt.c index 97c9d792..46c63418 100644 --- a/src/product/ao_telebt.c +++ b/src/product/ao_telebt.c @@ -17,7 +17,9 @@ #include "ao.h" +#if HAS_LOG __code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ +#endif void main(void) diff --git a/src/product/ao_terraui.c b/src/product/ao_terraui.c index 8875ff48..963c7be4 100644 --- a/src/product/ao_terraui.c +++ b/src/product/ao_terraui.c @@ -16,6 +16,7 @@ */ #include "ao.h" +#include #include static __xdata struct ao_telemetry_sensor ao_tel_sensor; diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index adb6eb94..62af86f7 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -181,8 +181,6 @@ void ao_lcd_font_init(void); void ao_lcd_font_string(char *s); -#define USE_SERIAL_STDIN (USE_SERIAL_1_STDIN + USE_SERIAL_2_STDIN + USE_SERIAL_3_STDIN) - char ao_serial1_getchar(void); diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index 3cebc094..406da9fb 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -249,7 +249,7 @@ ao_serial2_set_speed(uint8_t speed) struct ao_stm_usart ao_stm_usart3; -void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); } +void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_2_STDIN); } char ao_serial3_getchar(void) diff --git a/src/stm/ao_usb.h b/src/stm/ao_usb.h deleted file mode 100644 index d3129d34..00000000 --- a/src/stm/ao_usb.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef _AO_USB_H_ -#define _AO_USB_H_ - -#define AO_USB_SETUP_DIR_MASK (0x01 << 7) -#define AO_USB_SETUP_TYPE_MASK (0x03 << 5) -#define AO_USB_SETUP_RECIP_MASK (0x1f) - -#define AO_USB_DIR_OUT 0 -#define AO_USB_DIR_IN (1 << 7) - -#define AO_USB_TYPE_STANDARD 0 -#define AO_USB_TYPE_CLASS (1 << 5) -#define AO_USB_TYPE_VENDOR (2 << 5) -#define AO_USB_TYPE_RESERVED (3 << 5) - -#define AO_USB_RECIP_DEVICE 0 -#define AO_USB_RECIP_INTERFACE 1 -#define AO_USB_RECIP_ENDPOINT 2 -#define AO_USB_RECIP_OTHER 3 - -/* standard requests */ -#define AO_USB_REQ_GET_STATUS 0x00 -#define AO_USB_REQ_CLEAR_FEATURE 0x01 -#define AO_USB_REQ_SET_FEATURE 0x03 -#define AO_USB_REQ_SET_ADDRESS 0x05 -#define AO_USB_REQ_GET_DESCRIPTOR 0x06 -#define AO_USB_REQ_SET_DESCRIPTOR 0x07 -#define AO_USB_REQ_GET_CONFIGURATION 0x08 -#define AO_USB_REQ_SET_CONFIGURATION 0x09 -#define AO_USB_REQ_GET_INTERFACE 0x0A -#define AO_USB_REQ_SET_INTERFACE 0x0B -#define AO_USB_REQ_SYNCH_FRAME 0x0C - -#define AO_USB_DESC_DEVICE 1 -#define AO_USB_DESC_CONFIGURATION 2 -#define AO_USB_DESC_STRING 3 -#define AO_USB_DESC_INTERFACE 4 -#define AO_USB_DESC_ENDPOINT 5 -#define AO_USB_DESC_DEVICE_QUALIFIER 6 -#define AO_USB_DESC_OTHER_SPEED 7 -#define AO_USB_DESC_INTERFACE_POWER 8 - -#define AO_USB_GET_DESC_TYPE(x) (((x)>>8)&0xFF) -#define AO_USB_GET_DESC_INDEX(x) ((x)&0xFF) - -#define AO_USB_CONTROL_EP 0 -#define AO_USB_INT_EP 1 -#define AO_USB_OUT_EP 4 -#define AO_USB_IN_EP 5 -#define AO_USB_CONTROL_SIZE 32 -/* - * Double buffer IN and OUT EPs, so each - * gets half of the available space - * - * Ah, but USB bulk packets can only come in 8, 16, 32 and 64 - * byte sizes, so we'll use 64 for everything - */ -#define AO_USB_INT_SIZE 8 -#define AO_USB_IN_SIZE 64 -#define AO_USB_OUT_SIZE 64 - -#define AO_USB_EP0_IDLE 0 -#define AO_USB_EP0_DATA_IN 1 -#define AO_USB_EP0_DATA_OUT 2 - -#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8)) - -/* CDC definitions */ -#define CS_INTERFACE 0x24 -#define CS_ENDPOINT 0x25 - -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_CONTROL_LINE_STATE 0x22 - -/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ -struct ao_usb_line_coding { - uint32_t rate; - uint8_t char_format; - uint8_t parity; - uint8_t data_bits; -} ; - -#endif /* _AO_USB_H_ */ diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 5a447d43..586f1e33 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -717,17 +717,17 @@ ao_usb_ep0_setup(void) case AO_USB_TYPE_CLASS: debug ("Class setup packet\n"); switch (ao_usb_setup.request) { - case SET_LINE_CODING: + case AO_USB_SET_LINE_CODING: debug ("set line coding\n"); ao_usb_ep0_out_len = 7; ao_usb_ep0_out_data = (uint8_t *) &ao_usb_line_coding; break; - case GET_LINE_CODING: + case AO_USB_GET_LINE_CODING: debug ("get line coding\n"); ao_usb_ep0_in_len = 7; ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; break; - case SET_CONTROL_LINE_STATE: + case AO_USB_SET_CONTROL_LINE_STATE: break; } break; diff --git a/src/teleballoon-v1.1/ao_pins.h b/src/teleballoon-v1.1/ao_pins.h index a96c6f2b..3305719a 100644 --- a/src/teleballoon-v1.1/ao_pins.h +++ b/src/teleballoon-v1.1/ao_pins.h @@ -30,7 +30,6 @@ #define HAS_BEEP 1 #define HAS_GPS 1 #define HAS_SERIAL_1 1 - #define USE_SERIAL_STDIN 0 #define HAS_ADC 1 #define HAS_EEPROM 1 #define HAS_LOG 1 @@ -127,10 +126,6 @@ #error Please define HAS_SERIAL_1 #endif -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - #ifndef HAS_ADC #error Please define HAS_ADC #endif diff --git a/src/telepyro-v0.1/Makefile b/src/telepyro-v0.1/Makefile index 2f664fcb..2ac7e747 100644 --- a/src/telepyro-v0.1/Makefile +++ b/src/telepyro-v0.1/Makefile @@ -85,8 +85,10 @@ load: $(PROG).hex ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ -ao_product.rel: ao_product.c ao_product.h - $(call quiet,CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"ao_product.h\"' -o$@ $< +ao_product.o: ao_product.c ao_product.h + +%.o : %.c + $(call quiet,CC) -c $(CFLAGS) $< distclean: clean diff --git a/src/telescience-v0.1/Makefile b/src/telescience-v0.1/Makefile index be99f10d..10e4a2a3 100644 --- a/src/telescience-v0.1/Makefile +++ b/src/telescience-v0.1/Makefile @@ -22,7 +22,8 @@ INC = \ ao.h \ ao_arch.h \ ao_usb.h \ - ao_pins.h + ao_pins.h \ + ao_product.h # # Common AltOS sources @@ -96,8 +97,10 @@ load: $(PROG).hex ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ -ao_product.rel: ao_product.c ao_product.h - $(call quiet,CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"ao_product.h\"' -o$@ $< +ao_product.o: ao_product.c ao_product.h + +%.o : %.c $(INC) + $(call quiet,CC) -c $(CFLAGS) $< distclean: clean diff --git a/src/teleshield-v0.1/Makefile b/src/teleshield-v0.1/Makefile index 44780476..c1f45f37 100644 --- a/src/teleshield-v0.1/Makefile +++ b/src/teleshield-v0.1/Makefile @@ -54,7 +54,6 @@ CC1111_SRC = \ ao_radio.c \ ao_romconfig.c \ ao_serial.c \ - ao_serial0.c \ ao_string.c \ ao_timer.c \ ao_usb.c \ diff --git a/src/teleshield-v0.1/ao_ardu_serial.c b/src/teleshield-v0.1/ao_ardu_serial.c index 7ff859af..e6e19f67 100644 --- a/src/teleshield-v0.1/ao_ardu_serial.c +++ b/src/teleshield-v0.1/ao_ardu_serial.c @@ -23,7 +23,7 @@ ao_ardu_serial_recv(void) char c; for (;;) { - if (ao_fifo_empty(ao_usart0_rx_fifo)) + if (ao_fifo_empty(ao_serial0_rx_fifo)) flush(); c = ao_serial0_getchar(); putchar (c); @@ -35,6 +35,5 @@ static __xdata struct ao_task ao_ardu_serial_recv_task; void ao_ardu_serial_init (void) { - ao_serial0_init(); ao_add_task(&ao_ardu_serial_recv_task, ao_ardu_serial_recv, "recv"); } diff --git a/src/teleshield-v0.1/ao_pins.h b/src/teleshield-v0.1/ao_pins.h index a907e2a5..701e25fc 100644 --- a/src/teleshield-v0.1/ao_pins.h +++ b/src/teleshield-v0.1/ao_pins.h @@ -26,14 +26,14 @@ #define HAS_SERIAL_1_ALT_1 1 #define HAS_SERIAL_1_ALT_2 0 #define HAS_SERIAL_1_HW_FLOW 1 - #define USE_SERIAL_STDIN 1 + #define USE_SERIAL_1_STDIN 1 #define HAS_SERIAL_0 1 #define HAS_SERIAL_0_ALT_1 0 #define HAS_SERIAL_0_ALT_2 1 #define HAS_SERIAL_0_HW_FLOW 0 #define HAS_ADC 0 #define HAS_DBG 1 - #define HAS_EEPROM 0 + #define HAS_EEPROM 1 #define HAS_LOG 0 #define USE_INTERNAL_FLASH 1 #define HAS_BTM 1 @@ -128,10 +128,6 @@ #error Please define HAS_SERIAL_1 #endif -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - #ifndef HAS_ADC #error Please define HAS_ADC #endif diff --git a/src/teleshield-v0.1/ao_teleshield.c b/src/teleshield-v0.1/ao_teleshield.c index fd12ce7a..4c32817a 100644 --- a/src/teleshield-v0.1/ao_teleshield.c +++ b/src/teleshield-v0.1/ao_teleshield.c @@ -17,7 +17,9 @@ #include "ao.h" +#if 0 __code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ +#endif void main(void) @@ -43,6 +45,7 @@ main(void) ao_aes_init(); ao_radio_cmac_init(); #endif + ao_serial_init(); ao_ardu_serial_init(); ao_config_init(); ao_start_scheduler(); diff --git a/src/teleterra-v0.1/ao_pins.h b/src/teleterra-v0.1/ao_pins.h index 33de055e..ba7177af 100644 --- a/src/teleterra-v0.1/ao_pins.h +++ b/src/teleterra-v0.1/ao_pins.h @@ -25,7 +25,6 @@ #define HAS_GPS 0 #define HAS_SERIAL_1 0 #define HAS_ADC 0 - #define USE_SERIAL_STDIN 0 #define HAS_EEPROM 1 #define HAS_LOG 1 #define USE_INTERNAL_FLASH 0 @@ -124,10 +123,6 @@ #error Please define HAS_SERIAL_1 #endif -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - #ifndef HAS_ADC #error Please define HAS_ADC #endif diff --git a/src/teleterra-v0.2/ao_pins.h b/src/teleterra-v0.2/ao_pins.h index 29b97385..2bea4e04 100644 --- a/src/teleterra-v0.2/ao_pins.h +++ b/src/teleterra-v0.2/ao_pins.h @@ -25,7 +25,6 @@ #define HAS_GPS 1 #define HAS_SERIAL_1 1 #define HAS_ADC 0 - #define USE_SERIAL_STDIN 0 #define HAS_EEPROM 1 #define HAS_LOG 1 #define USE_INTERNAL_FLASH 0 @@ -139,10 +138,6 @@ #error Please define HAS_SERIAL_1 #endif -#ifndef USE_SERIAL_STDIN -#error Please define USE_SERIAL_STDIN -#endif - #ifndef HAS_ADC #error Please define HAS_ADC #endif diff --git a/src/test/ao_gps_test.c b/src/test/ao_gps_test.c index 93d7a9ab..4d4012df 100644 --- a/src/test/ao_gps_test.c +++ b/src/test/ao_gps_test.c @@ -317,7 +317,7 @@ static uint8_t sirf_in_message[4096]; static int sirf_in_len; char -ao_serial_getchar(void) +ao_serial1_getchar(void) { char c; uint8_t uc; @@ -351,7 +351,7 @@ ao_serial_getchar(void) void -ao_serial_putchar(char c) +ao_serial1_putchar(char c) { int i; uint8_t uc = (uint8_t) c; @@ -388,7 +388,7 @@ ao_serial_putchar(char c) #define AO_SERIAL_SPEED_57600 1 static void -ao_serial_set_speed(uint8_t speed) +ao_serial1_set_speed(uint8_t speed) { int fd = ao_gps_fd; struct termios termios; diff --git a/src/test/ao_gps_test_skytraq.c b/src/test/ao_gps_test_skytraq.c index a78fae0f..88bed305 100644 --- a/src/test/ao_gps_test_skytraq.c +++ b/src/test/ao_gps_test_skytraq.c @@ -319,7 +319,7 @@ static uint8_t skytraq_in_message[4096]; static int skytraq_in_len; char -ao_serial_getchar(void) +ao_serial1_getchar(void) { char c; uint8_t uc; @@ -354,7 +354,7 @@ ao_serial_getchar(void) void -ao_serial_putchar(char c) +ao_serial1_putchar(char c) { int i; uint8_t uc = (uint8_t) c; @@ -392,7 +392,7 @@ ao_serial_putchar(char c) #define AO_SERIAL_SPEED_57600 2 static void -ao_serial_set_speed(uint8_t speed) +ao_serial1_set_speed(uint8_t speed) { int fd = ao_gps_fd; struct termios termios; -- cgit v1.2.3 From 9a8fec1b6d8f3346f988882ffb03d7d0e45b3c81 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Apr 2012 12:00:32 -0700 Subject: altos: Clean up test scripts The flight test scripts were using invalid bash syntax. Clean that up and also switch the default flight directory to my new ~/misc/rockets/flights directory. Signed-off-by: Keith Packard --- src/test/run-one | 16 +++++++++++++--- src/test/run-tests | 10 +++++----- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'src/test') diff --git a/src/test/run-one b/src/test/run-one index 7d0f95ae..8fa0787c 100755 --- a/src/test/run-one +++ b/src/test/run-one @@ -1,10 +1,20 @@ #!/bin/sh +DIR=~/misc/rockets/flights + for i in "$@"; do -./ao_flight_test "$i" > run-out.full -./ao_flight_test_baro "$i" > run-out.baro +case "$i" in + */*) + file="$i" + ;; + *) + file="$DIR/$i" + ;; +esac +./ao_flight_test "$file" > run-out.full +./ao_flight_test_baro "$file" > run-out.baro -#./ao_flight_test_accel "$i" > run-out.accel +#./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",\ diff --git a/src/test/run-tests b/src/test/run-tests index 3e0cad3c..a8a8dc3f 100755 --- a/src/test/run-tests +++ b/src/test/run-tests @@ -1,6 +1,6 @@ -#!/bin/sh +#!/bin/bash -DIR=~/src/cc1111/flights +DIR=~/misc/rockets/flights bad_baro=0 bad_full=0 @@ -8,15 +8,15 @@ while read flight description; do if ./ao_flight_test_baro -s $DIR/$flight; then : else - ((bad_baro++)) + : $((bad_baro++)) fi if ./ao_flight_test -s $DIR/$flight; then : else - ((bad_full++)) + : $((bad_full++)) fi done < test-flights echo baro errors $bad_baro echo full errors $bad_full -((bad = bad_baro + bad_full)) +: $((bad = bad_baro + bad_full)) exit $bad \ No newline at end of file -- cgit v1.2.3 From 6cb744e305116a738b5d71686c6748f6f08c12ea Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Apr 2012 12:02:14 -0700 Subject: altos: Respect apogee lockout time in flight algorithm This prevents any apogee detection from occurring until the specified number of seconds after boost. This also prevents the switch from accel+baro to baro only mode in the Kalman filter. The test frame work is also changed to look for Apogee lockout: in the eeprom input file. Signed-off-by: Keith Packard --- src/core/ao_flight.c | 11 +++++++++++ src/test/ao_flight_test.c | 4 ++++ 2 files changed, 15 insertions(+) (limited to 'src/test') diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c index 5e194638..494e656d 100644 --- a/src/core/ao_flight.c +++ b/src/core/ao_flight.c @@ -223,6 +223,17 @@ ao_flight(void) #endif case ao_flight_coast: + /* + * By customer request - allow the user + * to lock out apogee detection for a specified + * number of seconds. + */ + if (ao_config.apogee_lockout) { + if ((ao_sample_tick - ao_boost_tick) < + AO_SEC_TO_TICKS(ao_config.apogee_lockout)) + break; + } + /* apogee detect: coast to drogue deploy: * * speed: < 0 diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 921d44e7..4a8625cf 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -184,6 +184,7 @@ struct ao_config { int16_t accel_plus_g; int16_t accel_minus_g; uint8_t pad_orientation; + uint16_t apogee_lockout; }; #define AO_PAD_ORIENTATION_ANTENNA_UP 0 @@ -523,6 +524,9 @@ ao_sleep(void *wchan) ao_config.accel_minus_g = atoi(words[5]); } else if (nword >= 4 && strcmp(words[0], "Main") == 0) { ao_config.main_deploy = atoi(words[2]); + } else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 && + strcmp(words[1], "lockout:") == 0) { + ao_config.apogee_lockout = atoi(words[2]); } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { tick = atoi(words[10]); if (!ao_flight_started) { -- cgit v1.2.3 From 5d8b9d524d6424ff98dcc4155fe8b8bd892b6d8f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 May 2012 20:04:57 -0700 Subject: altos: Add conversion between Pa and meters To be used with the MS5607 which generates data in calibrated units. Signed-off-by: Keith Packard --- src/Makefile | 6 +- src/core/ao.h | 12 ++ src/core/ao_convert_pa.c | 72 +++++++++++ src/core/ao_convert_pa_test.c | 76 ++++++++++++ src/test/Makefile | 5 +- src/util/make-altitude-pa | 275 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 src/core/ao_convert_pa.c create mode 100644 src/core/ao_convert_pa_test.c create mode 100644 src/util/make-altitude-pa (limited to 'src/test') diff --git a/src/Makefile b/src/Makefile index db9bd508..c2e324c4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,6 +4,7 @@ # vpath make-altitude util +vpath make-altitude-pa util vpath make-kalman util vpath kalman.5c kalman vpath kalman_filter.5c kalman @@ -45,11 +46,14 @@ uninstall: all-recursive: all-local -all-local: altitude.h ao_kalman.h +all-local: altitude.h altitude-pa.h ao_kalman.h altitude.h: make-altitude nickle $< > $@ +altitude-pa.h: make-altitude-pa + nickle $< > $@ + ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c bash $< kalman > $@ diff --git a/src/core/ao.h b/src/core/ao.h index 27b9c5c4..a2092cfe 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -282,6 +282,18 @@ ao_altitude_to_pres(int16_t alt) __reentrant; int16_t ao_temp_to_dC(int16_t temp) __reentrant; +/* + * ao_convert_pa.c + * + * Convert between pressure in Pa and altitude in meters + */ + +int32_t +ao_pa_to_altitude(int32_t pa); + +int32_t +ao_altitude_to_pa(int32_t alt); + #if HAS_DBG #include #endif diff --git a/src/core/ao_convert_pa.c b/src/core/ao_convert_pa.c new file mode 100644 index 00000000..0c93caea --- /dev/null +++ b/src/core/ao_convert_pa.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST) +#include "ao.h" +#endif + +static const int32_t altitude_table[] = { +#include "altitude-pa.h" +}; + +#define ALT_SCALE (1 << ALT_SHIFT) +#define ALT_MASK (ALT_SCALE - 1) + +int32_t +ao_pa_to_altitude(int32_t pa) +{ + int16_t o; + int16_t part; + int32_t low, high; + + if (pa < 0) + pa = 0; + if (pa > 120000) + pa = 120000; + o = pa >> ALT_SHIFT; + part = pa & ALT_MASK; + + low = (int32_t) altitude_table[o] * (ALT_SCALE - part); + high = (int32_t) altitude_table[o+1] * part + (ALT_SCALE >> 1); + return (low + high) >> ALT_SHIFT; +} + +int32_t +ao_altitude_to_pa(int32_t alt) +{ + int32_t span, sub_span; + uint16_t l, h, m; + int32_t pa; + + l = 0; + h = NALT - 1; + while ((h - l) != 1) { + m = (l + h) >> 1; + if (altitude_table[m] < alt) + h = m; + else + l = m; + } + span = altitude_table[l] - altitude_table[h]; + sub_span = altitude_table[l] - alt; + pa = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_SHIFT) + (span >> 1)) / span; + if (pa > 120000) + pa = 120000; + if (pa < 0) + pa = 0; + return pa; +} diff --git a/src/core/ao_convert_pa_test.c b/src/core/ao_convert_pa_test.c new file mode 100644 index 00000000..972a4d4c --- /dev/null +++ b/src/core/ao_convert_pa_test.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 +#define AO_CONVERT_TEST +#include "ao_host.h" +#include "ao_convert_pa.c" + +#define STEP_P 1 +#define STEP_A 1 + +static inline i_abs(int i) { return i < 0 ? -i : i; } + +main () +{ + int i; + int32_t p_to_a, p_to_a_to_p; + int32_t a_to_p, a_to_p_to_a; + int max_p_error = 0, max_p_error_p = -1; + int max_a_error = 0, max_a_error_a = -1; + int p_error; + int a_error; + int ret = 0; + + for (i = 0; i < 120000 + STEP_P; i += STEP_P) { + if (i > 120000) + i = 120000; + p_to_a = ao_pa_to_altitude(i); + p_to_a_to_p = ao_altitude_to_pa(p_to_a); + p_error = i_abs(p_to_a_to_p - i); + if (p_error > max_p_error) { + max_p_error = p_error; + max_p_error_p = i; + } +// printf ("pa %d alt %d pa %d\n", +// i, p_to_a, p_to_a_to_p); + } + for (i = -1450; i < 74250 + STEP_A; i += STEP_A) { + if (i > 74250) + i = 74250; + a_to_p = ao_altitude_to_pa(i); + a_to_p_to_a = ao_pa_to_altitude(a_to_p); + a_error = i_abs(a_to_p_to_a - i); + if (a_error > max_a_error) { + max_a_error = a_error; + max_a_error_a = i; + } +// printf ("alt %d pa %d alt %d\n", +// i, a_to_p, a_to_p_to_a); + } + if (max_p_error > 2) { + printf ("max p error %d at %d\n", max_p_error, + max_p_error_p); + ret++; + } + if (max_a_error > 1) { + printf ("max a error %d at %d\n", max_a_error, + max_a_error_a); + ret++; + } + return ret; +} diff --git a/src/test/Makefile b/src/test/Makefile index 4e403da6..3c2b8732 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,6 @@ vpath % ..:../core:../drivers:../util -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 +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 KALMAN=make-kalman @@ -34,5 +34,8 @@ ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_ho ao_convert_test: ao_convert_test.c ao_convert.c altitude.h cc $(CFLAGS) -o $@ $< +ao_convert_pa_test: ao_convert_pa_test.c ao_convert_pa.c altitude-pa.h + cc $(CFLAGS) -o $@ $< + ao_kalman.h: $(KALMAN) (cd .. && make ao_kalman.h) \ No newline at end of file diff --git a/src/util/make-altitude-pa b/src/util/make-altitude-pa new file mode 100644 index 00000000..190b36fc --- /dev/null +++ b/src/util/make-altitude-pa @@ -0,0 +1,275 @@ +#!/usr/bin/nickle -f +/* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * pow(base, exponent); + } + + return pressure; +} + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ +real pressure_to_altitude(real pressure) { + + real next_base_temperature = LAYER0_BASE_TEMPERATURE; + real next_base_pressure = LAYER0_BASE_PRESSURE; + + real altitude; + real base_pressure; + real base_temperature; + real base; /* base for function to determine base pressure of next layer */ + real exponent; /* exponent for function to determine base pressure + of next layer */ + real coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (pow(base, exponent) - 1); + } + + return altitude; +} + +real feet_to_meters(real feet) +{ + return feet * (12 * 2.54 / 100); +} + +real meters_to_feet(real meters) +{ + return meters / (12 * 2.54 / 100); +} + +/* + * Values for our MS5607 + * + * From the data sheet: + * + * Pressure range: 10-1200 mbar (1000 - 120000 Pa) + * + * Pressure data is reported in units of Pa + */ + +typedef struct { + real m, b; + int m_i, b_i; +} line_t; + +line_t best_fit(real[] values, int first, int last) { + real sum_x = 0, sum_x2 = 0, sum_y = 0, sum_xy = 0; + int n = last - first + 1; + real m, b; + int m_i, b_i; + + for (int i = first; i <= last; i++) { + sum_x += i; + sum_x2 += i**2; + sum_y += values[i]; + sum_xy += values[i] * i; + } + m = (n*sum_xy - sum_y*sum_x) / (n*sum_x2 - sum_x**2); + b = sum_y/n - m*(sum_x/n); + return (line_t) { m = m, b = b }; +} + +real min_Pa = 0; +real max_Pa = 120000; + +/* Target is an array of < 2000 entries */ +int pa_sample_shift = 3; +int pa_part_shift = 3; + +int num_part = ceil(max_Pa / (2 ** (pa_part_shift + pa_sample_shift))); + +int num_samples = num_part << pa_part_shift; + +real sample_to_Pa(int sample) = sample << pa_sample_shift; + +real sample_to_altitude(int sample) = pressure_to_altitude(sample_to_Pa(sample)); + +int part_to_sample(int part) = part << pa_part_shift; + +real[num_samples] alt = { [n] = sample_to_altitude(n) }; + +int seg_len = 1 << pa_part_shift; + +line_t [num_part] fit = { + [n] = best_fit(alt, n * seg_len, n * seg_len + seg_len - 1) +}; + +int[num_samples/seg_len + 1] alt_part; + +alt_part[0] = floor (fit[0].b + 0.5); +alt_part[dim(fit)] = floor(fit[dim(fit)-1].m * dim(fit) * seg_len + fit[dim(fit)-1].b + 0.5); + +for (int i = 0; i < dim(fit) - 1; i++) { + real here, there; + here = fit[i].m * (i+1) * seg_len + fit[i].b; + there = fit[i+1].m * (i+1) * seg_len + fit[i+1].b; + alt_part[i+1] = floor ((here + there) / 2 + 0.5); +} + +real sample_to_fit_altitude(int sample) { + int sub = sample // seg_len; + int off = sample % seg_len; + line_t l = fit[sub]; + real r_v; + real i_v; + + r_v = sample * l.m + l.b; + i_v = (alt_part[sub] * (seg_len - off) + alt_part[sub+1] * off) / seg_len; + return i_v; +} + +real max_error = 0; +int max_error_sample = 0; +real total_error = 0; + +for (int sample = 0; sample < num_samples; sample++) { + real Pa = sample_to_Pa(sample); + real meters = pressure_to_altitude(Pa); + + real meters_approx = sample_to_fit_altitude(sample); + real error = abs(meters - meters_approx); + + total_error += error; + if (error > max_error) { + max_error = error; + max_error_sample = sample; + } +# printf (" %7d, /* %6.2f kPa %5d sample approx %d */\n", +# floor (meters + 0.5), Pa / 1000, sample, floor(sample_to_fit_altitude(sample) + 0.5)); +} + +printf ("/*max error %f at %7.3f%%. Average error %f*/\n", max_error, max_error_sample / (num_samples - 1) * 100, total_error / num_samples); + +printf ("#define NALT %d\n", dim(alt_part)); +printf ("#define ALT_SHIFT %d\n", pa_part_shift + pa_sample_shift); + +for (int part = 0; part < dim(alt_part); part++) { + real kPa = sample_to_Pa(part_to_sample(part)) / 1000; + printf ("%9d, /* %6.2f kPa */\n", + alt_part[part], kPa); +} -- cgit v1.2.3 From 29edf6d901432a1afc65900ff599c963edac5a2b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 27 May 2012 17:44:01 -0600 Subject: altos: Make telescience-v0.1 build with new ao_data struct Signed-off-by: Keith Packard --- src/avr/ao_adc_avr.c | 24 ++++++++--------- src/avr/ao_pins.h | 3 +-- src/core/ao_log_telescience.c | 14 +++++----- src/core/ao_stdio.c | 16 ++++++------ src/drivers/ao_science_slave.c | 2 +- src/test/Makefile | 4 +-- src/test/ao_flight_test.c | 58 ++++++++++++++++++++++-------------------- 7 files changed, 61 insertions(+), 60 deletions(-) (limited to 'src/test') diff --git a/src/avr/ao_adc_avr.c b/src/avr/ao_adc_avr.c index 4f6f0e60..928cd3e1 100644 --- a/src/avr/ao_adc_avr.c +++ b/src/avr/ao_adc_avr.c @@ -17,8 +17,8 @@ #include "ao.h" -volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; -volatile __data uint8_t ao_adc_head; +volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING]; +volatile __data uint8_t ao_data_head; #ifdef TELESCIENCE const uint8_t adc_channels[AO_LOG_TELESCIENCE_NUM_ADC] = { @@ -92,14 +92,14 @@ ISR(ADC_vect) /* Must read ADCL first or the value there will be lost */ value = ADCL; value |= (ADCH << 8); - ao_adc_ring[ao_adc_head].adc[ao_adc_channel] = value; + ao_data_ring[ao_data_head].adc.adc[ao_adc_channel] = value; if (++ao_adc_channel < NUM_ADC) ao_adc_start(); else { ADCSRA = ADCSRA_INIT; - ao_adc_ring[ao_adc_head].tick = ao_time(); - ao_adc_head = ao_adc_ring_next(ao_adc_head); - ao_wakeup((void *) &ao_adc_head); + ao_data_ring[ao_data_head].tick = ao_time(); + ao_data_head = ao_data_ring_next(ao_data_head); + ao_wakeup((void *) &ao_data_head); ao_cpu_sleep_disable = 0; } } @@ -113,18 +113,18 @@ ao_adc_poll(void) } void -ao_adc_get(__xdata struct ao_adc *packet) +ao_data_get(__xdata struct ao_data *packet) { - uint8_t i = ao_adc_ring_prev(ao_adc_head); - memcpy(packet, (void *) &ao_adc_ring[i], sizeof (struct ao_adc)); + uint8_t i = ao_data_ring_prev(ao_data_head); + memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data)); } static void ao_adc_dump(void) __reentrant { - static __xdata struct ao_adc packet; + static __xdata struct ao_data packet; uint8_t i; - ao_adc_get(&packet); + ao_data_get(&packet); #ifdef TELEPYRO printf("ADMUX: %02x\n", ADMUX); printf("ADCSRA: %02x\n", ADCSRA); @@ -137,7 +137,7 @@ ao_adc_dump(void) __reentrant #endif printf("tick: %5u", packet.tick); for (i = 0; i < NUM_ADC; i++) - printf (" %2d: %5u", i, packet.adc[i]); + printf (" %2d: %5u", i, packet.adc.adc[i]); printf("\n"); diff --git a/src/avr/ao_pins.h b/src/avr/ao_pins.h index f2b40fb4..850a08ec 100644 --- a/src/avr/ao_pins.h +++ b/src/avr/ao_pins.h @@ -91,10 +91,9 @@ #define AO_TELESCIENCE_NUM_ADC 12 struct ao_adc { - uint16_t tick; /* tick when the sample was read */ uint16_t adc[AO_TELESCIENCE_NUM_ADC]; /* samples */ }; -#define AO_ADC_RING 16 +#define AO_DATA_RING 16 #endif /* _AO_PINS_H_ */ diff --git a/src/core/ao_log_telescience.c b/src/core/ao_log_telescience.c index ae045281..002a10bd 100644 --- a/src/core/ao_log_telescience.c +++ b/src/core/ao_log_telescience.c @@ -20,7 +20,7 @@ #include "ao_log.h" #include "ao_companion.h" -static uint8_t ao_log_adc_pos; +static uint8_t ao_log_data_pos; __code uint8_t ao_log_format = AO_LOG_FORMAT_TELESCIENCE; @@ -62,20 +62,20 @@ ao_log_single(void) /* Write the whole contents of the ring to the log * when starting up. */ - ao_log_adc_pos = ao_adc_ring_next(ao_adc_head); + ao_log_data_pos = ao_data_ring_next(ao_data_head); ao_log_single_write_data.telescience.type = AO_LOG_TELESCIENCE_DATA; while (ao_log_running) { /* Write samples to EEPROM */ - while (ao_log_adc_pos != ao_adc_head) { - ao_log_single_write_data.telescience.tick = ao_adc_ring[ao_log_adc_pos].tick; - memcpy(&ao_log_single_write_data.telescience.adc, (void *) ao_adc_ring[ao_log_adc_pos].adc, + while (ao_log_data_pos != ao_data_head) { + ao_log_single_write_data.telescience.tick = ao_data_ring[ao_log_data_pos].tick; + memcpy(&ao_log_single_write_data.telescience.adc, (void *) ao_data_ring[ao_log_data_pos].adc.adc, AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t)); ao_log_telescience_csum(); ao_log_single_write(); - ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos); + ao_log_data_pos = ao_data_ring_next(ao_log_data_pos); } /* Wait for more ADC data to arrive */ - ao_sleep((void *) &ao_adc_head); + ao_sleep((void *) &ao_data_head); } memset(&ao_log_single_write_data.telescience.adc, '\0', sizeof (ao_log_single_write_data.telescience.adc)); } diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c index 9b4ea473..656b23c9 100644 --- a/src/core/ao_stdio.c +++ b/src/core/ao_stdio.c @@ -53,14 +53,14 @@ #endif #define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN + \ - USE_SERIAL_1_STDIN | \ - USE_SERIAL_2_STDIN | \ - USE_SERIAL_3_STDIN | \ - USE_SERIAL_4_STDIN | \ - USE_SERIAL_5_STDIN | \ - USE_SERIAL_6_STDIN | \ - USE_SERIAL_7_STDIN | \ - USE_SERIAL_8_STDIN | \ + USE_SERIAL_1_STDIN + \ + USE_SERIAL_2_STDIN + \ + USE_SERIAL_3_STDIN + \ + USE_SERIAL_4_STDIN + \ + USE_SERIAL_5_STDIN + \ + USE_SERIAL_6_STDIN + \ + USE_SERIAL_7_STDIN + \ + USE_SERIAL_8_STDIN + \ USE_SERIAL_9_STDIN) #define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) diff --git a/src/drivers/ao_science_slave.c b/src/drivers/ao_science_slave.c index a86b5151..996e98d9 100644 --- a/src/drivers/ao_science_slave.c +++ b/src/drivers/ao_science_slave.c @@ -42,7 +42,7 @@ void ao_spi_slave(void) sizeof (ao_telescience_setup)); break; case AO_COMPANION_FETCH: - ao_spi_slave_send((uint8_t *) &ao_adc_ring[ao_adc_ring_prev(ao_adc_head)].adc, + ao_spi_slave_send((uint8_t *) &ao_data_ring[ao_data_ring_prev(ao_data_head)].adc, AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t)); break; case AO_COMPANION_NOTIFY: diff --git a/src/test/Makefile b/src/test/Makefile index 3c2b8732..1e54f5e0 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -13,10 +13,10 @@ clean: 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_mm.c ao_sample_mm.c ao_kalman.c altitude.h ao_kalman.h 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_mm.c ao_sample_mm.c ao_kalman.c altitude.h ao_kalman.h 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 diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 4a8625cf..baf2ad1d 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -26,9 +26,10 @@ #define AO_HERTZ 100 -#define AO_ADC_RING 64 -#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1)) -#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1)) +#define HAS_ADC 1 +#define AO_DATA_RING 64 +#define ao_data_ring_next(n) (((n) + 1) & (AO_DATA_RING - 1)) +#define ao_data_ring_prev(n) (((n) - 1) & (AO_DATA_RING - 1)) #define AO_M_TO_HEIGHT(m) ((int16_t) (m)) #define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16)) @@ -38,7 +39,6 @@ * One set of samples read from the A/D converter */ struct ao_adc { - uint16_t tick; /* tick when the sample was read */ int16_t accel; /* accelerometer */ int16_t pres; /* pressure sensor */ int16_t pres_real; /* unclipped */ @@ -54,6 +54,8 @@ struct ao_adc { #define __code #define __reentrant +#include + #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) #define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5)) #define from_fix(x) ((x) >> 16) @@ -90,8 +92,8 @@ extern enum ao_flight_state ao_flight_state; #define FALSE 0 #define TRUE 1 -struct ao_adc ao_adc_ring[AO_ADC_RING]; -uint8_t ao_adc_head; +volatile struct ao_data ao_data_ring[AO_DATA_RING]; +volatile uint8_t ao_data_head; int ao_summary = 0; #define ao_led_on(l) @@ -110,7 +112,7 @@ enum ao_igniter { ao_igniter_main = 1 }; -struct ao_adc ao_adc_static; +struct ao_data ao_data_static; int drogue_height; double drogue_time; @@ -124,7 +126,7 @@ static int32_t ao_k_height; void ao_ignite(enum ao_igniter igniter) { - double time = (double) (ao_adc_static.tick + tick_offset) / 100; + double time = (double) (ao_data_static.tick + tick_offset) / 100; if (igniter == ao_igniter_drogue) { drogue_time = time; @@ -221,8 +223,8 @@ int ao_sample_prev_tick; uint16_t prev_tick; #include "ao_kalman.c" -#include "ao_sample.c" -#include "ao_flight.c" +#include "ao_sample_mm.c" +#include "ao_flight_mm.c" #define to_double(f) ((f) / 65536.0) @@ -282,19 +284,19 @@ ao_insert(void) { double time; - ao_adc_ring[ao_adc_head] = ao_adc_static; - ao_adc_head = ao_adc_ring_next(ao_adc_head); + 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_adc_static.pres_real) - ao_ground_height; - double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) / + 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) / (ao_config.accel_minus_g - ao_config.accel_plus_g); if (!tick_offset) - tick_offset = -ao_adc_static.tick; - if ((prev_tick - ao_adc_static.tick) > 0x400) + tick_offset = -ao_data_static.tick; + if ((prev_tick - ao_data_static.tick) > 0x400) tick_offset += 65536; - prev_tick = ao_adc_static.tick; - time = (double) (ao_adc_static.tick + tick_offset) / 100; + prev_tick = ao_data_static.tick; + time = (double) (ao_data_static.tick + tick_offset) / 100; if (ao_test_max_height < height) { ao_test_max_height = height; @@ -474,7 +476,7 @@ int16(uint8_t *bytes, int off) void ao_sleep(void *wchan) { - if (wchan == &ao_adc_head) { + if (wchan == &ao_data_head) { char type; uint16_t tick; uint16_t a, b; @@ -490,7 +492,7 @@ ao_sleep(void *wchan) for (;;) { if (ao_records_read > 2 && ao_flight_state == ao_flight_startup) { - ao_adc_static.accel = ao_flight_ground_accel; + ao_data_static.adc.accel = ao_flight_ground_accel; ao_insert(); return; } @@ -501,7 +503,7 @@ ao_sleep(void *wchan) printf ("no more data, exiting simulation\n"); ao_test_exit(); } - ao_adc_static.tick += 10; + ao_data_static.tick += 10; ao_insert(); return; } @@ -639,19 +641,19 @@ ao_sleep(void *wchan) case 'S': break; case 'A': - ao_adc_static.tick = tick; - ao_adc_static.accel = a; - ao_adc_static.pres_real = b; + ao_data_static.tick = tick; + ao_data_static.adc.accel = a; + ao_data_static.adc.pres_real = b; if (b < AO_MIN_BARO_VALUE) b = AO_MIN_BARO_VALUE; - ao_adc_static.pres = b; + ao_data_static.adc.pres = b; ao_records_read++; ao_insert(); return; case 'T': - ao_adc_static.tick = tick; - ao_adc_static.temp = a; - ao_adc_static.v_batt = b; + ao_data_static.tick = tick; + ao_data_static.adc.temp = a; + ao_data_static.adc.v_batt = b; break; case 'D': case 'G': -- cgit v1.2.3 From e6d236fdc615625fbbf28377453f920729e49b0f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 16:17:00 -0700 Subject: altos: Software implemenation of CC1111 radio encoding Add CRC, whitening, FEC and interleaving routines for transmission path to allow cc1120 to send telem packets to cc1111. Signed-off-by: Keith Packard --- src/.gitignore | 1 + src/Makefile | 6 +- src/drivers/ao_cc1120.c | 87 ++++++++++++++++++-------- src/drivers/ao_cc1120_CC1120.h | 28 ++++----- src/drivers/ao_fec.h | 60 ++++++++++++++++++ src/drivers/ao_fec_tx.c | 139 +++++++++++++++++++++++++++++++++++++++++ src/megametrum-v0.1/Makefile | 3 + src/test/Makefile | 7 ++- src/test/ao_fec_tx_test.c | 47 ++++++++++++++ src/util/make-whiten | 37 +++++++++++ 10 files changed, 372 insertions(+), 43 deletions(-) create mode 100644 src/drivers/ao_fec.h create mode 100644 src/drivers/ao_fec_tx.c create mode 100644 src/test/ao_fec_tx_test.c create mode 100644 src/util/make-whiten (limited to 'src/test') diff --git a/src/.gitignore b/src/.gitignore index c6e1e353..cae36ae6 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,2 +1,3 @@ altitude.h altitude-pa.h +ao_whiten.h diff --git a/src/Makefile b/src/Makefile index c2e324c4..3fca2ab2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,6 +6,7 @@ vpath make-altitude util vpath make-altitude-pa util vpath make-kalman util +vpath make-whiten util vpath kalman.5c kalman vpath kalman_filter.5c kalman vpath load_csv.5c kalman @@ -46,7 +47,7 @@ uninstall: all-recursive: all-local -all-local: altitude.h altitude-pa.h ao_kalman.h +all-local: altitude.h altitude-pa.h ao_kalman.h ao_whiten.h altitude.h: make-altitude nickle $< > $@ @@ -57,5 +58,8 @@ altitude-pa.h: make-altitude-pa ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c bash $< kalman > $@ +ao_whiten.h: make-whiten + nickle $< > $@ + clean-local: rm -f altitude.h ao_kalman.h diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index f06d52ca..231d14d4 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -18,6 +18,7 @@ #include #include #include +#include uint8_t ao_radio_wake; uint8_t ao_radio_mutex; @@ -240,26 +241,27 @@ ao_radio_rx_done(void) return ao_radio_marc_status() == CC1120_MARC_STATUS1_RX_FINISHED; } +static void +ao_radio_start_tx(void) +{ + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); + ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_strobe(CC1120_STX); +} + void ao_radio_rdf(uint8_t len) { int i; ao_radio_get(len); - ao_radio_abort = 0; ao_radio_wake = 0; for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]); - ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); - ao_radio_fifo_write_fixed(ao_radio_rdf_value, len); - ao_radio_reg_write(CC1120_PKT_LEN, len); - - ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); - - ao_radio_strobe(CC1120_STX); + ao_radio_start_tx(); cli(); while (!ao_radio_wake && !ao_radio_abort) @@ -327,24 +329,45 @@ ao_radio_test(void) void ao_radio_send(void *d, uint8_t size) { - uint8_t marc_status; - + uint8_t marc_status; + static uint8_t prepare[128]; + uint8_t prepare_len; + static uint8_t encode[256]; + uint8_t encode_len; + static uint8_t interleave[256]; + uint8_t interleave_len; + + ao_fec_dump_bytes(d, size, "Input"); + +#if 1 + prepare_len = ao_fec_prepare(d, size, prepare); + ao_fec_dump_bytes(prepare, prepare_len, "Prepare"); + + ao_fec_whiten(prepare, prepare_len, prepare); + ao_fec_dump_bytes(prepare, prepare_len, "Whiten"); + + encode_len = ao_fec_encode(prepare, prepare_len, encode); + ao_fec_dump_bytes(encode, encode_len, "Encode"); + + interleave_len = ao_fec_interleave(encode, encode_len, interleave); + ao_fec_dump_bytes(interleave, interleave_len, "Interleave"); + ao_radio_get(interleave_len); + ao_radio_fifo_write(interleave, interleave_len); +#else ao_radio_get(size); - ao_radio_wake = 0; ao_radio_fifo_write(d, size); - ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); - ao_radio_strobe(CC1120_STX); +#endif + + ao_radio_wake = 0; + + ao_radio_start_tx(); + cli(); - for (;;) { - if (ao_radio_wake) { - marc_status = ao_radio_marc_status(); - if (marc_status != CC1120_MARC_STATUS1_NO_FAILURE) - break; - ao_radio_wake = 0; - } + while (!ao_radio_wake && !ao_radio_abort) ao_sleep(&ao_radio_wake); - } sei(); + if (!ao_radio_tx_done()) + ao_radio_idle(); ao_radio_put(); } @@ -361,6 +384,7 @@ ao_radio_recv(__xdata void *d, uint8_t size) cli(); for (;;) { if (ao_radio_abort) + break; if (ao_radio_wake) { marc_status = ao_radio_marc_status(); @@ -413,7 +437,7 @@ static const uint16_t packet_setup[] = { CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff), CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)), - CC1120_PKT_CFG1, ((1 << CC1120_PKT_CFG1_WHITE_DATA) | + CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) | (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) | (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) | (1 << CC1120_PKT_CFG1_APPEND_STATUS)), @@ -469,9 +493,6 @@ ao_radio_setup(void) for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) ao_radio_reg_write(radio_setup[i], radio_setup[i+1]); - /* Enable marc status interrupt on gpio 2 pin */ - ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP); - ao_radio_set_packet(); ao_config_get(); @@ -707,6 +728,21 @@ static void ao_radio_beep(void) { ao_radio_rdf(RDF_PACKET_LEN); } +static void ao_radio_packet(void) { + static uint8_t packet[] = { +#if 1 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +#else + 3, 1, 2, 3 +#endif + }; + + ao_radio_send(packet, sizeof (packet)); +} + #endif static const struct ao_cmds ao_radio_cmds[] = { @@ -714,6 +750,7 @@ static const struct ao_cmds ao_radio_cmds[] = { #if CC1120_DEBUG { ao_radio_show, "R\0Show CC1120 status" }, { ao_radio_beep, "b\0Emit an RDF beacon" }, + { ao_radio_packet, "p\0Send a test packet" }, #endif { 0, NULL } }; diff --git a/src/drivers/ao_cc1120_CC1120.h b/src/drivers/ao_cc1120_CC1120.h index c900b7f9..c0f35a23 100644 --- a/src/drivers/ao_cc1120_CC1120.h +++ b/src/drivers/ao_cc1120_CC1120.h @@ -21,29 +21,27 @@ * ***************************************************************/ - CC1120_SYNC3, 0x93, /* Sync Word Configuration [31:24] */ - CC1120_SYNC2, 0x0b, /* Sync Word Configuration [23:16] */ - CC1120_SYNC1, 0x51, /* Sync Word Configuration [15:8] */ - CC1120_SYNC0, 0xde, /* Sync Word Configuration [7:0] */ + CC1120_SYNC3, 0xD3, /* Sync Word Configuration [31:24] */ + CC1120_SYNC2, 0x91, /* Sync Word Configuration [23:16] */ + CC1120_SYNC1, 0xD3, /* Sync Word Configuration [15:8] */ + CC1120_SYNC0, 0x91, /* Sync Word Configuration [7:0] */ + CC1120_SYNC_CFG1, 0x08, /* Sync Word Detection Configuration */ - CC1120_SYNC_CFG0, 0x17, /* Sync Word Length Configuration */ -#if 0 - CC1120_DEVIATION_M, 0x50, /* Frequency Deviation Configuration */ - CC1120_MODCFG_DEV_E, 0x0d, /* Modulation Format and Frequency Deviation Configuration */ -#endif + CC1120_SYNC_CFG0, + (CC1120_SYNC_CFG0_SYNC_MODE_16_BITS << CC1120_SYNC_CFG0_SYNC_MODE) | + (CC1120_SYNC_CFG0_SYNC_NUM_ERROR_2 << CC1120_SYNC_CFG0_SYNC_NUM_ERROR), CC1120_DCFILT_CFG, 0x1c, /* Digital DC Removal Configuration */ - CC1120_PREAMBLE_CFG1, 0x18, /* Preamble Length Configuration */ + CC1120_PREAMBLE_CFG1, /* Preamble Length Configuration */ + (CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) | + (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD), CC1120_PREAMBLE_CFG0, 0x2a, /* */ CC1120_FREQ_IF_CFG, 0x40, /* RX Mixer Frequency Configuration */ CC1120_IQIC, 0x46, /* Digital Image Channel Compensation Configuration */ CC1120_CHAN_BW, 0x02, /* Channel Filter Configuration */ + CC1120_MDMCFG1, 0x46, /* General Modem Parameter Configuration */ CC1120_MDMCFG0, 0x05, /* General Modem Parameter Configuration */ -#if 0 - CC1120_DRATE2, 0x93, /* Data Rate Configuration Exponent and Mantissa [19:16] */ - CC1120_DRATE1, 0xa4, /* Data Rate Configuration Mantissa [15:8] */ - CC1120_DRATE0, 0x00, /* Data Rate Configuration Mantissa [7:0] */ -#endif + CC1120_AGC_REF, 0x20, /* AGC Reference Level Configuration */ CC1120_AGC_CS_THR, 0x19, /* Carrier Sense Threshold Configuration */ CC1120_AGC_GAIN_ADJUST, 0x00, /* RSSI Offset Configuration */ diff --git a/src/drivers/ao_fec.h b/src/drivers/ao_fec.h new file mode 100644 index 00000000..db5523a3 --- /dev/null +++ b/src/drivers/ao_fec.h @@ -0,0 +1,60 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +#ifndef _AO_FEC_H_ +#define _AO_FEC_H_ + +#include + +#define AO_FEC_CRC_INIT 0xffff +#define AO_FEC_TRELLIS_TERMINATOR 0x0b +#define AO_FEC_PREPARE_EXTRA 4 + +void +ao_fec_dump_bytes(uint8_t *bytes, uint8_t len, char *name); + +uint16_t +ao_fec_crc(uint8_t *bytes, uint8_t len); + +/* + * Append CRC and terminator bytes, returns resulting length. + * 'out' must be at least len + AO_FEC_PREPARE_EXTRA bytes long + */ +uint8_t +ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *out); + +/* + * Whiten data using the cc1111 PN9 sequence. 'out' + * must be 'len' bytes long. 'out' and 'in' can be + * the same array + */ +uint8_t +ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out); + +/* + * Encode data. 'out' must be len*2 bytes long + */ +uint8_t +ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out); + +/* + * Interleave data. 'out' must be 'len' bytes long + */ +uint8_t +ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out); + +#endif /* _AO_FEC_H_ */ diff --git a/src/drivers/ao_fec_tx.c b/src/drivers/ao_fec_tx.c new file mode 100644 index 00000000..b8933956 --- /dev/null +++ b/src/drivers/ao_fec_tx.c @@ -0,0 +1,139 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 +#include + +void +ao_fec_dump_bytes(uint8_t *bytes, uint8_t len, char *name) +{ + uint8_t i; + + printf ("%s (%d):", name, len); + for (i = 0; i < len; i++) { + if ((i & 7) == 0) + printf ("\n\t%02x:", i); + printf(" %02x", bytes[i]); + } + printf ("\n"); +} + +static uint16_t inline +crc_byte(uint8_t byte, uint16_t crc) +{ + uint8_t bit; + + for (bit = 0; bit < 8; bit++) { + if (((crc & 0x8000) >> 8) ^ (byte & 0x80)) + crc = (crc << 1) ^ 0x8005; + else + crc = (crc << 1); + byte <<= 1; + } + return crc; +} + +uint16_t +ao_fec_crc(uint8_t *bytes, uint8_t len) +{ + uint16_t crc = AO_FEC_CRC_INIT; + + while (len--) + crc = crc_byte(*bytes++, crc); + return crc; +} + +uint8_t +ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *out) +{ + uint16_t crc = ao_fec_crc (in, len); + uint8_t i; + uint8_t num_fec; + + /* Copy data */ + for (i = 0; i < len; i++) + out[i] = in[i]; + + /* Append CRC */ + out[i++] = crc >> 8; + out[i++] = crc; + + /* Append FEC -- 1 byte if odd, two bytes if even */ + num_fec = 2 - (i & 1); + while (num_fec--) + out[i++] = AO_FEC_TRELLIS_TERMINATOR; + return i; +} + +static const uint8_t whiten[] = { +#include "ao_whiten.h" +}; + +uint8_t +ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out) +{ + const uint8_t *w = whiten; + + while (len--) + *out++ = *in++ ^ *w++; +} + +static const uint8_t ao_fec_encode_table[16] = { + 0, 3, 1, 2, + 3, 0, 2, 1, + 3, 0, 2, 1, + 0, 3, 1, 2 +}; + +uint8_t +ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out) +{ + uint16_t fec = 0, output; + uint8_t byte, bit; + + for (byte = 0; byte < len; byte++) { + fec = (fec & 0x700) | in[byte]; + output = 0; + for (bit = 0; bit < 8; bit++) { + output = output << 2 | ao_fec_encode_table[fec >> 7]; + fec = (fec << 1) & 0x7ff; + } + out[byte * 2] = output >> 8; + out[byte * 2 + 1] = output; + } + return len * 2; +} + +uint8_t +ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out) +{ + uint8_t i, j; + + for (i = 0; i < len; i += 4) { + uint32_t interleaved = 0; + + for (j = 0; j < 4 * 4; j++) { + interleaved <<= 2; + interleaved |= (in[i + (~j & 0x3)] >> (2 * ((j & 0xc) >> 2))) & 0x03; + } + out[i+0] = interleaved >> 24; + out[i+1] = interleaved >> 16; + out[i+2] = interleaved >> 8; + out[i+3] = interleaved; + } + return len; +} diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index 5761fed7..054855ba 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -18,6 +18,8 @@ INC = \ ao_ms5607.h \ ao_hmc5883.h \ ao_mpu6000.h \ + ao_cc1120_CC1120.h \ + ao_whiten.h \ stm32l.h # @@ -45,6 +47,7 @@ ALTOS_SRC = \ ao_dma_stm.c \ ao_spi_stm.c \ ao_cc1120.c \ + ao_fec_tx.c \ ao_ms5607.c \ ao_adc_stm.c \ ao_beep_stm.c \ diff --git a/src/test/Makefile b/src/test/Makefile index 1e54f5e0..3e308dd7 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,6 @@ vpath % ..:../core:../drivers:../util -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 +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_tx_test KALMAN=make-kalman @@ -38,4 +38,7 @@ ao_convert_pa_test: ao_convert_pa_test.c ao_convert_pa.c altitude-pa.h cc $(CFLAGS) -o $@ $< ao_kalman.h: $(KALMAN) - (cd .. && make ao_kalman.h) \ No newline at end of file + (cd .. && make ao_kalman.h) + +ao_fec_tx_test: ao_fec_tx_test.c ao_fec_tx.c + cc $(CFLAGS) -o $@ ao_fec_tx_test.c ../drivers/ao_fec_tx.c diff --git a/src/test/ao_fec_tx_test.c b/src/test/ao_fec_tx_test.c new file mode 100644 index 00000000..b8dc9308 --- /dev/null +++ b/src/test/ao_fec_tx_test.c @@ -0,0 +1,47 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 +#include +#include + +int +main(int argc, char **argv) +{ + uint8_t input[4] = { 3, 1, 2, 3 }; + uint8_t prepare[sizeof(input) + AO_FEC_PREPARE_EXTRA]; + uint8_t encode[sizeof(prepare) * 2]; + uint8_t interleave[sizeof(encode)]; + uint8_t prepare_len; + uint8_t encode_len; + uint8_t interleave_len; + + ao_fec_dump_bytes(input, sizeof(input), "Input"); + + prepare_len = ao_fec_prepare(input, sizeof (input), prepare); + + ao_fec_dump_bytes(prepare, prepare_len, "Prepare"); + + encode_len = ao_fec_encode(prepare, prepare_len, encode); + + ao_fec_dump_bytes(encode, encode_len, "Encode"); + + interleave_len = ao_fec_interleave(encode, encode_len, interleave); + + ao_fec_dump_bytes(interleave, interleave_len, "Interleave"); +} + diff --git a/src/util/make-whiten b/src/util/make-whiten new file mode 100644 index 00000000..d68a02af --- /dev/null +++ b/src/util/make-whiten @@ -0,0 +1,37 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +/* Generate the data whitening array used by the CC11* radios */ + +int pn9 = 0x1ff; + +void +pn9_step() { + pn9 = (pn9 >> 1) | (((pn9 ^ (pn9 >> 5)) & 1) << 8); +} + +int val() +{ + int ret = pn9 & 0xff; + + for (int i = 0; i < 8; i++) + pn9_step(); + return ret; +} + +for (int i = 0; i < 128; i++) + printf (" /* %3d */ 0x%02x,\n", i + 1, val()); -- cgit v1.2.3 From cbf79a0f9cb859d04e8e03d627219cb2bf49611f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 22 Jun 2012 23:12:02 -0700 Subject: altos: Add the simplest possible viterbi decoder I think I understand how it works now. It's not exactly speedy, and it uses a lot of memory. Signed-off-by: Keith Packard --- src/core/ao_fec.h | 9 +++ src/core/ao_viterbi.c | 143 ++++++++++++++++++++++++++++++++++++++++ src/test/Makefile | 4 +- src/test/ao_fec_tx_test.c | 163 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 307 insertions(+), 12 deletions(-) create mode 100644 src/core/ao_viterbi.c (limited to 'src/test') diff --git a/src/core/ao_fec.h b/src/core/ao_fec.h index db5523a3..985352dd 100644 --- a/src/core/ao_fec.h +++ b/src/core/ao_fec.h @@ -57,4 +57,13 @@ ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out); uint8_t ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out); + +/* + * Decode data. 'in' is one byte per bit, soft decision + * 'out' must be len/8 bytes long + */ + +uint8_t +ao_fec_decode(uint8_t *in, int in_len, uint8_t *out); + #endif /* _AO_FEC_H_ */ diff --git a/src/core/ao_viterbi.c b/src/core/ao_viterbi.c new file mode 100644 index 00000000..2d441f4b --- /dev/null +++ b/src/core/ao_viterbi.c @@ -0,0 +1,143 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 +#include + +/* + * 'input' is 8-bits per symbol soft decision data + * 'len' is output byte length + */ + +static const uint8_t ao_fec_encode_table[16] = { +/* next 0 1 state */ + 0, 3, /* 000 */ + 1, 2, /* 001 */ + 3, 0, /* 010 */ + 2, 1, /* 011 */ + 3, 0, /* 100 */ + 2, 1, /* 101 */ + 0, 3, /* 110 */ + 1, 2 /* 111 */ +}; + +struct ao_soft_sym { + uint8_t a, b; +}; + +struct ao_soft_sym +ao_soft_sym(uint8_t bits) +{ + struct ao_soft_sym s; + + s.a = ((bits & 2) >> 1) * 0xff; + s.b = (bits & 1) * 0xff; + return s; +} + +uint8_t +ao_next_state(uint8_t state, uint8_t bit) +{ + return ((state << 1) | bit) & 0x7; +} + +static inline abs(int x) { return x < 0 ? -x : x; } + +int +ao_cost(struct ao_soft_sym a, struct ao_soft_sym b) +{ + return abs(a.a - b.a) + abs(a.b - b.b); +} + +uint8_t +ao_fec_decode(uint8_t *in, int len, uint8_t *out) +{ + int cost[len/2 + 1][8]; + uint8_t prev[len/2 + 1][8]; + int c; + int i, b; + uint8_t state = 0, min_state; + uint8_t bits[len/2]; + + for (c = 0; c < 8; c++) + cost[0][c] = 10000; + cost[0][0] = 0; + + for (i = 0; i < len; i += 2) { + b = i/2; + struct ao_soft_sym s = { .a = in[i], .b = in[i+1] }; + + for (state = 0; state < 8; state++) + cost[b+1][state] = 10000; + + for (state = 0; state < 8; state++) { + struct ao_soft_sym zero = ao_soft_sym(ao_fec_encode_table[state * 2 + 0]); + struct ao_soft_sym one = ao_soft_sym(ao_fec_encode_table[state * 2 + 1]); + uint8_t zero_state = ao_next_state(state, 0); + uint8_t one_state = ao_next_state(state, 1); + int zero_cost = ao_cost(s, zero); + int one_cost = ao_cost(s, one); + +#if 0 + printf ("saw %02x %02x expected %02x %02x (%d) or %02x %02x (%d)\n", + s.a, s.b, zero.a, zero.b, zero_cost, one.a, one.b, one_cost); +#endif + zero_cost += cost[b][state]; + one_cost += cost[b][state]; + if (zero_cost < cost[b+1][zero_state]) { + prev[b+1][zero_state] = state; + cost[b+1][zero_state] = zero_cost; + } + + if (one_cost < cost[b+1][one_state]) { + prev[b+1][one_state] = state; + cost[b+1][one_state] = one_cost; + } + } + + printf ("bit %3d symbol %2x %2x:", i/2, s.a, s.b); + for (state = 0; state < 8; state++) { + printf (" %5d", cost[b+1][state]); + } + printf ("\n"); + } + + b = len / 2; + c = cost[b][0]; + min_state = 0; + for (state = 1; state < 8; state++) { + if (cost[b][state] < c) { + c = cost[b][state]; + min_state = state; + } + } + + for (b = len/2; b > 0; b--) { + bits[b-1] = min_state & 1; + min_state = prev[b][min_state]; + } + + for (i = 0; i < len/2; i += 8) { + uint8_t byte; + + byte = 0; + for (b = 0; b < 8; b++) + byte = (byte << 1) | bits[i + b]; + out[i/8] = byte; + } + return len/16; +} diff --git a/src/test/Makefile b/src/test/Makefile index 3e308dd7..024a54c1 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -40,5 +40,5 @@ ao_convert_pa_test: ao_convert_pa_test.c ao_convert_pa.c altitude-pa.h ao_kalman.h: $(KALMAN) (cd .. && make ao_kalman.h) -ao_fec_tx_test: ao_fec_tx_test.c ao_fec_tx.c - cc $(CFLAGS) -o $@ ao_fec_tx_test.c ../drivers/ao_fec_tx.c +ao_fec_tx_test: ao_fec_tx_test.c ao_fec_tx.c ao_viterbi.c + cc $(CFLAGS) -o $@ ao_fec_tx_test.c ../core/ao_fec_tx.c ../core/ao_viterbi.c -lm diff --git a/src/test/ao_fec_tx_test.c b/src/test/ao_fec_tx_test.c index b8dc9308..d01eadc5 100644 --- a/src/test/ao_fec_tx_test.c +++ b/src/test/ao_fec_tx_test.c @@ -18,21 +18,73 @@ #include #include #include +#include +#include -int -main(int argc, char **argv) +#ifndef RANDOM_MAX +#define RANDOM_MAX 0x7fffffff +#endif + +static double +rand_real(void) { + return (double) random() / (double) RANDOM_MAX; +} + +static double +gaussian_random(double mean, double dev) { - uint8_t input[4] = { 3, 1, 2, 3 }; - uint8_t prepare[sizeof(input) + AO_FEC_PREPARE_EXTRA]; - uint8_t encode[sizeof(prepare) * 2]; - uint8_t interleave[sizeof(encode)]; + static int save_x_valid = 0; + static double save_x; + double x; + + if (save_x_valid) + { + x = save_x; + save_x_valid = 0; + } + else + { + double w; + double normal_x1, normal_x2; + + do { + normal_x1 = 2 * rand_real () - 1; + normal_x2 = 2 * rand_real () - 1; + w = normal_x1*normal_x1 + normal_x2*normal_x2; + } while (w >= 1 || w < 1E-30); + + w = sqrt(log(w)*(-2./w)); + + /* + * normal_x1 and normal_x2 are independent normally + * distributed variates + */ + + x = normal_x1 * w; + /* save normal_x2 for next call */ + save_x = normal_x2 * w; + save_x_valid = 1; + } + return x * dev + mean; +} + +#define PREPARE_LEN(input_len) ((input_len) + AO_FEC_PREPARE_EXTRA) +#define ENCODE_LEN(input_len) (PREPARE_LEN(input_len) * 2) +#define INTERLEAVE_LEN(input_len) ENCODE_LEN(input_len) + +static int +ao_encode(uint8_t *input, int input_len, uint8_t *output) +{ + uint8_t prepare[PREPARE_LEN(input_len)]; + uint8_t encode[ENCODE_LEN(input_len)]; + uint8_t interleave[INTERLEAVE_LEN(input_len)]; uint8_t prepare_len; uint8_t encode_len; uint8_t interleave_len; - ao_fec_dump_bytes(input, sizeof(input), "Input"); + ao_fec_dump_bytes(input, input_len, "Input"); - prepare_len = ao_fec_prepare(input, sizeof (input), prepare); + prepare_len = ao_fec_prepare(input, input_len, prepare); ao_fec_dump_bytes(prepare, prepare_len, "Prepare"); @@ -40,8 +92,99 @@ main(int argc, char **argv) ao_fec_dump_bytes(encode, encode_len, "Encode"); - interleave_len = ao_fec_interleave(encode, encode_len, interleave); + interleave_len = ao_fec_interleave(encode, encode_len, output); + + ao_fec_dump_bytes(output, interleave_len, "Interleave"); + + return interleave_len; +} + +#define RADIO_LEN(input_len) (INTERLEAVE_LEN(input_len) * 8) + +static int +ao_radio(uint8_t *bits, int bits_len, uint8_t *bytes) +{ + uint8_t b, *bytes_orig = bytes; + uint8_t interleave[bits_len]; + int i, bit; + + ao_fec_interleave(bits, bits_len, interleave); + + ao_fec_dump_bytes(interleave, bits_len, "De-interleave"); + + for (i = 0; i < bits_len; i++) { + b = interleave[i]; + for (bit = 7; bit >= 0; bit--) + *bytes++ = ((b >> bit) & 1) * 0xff; + } + + ao_fec_dump_bytes(bytes_orig, bits_len * 8, "Bytes"); - ao_fec_dump_bytes(interleave, interleave_len, "Interleave"); + return bits_len * 8; } +static int +ao_fuzz (uint8_t *in, int in_len, uint8_t *out, double dev) +{ + int i; + int errors = 0; + + for (i = 0; i < in_len; i++) { + double error = gaussian_random(0, dev); + uint8_t byte = in[i]; + + if (error > 0) { + if (error > 0xff) + error = 0xff; + if (error >= 0x80) + errors++; + if (byte < 0x80) + byte += error; + else + byte -= error; + } + out[i] = byte; + } + + printf ("Introduced %d errors\n", errors); + ao_fec_dump_bytes(out, in_len, "Fuzz"); + return in_len; +} + +static int +ao_decode(uint8_t *bytes, int bytes_len, uint8_t *bits) +{ + int bits_len; + + bits_len = ao_fec_decode(bytes, bytes_len, bits); + + ao_fec_dump_bytes(bits, bits_len, "Decode"); +} + +int +main(int argc, char **argv) +{ + uint8_t original[4] = { 3, 1, 2, 3 }; + uint8_t encode[INTERLEAVE_LEN(sizeof(original))]; + int encode_len; + + uint8_t transmit[RADIO_LEN(sizeof(original))]; + int transmit_len; + + uint8_t receive[RADIO_LEN(sizeof(original))]; + int receive_len; + + uint8_t decode[INTERLEAVE_LEN(sizeof(original))]; + int decode_len; + + encode_len = ao_encode(original, sizeof(original), encode); + + transmit_len = ao_radio(encode, encode_len, transmit); + + /* apply gaussian noise to test viterbi code against errors */ + receive_len = ao_fuzz(transmit, transmit_len, receive, 0x80); + + decode_len = ao_decode(receive, receive_len, decode); +} + + -- cgit v1.2.3 From 83549f8bde42c3fddbdc817540c869dc8aefd013 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 23 Jun 2012 02:13:52 -0700 Subject: altos: Make ao_fec_tx_test build cleanly with -Wall Signed-off-by: Keith Packard --- src/test/Makefile | 2 +- src/test/ao_fec_tx_test.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/test') diff --git a/src/test/Makefile b/src/test/Makefile index 024a54c1..7bcf24e1 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -4,7 +4,7 @@ PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noi KALMAN=make-kalman -CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g +CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g -Wall all: $(PROGS) diff --git a/src/test/ao_fec_tx_test.c b/src/test/ao_fec_tx_test.c index d01eadc5..1b1fd56d 100644 --- a/src/test/ao_fec_tx_test.c +++ b/src/test/ao_fec_tx_test.c @@ -77,7 +77,6 @@ ao_encode(uint8_t *input, int input_len, uint8_t *output) { uint8_t prepare[PREPARE_LEN(input_len)]; uint8_t encode[ENCODE_LEN(input_len)]; - uint8_t interleave[INTERLEAVE_LEN(input_len)]; uint8_t prepare_len; uint8_t encode_len; uint8_t interleave_len; @@ -159,6 +158,7 @@ ao_decode(uint8_t *bytes, int bytes_len, uint8_t *bits) bits_len = ao_fec_decode(bytes, bytes_len, bits); ao_fec_dump_bytes(bits, bits_len, "Decode"); + return bits_len; } int @@ -182,9 +182,11 @@ main(int argc, char **argv) transmit_len = ao_radio(encode, encode_len, transmit); /* apply gaussian noise to test viterbi code against errors */ - receive_len = ao_fuzz(transmit, transmit_len, receive, 0x80); + receive_len = ao_fuzz(transmit, transmit_len, receive, 0x70); decode_len = ao_decode(receive, receive_len, decode); + + return decode_len >= sizeof(original); } -- cgit v1.2.3 From b292c14790fc225029cba3f80ce8ad6c5652bc4e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 23 Jun 2012 16:05:42 -0700 Subject: altos: improve FEC apis to reduce data copying Integrate interleaving and whitening into encode and decode steps. Add CRC checking function for receive. Make ao_fec_test program round-trip the data and verify correctness. Signed-off-by: Keith Packard --- src/core/ao_fec.h | 26 ++++-- src/core/ao_fec_tx.c | 118 +++++++++++++++++---------- src/core/ao_viterbi.c | 46 ++++++++++- src/test/Makefile | 6 +- src/test/ao_fec_test.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++ src/test/ao_fec_tx_test.c | 192 -------------------------------------------- 6 files changed, 337 insertions(+), 249 deletions(-) create mode 100644 src/test/ao_fec_test.c delete mode 100644 src/test/ao_fec_tx_test.c (limited to 'src/test') diff --git a/src/core/ao_fec.h b/src/core/ao_fec.h index d4f64b74..f3f55fa8 100644 --- a/src/core/ao_fec.h +++ b/src/core/ao_fec.h @@ -24,12 +24,22 @@ #define AO_FEC_TRELLIS_TERMINATOR 0x0b #define AO_FEC_PREPARE_EXTRA 4 +extern const uint8_t ao_fec_whiten_table[]; + void -ao_fec_dump_bytes(uint8_t *bytes, uint8_t len, char *name); +ao_fec_dump_bytes(uint8_t *bytes, uint16_t len, char *name); uint16_t ao_fec_crc(uint8_t *bytes, uint8_t len); +/* + * 'len' is the length of the original data; 'bytes' + * must be four bytes longer than that, and the first + * two after 'len' must be the received crc + */ +uint8_t +ao_fec_check_crc(uint8_t *bytes, uint8_t len); + /* * Append CRC and terminator bytes, returns resulting length. * 'out' must be at least len + AO_FEC_PREPARE_EXTRA bytes long @@ -46,17 +56,11 @@ void ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out); /* - * Encode data. 'out' must be len*2 bytes long + * Encode and interleave data. 'out' must be len*2 bytes long */ uint8_t ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out); -/* - * Interleave data. 'out' must be 'len' bytes long - */ -uint8_t -ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out); - /* * Decode data. 'in' is one byte per bit, soft decision * 'out' must be len/8 bytes long @@ -65,4 +69,10 @@ ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out); uint8_t ao_fec_decode(uint8_t *in, uint16_t in_len, uint8_t *out); +/* + * Interleave data packed in bytes. 'out' must be 'len' bytes long. + */ +uint16_t +ao_fec_interleave_bytes(uint8_t *in, uint16_t len, uint8_t *out); + #endif /* _AO_FEC_H_ */ diff --git a/src/core/ao_fec_tx.c b/src/core/ao_fec_tx.c index c5f410b8..c9c0a3d6 100644 --- a/src/core/ao_fec_tx.c +++ b/src/core/ao_fec_tx.c @@ -19,9 +19,9 @@ #include void -ao_fec_dump_bytes(uint8_t *bytes, uint8_t len, char *name) +ao_fec_dump_bytes(uint8_t *bytes, uint16_t len, char *name) { - uint8_t i; + uint16_t i; printf ("%s (%d):", name, len); for (i = 0; i < len; i++) { @@ -57,41 +57,76 @@ ao_fec_crc(uint8_t *bytes, uint8_t len) return crc; } +/* + * len is the length of the data; the crc will be + * the fist two bytes after that + */ + uint8_t -ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *out) +ao_fec_check_crc(uint8_t *bytes, uint8_t len) +{ + uint16_t computed_crc = ao_fec_crc(bytes, len); + uint16_t received_crc = (bytes[len] << 8) | (bytes[len+1]); + + return computed_crc == received_crc; +} + +uint8_t +ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *extra) { uint16_t crc = ao_fec_crc (in, len); - uint8_t i; + uint8_t i = 0; uint8_t num_fec; - /* Copy data */ - for (i = 0; i < len; i++) - out[i] = in[i]; - /* Append CRC */ - out[i++] = crc >> 8; - out[i++] = crc; + extra[i++] = crc >> 8; + extra[i++] = crc; /* Append FEC -- 1 byte if odd, two bytes if even */ num_fec = 2 - (i & 1); while (num_fec--) - out[i++] = AO_FEC_TRELLIS_TERMINATOR; + extra[i++] = AO_FEC_TRELLIS_TERMINATOR; return i; } -static const uint8_t whiten[] = { +const uint8_t ao_fec_whiten_table[] = { #include "ao_whiten.h" }; +#if 0 void ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out) { - const uint8_t *w = whiten; + const uint8_t *w = ao_fec_whiten_table; while (len--) *out++ = *in++ ^ *w++; } +/* + * Unused as interleaving is now built in to ao_fec_encode + */ + +static void +ao_fec_interleave(uint8_t *d, uint8_t len) +{ + uint8_t i, j; + + for (i = 0; i < len; i += 4) { + uint32_t interleaved = 0; + + for (j = 0; j < 4 * 4; j++) { + interleaved <<= 2; + interleaved |= (d[i + (~j & 0x3)] >> (2 * ((j & 0xc) >> 2))) & 0x03; + } + d[i+0] = interleaved >> 24; + d[i+1] = interleaved >> 16; + d[i+2] = interleaved >> 8; + d[i+3] = interleaved; + } +} +#endif + static const uint8_t ao_fec_encode_table[16] = { /* next 0 1 state */ 0, 3, /* 000 */ @@ -107,38 +142,37 @@ static const uint8_t ao_fec_encode_table[16] = { uint8_t ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out) { - uint16_t fec = 0, output; - uint8_t byte, bit; - - for (byte = 0; byte < len; byte++) { - fec = (fec & 0x700) | in[byte]; - output = 0; - for (bit = 0; bit < 8; bit++) { - output = output << 2 | ao_fec_encode_table[fec >> 7]; - fec = (fec << 1) & 0x7ff; + uint8_t extra[AO_FEC_PREPARE_EXTRA]; + uint8_t extra_len; + uint32_t encode, interleave; + uint8_t pair, byte, bit; + uint16_t fec = 0; + const uint8_t *whiten = ao_fec_whiten_table; + + extra_len = ao_fec_prepare(in, len, extra); + for (pair = 0; pair < len + extra_len; pair += 2) { + encode = 0; + for (byte = 0; byte < 2; byte++) { + if (pair + byte == len) + in = extra; + fec |= *in++ ^ *whiten++; + for (bit = 0; bit < 8; bit++) { + encode = encode << 2 | ao_fec_encode_table[fec >> 7]; + fec = (fec << 1) & 0x7ff; + } } - out[byte * 2] = output >> 8; - out[byte * 2 + 1] = output; - } - return len * 2; -} -uint8_t -ao_fec_interleave(uint8_t *in, uint8_t len, uint8_t *out) -{ - uint8_t i, j; - - for (i = 0; i < len; i += 4) { - uint32_t interleaved = 0; + interleave = 0; + for (bit = 0; bit < 4 * 4; bit++) { + uint8_t byte_shift = (bit & 0x3) << 3; + uint8_t bit_shift = (bit & 0xc) >> 1; - for (j = 0; j < 4 * 4; j++) { - interleaved <<= 2; - interleaved |= (in[i + (~j & 0x3)] >> (2 * ((j & 0xc) >> 2))) & 0x03; + interleave = (interleave << 2) | ((encode >> (byte_shift + bit_shift)) & 0x3); } - out[i+0] = interleaved >> 24; - out[i+1] = interleaved >> 16; - out[i+2] = interleaved >> 8; - out[i+3] = interleaved; + *out++ = interleave >> 24; + *out++ = interleave >> 16; + *out++ = interleave >> 8; + *out++ = interleave >> 0; } - return len; + return (len + extra_len) * 2; } diff --git a/src/core/ao_viterbi.c b/src/core/ao_viterbi.c index 17464cd1..bb93bc83 100644 --- a/src/core/ao_viterbi.c +++ b/src/core/ao_viterbi.c @@ -18,6 +18,35 @@ #include #include +/* + * byte order repeats through 3 2 1 0 + * + * bit-pair order repeats through + * + * 1/0 3/2 5/4 7/6 + * + * So, the over all order is: + * + * 3,1/0 2,1/0 1,1/0 0,1/0 + * 3,3/2 2,3/2 1,3/2 0,3/2 + * 3,5/4 2,5/4 1,5/4 0,5/4 + * 3,7/6 2,7/6 1,7/6 0,7/6 + * + * The raw bit order is thus + * + * 1e/1f 16/17 0e/0f 06/07 + * 1c/1d 14/15 0c/0d 04/05 + * 1a/1b 12/13 0a/0b 02/03 + * 18/19 10/11 08/09 00/01 + */ + +static inline uint16_t ao_interleave_index(uint16_t i) { + uint8_t l = i & 0x1e; + uint16_t h = i & ~0x1e; + uint8_t o = 0x1e ^ (((l >> 2) & 0x6) | ((l << 2) & 0x18)); + return h | o; +} + struct ao_soft_sym { uint8_t a, b; }; @@ -70,6 +99,9 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out) uint8_t n; /* next cost/bits index */ uint8_t state; /* state index */ uint8_t bit; /* original encoded bit index */ + const uint8_t *whiten = ao_fec_whiten_table; + uint16_t interleave; /* input byte array index */ + struct ao_soft_sym s; /* input symbol pair */ p = 0; for (state = 0; state < NUM_STATE; state++) { @@ -82,7 +114,13 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out) for (i = 0; i < len; i += 2) { b = i/2; n = p ^ 1; - struct ao_soft_sym s = { .a = in[i], .b = in[i+1] }; + + /* Fetch one pair of input bytes, de-interleaving + * the input. + */ + interleave = ao_interleave_index(i); + s.a = in[interleave]; + s.b = in[interleave+1]; /* Reset next costs to 'impossibly high' values so that * the first path through this state is cheaper than this @@ -159,10 +197,10 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out) } #if 0 - printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x\n", - i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff); + printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x whiten %0x\n", + i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten); #endif - out[o >> 3] = bits[p][min_state] >> dist; + *out++ = (bits[p][min_state] >> dist) ^ *whiten++; o += 8; } } diff --git a/src/test/Makefile b/src/test/Makefile index 7bcf24e1..cdcecd51 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,6 @@ vpath % ..:../core:../drivers:../util -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_tx_test +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 KALMAN=make-kalman @@ -40,5 +40,5 @@ ao_convert_pa_test: ao_convert_pa_test.c ao_convert_pa.c altitude-pa.h ao_kalman.h: $(KALMAN) (cd .. && make ao_kalman.h) -ao_fec_tx_test: ao_fec_tx_test.c ao_fec_tx.c ao_viterbi.c - cc $(CFLAGS) -o $@ ao_fec_tx_test.c ../core/ao_fec_tx.c ../core/ao_viterbi.c -lm +ao_fec_test: ao_fec_test.c ao_fec_tx.c ao_viterbi.c + cc $(CFLAGS) -o $@ ao_fec_test.c ../core/ao_fec_tx.c ../core/ao_viterbi.c -lm diff --git a/src/test/ao_fec_test.c b/src/test/ao_fec_test.c new file mode 100644 index 00000000..c7509728 --- /dev/null +++ b/src/test/ao_fec_test.c @@ -0,0 +1,198 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 +#include +#include +#include +#include +#include + +#ifndef RANDOM_MAX +#define RANDOM_MAX 0x7fffffff +#endif + +static double +rand_real(void) { + return (double) random() / (double) RANDOM_MAX; +} + +static double +gaussian_random(double mean, double dev) +{ + static int save_x_valid = 0; + static double save_x; + double x; + + if (save_x_valid) + { + x = save_x; + save_x_valid = 0; + } + else + { + double w; + double normal_x1, normal_x2; + + do { + normal_x1 = 2 * rand_real () - 1; + normal_x2 = 2 * rand_real () - 1; + w = normal_x1*normal_x1 + normal_x2*normal_x2; + } while (w >= 1 || w < 1E-30); + + w = sqrt(log(w)*(-2./w)); + + /* + * normal_x1 and normal_x2 are independent normally + * distributed variates + */ + + x = normal_x1 * w; + /* save normal_x2 for next call */ + save_x = normal_x2 * w; + save_x_valid = 1; + } + return x * dev + mean; +} + +#define PREPARE_LEN(input_len) ((input_len) + AO_FEC_PREPARE_EXTRA) +#define ENCODE_LEN(input_len) (PREPARE_LEN(input_len) * 2) +#define DECODE_LEN(input_len) ((input_len) + AO_FEC_PREPARE_EXTRA) +#define EXPAND_LEN(input_len) (ENCODE_LEN(input_len) * 8) + +static int +ao_expand(uint8_t *bits, int bits_len, uint8_t *bytes) +{ + int i, bit; + uint8_t b; + + for (i = 0; i < bits_len; i++) { + b = bits[i]; + for (bit = 7; bit >= 0; bit--) + *bytes++ = ((b >> bit) & 1) * 0xff; + } + + return bits_len * 8; +} + +static int +ao_fuzz (uint8_t *in, int in_len, uint8_t *out, double dev) +{ + int i; + int errors = 0; + + for (i = 0; i < in_len; i++) { + double error = gaussian_random(0, dev); + uint8_t byte = in[i]; + + if (error > 0) { + if (error > 0xff) + error = 0xff; + if (error >= 0x80) + errors++; + if (byte < 0x80) + byte += error; + else + byte -= error; + } + out[i] = byte; + } + return errors; +} + +static uint8_t +ao_random_data(uint8_t *out, uint8_t out_len) +{ + uint8_t len = random() % (out_len + 1); + uint8_t i; + + for (i = 0; i < len; i++) + out[i] = random(); + return len; +} + + +int +main(int argc, char **argv) +{ + int trial; + + uint8_t original[120]; + uint8_t original_len; + + uint8_t encode[ENCODE_LEN(sizeof(original))]; + int encode_len; + + uint8_t transmit[EXPAND_LEN(sizeof(original))]; + int transmit_len; + + uint8_t receive[EXPAND_LEN(sizeof(original))]; + int receive_len, receive_errors; + + uint8_t decode[DECODE_LEN(sizeof(original))]; + int decode_len; + + int errors = 0; + int error; + + srandom(0); + for (trial = 0; trial < 10000; trial++) { + + /* Compute some random data */ + original_len = ao_random_data(original, sizeof(original)); + + /* Encode it */ + encode_len = ao_fec_encode(original, original_len, encode); + + /* Expand from 1-bit-per-symbol to 1-byte-per-symbol */ + transmit_len = ao_expand(encode, encode_len, transmit); + + /* Add gaussian noise to the signal */ + receive_errors = ao_fuzz(transmit, transmit_len, receive, 0x30); + receive_len = transmit_len; + + /* Decode it */ + decode_len = ao_fec_decode(receive, receive_len, decode); + + /* Check to see if we received the right data */ + error = 0; + + if (decode_len < original_len + 2) { + printf ("len mis-match\n"); + error++; + } + + if (!ao_fec_check_crc(decode, original_len)) { + printf ("crc mis-match\n"); + error++; + } + + if (memcmp(original, decode, original_len) != 0) { + printf ("data mis-match\n"); + error++; + } + if (error) { + printf ("Errors: %d\n", receive_errors); + ao_fec_dump_bytes(original, original_len, "Input"); + ao_fec_dump_bytes(decode, original_len, "Decode"); + errors += error; + } + } + return errors; +} + + diff --git a/src/test/ao_fec_tx_test.c b/src/test/ao_fec_tx_test.c deleted file mode 100644 index 1b1fd56d..00000000 --- a/src/test/ao_fec_tx_test.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright © 2012 Keith Packard - * - * 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 -#include -#include -#include -#include - -#ifndef RANDOM_MAX -#define RANDOM_MAX 0x7fffffff -#endif - -static double -rand_real(void) { - return (double) random() / (double) RANDOM_MAX; -} - -static double -gaussian_random(double mean, double dev) -{ - static int save_x_valid = 0; - static double save_x; - double x; - - if (save_x_valid) - { - x = save_x; - save_x_valid = 0; - } - else - { - double w; - double normal_x1, normal_x2; - - do { - normal_x1 = 2 * rand_real () - 1; - normal_x2 = 2 * rand_real () - 1; - w = normal_x1*normal_x1 + normal_x2*normal_x2; - } while (w >= 1 || w < 1E-30); - - w = sqrt(log(w)*(-2./w)); - - /* - * normal_x1 and normal_x2 are independent normally - * distributed variates - */ - - x = normal_x1 * w; - /* save normal_x2 for next call */ - save_x = normal_x2 * w; - save_x_valid = 1; - } - return x * dev + mean; -} - -#define PREPARE_LEN(input_len) ((input_len) + AO_FEC_PREPARE_EXTRA) -#define ENCODE_LEN(input_len) (PREPARE_LEN(input_len) * 2) -#define INTERLEAVE_LEN(input_len) ENCODE_LEN(input_len) - -static int -ao_encode(uint8_t *input, int input_len, uint8_t *output) -{ - uint8_t prepare[PREPARE_LEN(input_len)]; - uint8_t encode[ENCODE_LEN(input_len)]; - uint8_t prepare_len; - uint8_t encode_len; - uint8_t interleave_len; - - ao_fec_dump_bytes(input, input_len, "Input"); - - prepare_len = ao_fec_prepare(input, input_len, prepare); - - ao_fec_dump_bytes(prepare, prepare_len, "Prepare"); - - encode_len = ao_fec_encode(prepare, prepare_len, encode); - - ao_fec_dump_bytes(encode, encode_len, "Encode"); - - interleave_len = ao_fec_interleave(encode, encode_len, output); - - ao_fec_dump_bytes(output, interleave_len, "Interleave"); - - return interleave_len; -} - -#define RADIO_LEN(input_len) (INTERLEAVE_LEN(input_len) * 8) - -static int -ao_radio(uint8_t *bits, int bits_len, uint8_t *bytes) -{ - uint8_t b, *bytes_orig = bytes; - uint8_t interleave[bits_len]; - int i, bit; - - ao_fec_interleave(bits, bits_len, interleave); - - ao_fec_dump_bytes(interleave, bits_len, "De-interleave"); - - for (i = 0; i < bits_len; i++) { - b = interleave[i]; - for (bit = 7; bit >= 0; bit--) - *bytes++ = ((b >> bit) & 1) * 0xff; - } - - ao_fec_dump_bytes(bytes_orig, bits_len * 8, "Bytes"); - - return bits_len * 8; -} - -static int -ao_fuzz (uint8_t *in, int in_len, uint8_t *out, double dev) -{ - int i; - int errors = 0; - - for (i = 0; i < in_len; i++) { - double error = gaussian_random(0, dev); - uint8_t byte = in[i]; - - if (error > 0) { - if (error > 0xff) - error = 0xff; - if (error >= 0x80) - errors++; - if (byte < 0x80) - byte += error; - else - byte -= error; - } - out[i] = byte; - } - - printf ("Introduced %d errors\n", errors); - ao_fec_dump_bytes(out, in_len, "Fuzz"); - return in_len; -} - -static int -ao_decode(uint8_t *bytes, int bytes_len, uint8_t *bits) -{ - int bits_len; - - bits_len = ao_fec_decode(bytes, bytes_len, bits); - - ao_fec_dump_bytes(bits, bits_len, "Decode"); - return bits_len; -} - -int -main(int argc, char **argv) -{ - uint8_t original[4] = { 3, 1, 2, 3 }; - uint8_t encode[INTERLEAVE_LEN(sizeof(original))]; - int encode_len; - - uint8_t transmit[RADIO_LEN(sizeof(original))]; - int transmit_len; - - uint8_t receive[RADIO_LEN(sizeof(original))]; - int receive_len; - - uint8_t decode[INTERLEAVE_LEN(sizeof(original))]; - int decode_len; - - encode_len = ao_encode(original, sizeof(original), encode); - - transmit_len = ao_radio(encode, encode_len, transmit); - - /* apply gaussian noise to test viterbi code against errors */ - receive_len = ao_fuzz(transmit, transmit_len, receive, 0x70); - - decode_len = ao_decode(receive, receive_len, decode); - - return decode_len >= sizeof(original); -} - - -- cgit v1.2.3 From 70cf32e89df19bde5185339fc703532c8a5b8be6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jun 2012 05:03:34 -0700 Subject: altos: Get cc1120 packet reception working Interrupt-per-bit, but it seems to work Signed-off-by: Keith Packard --- src/core/ao_viterbi.c | 19 ++-- src/drivers/ao_cc1120.c | 169 ++++++++++++++++++++++++++---------- src/megametrum-v0.1/ao_megametrum.c | 6 +- src/megametrum-v0.1/ao_pins.h | 2 +- src/stm/ao_exti.h | 3 + src/stm/ao_exti_stm.c | 5 ++ src/test/ao_fec_test.c | 151 ++++++++++++++++++++++++++++++++ 7 files changed, 299 insertions(+), 56 deletions(-) (limited to 'src/test') diff --git a/src/core/ao_viterbi.c b/src/core/ao_viterbi.c index bb93bc83..594c0d91 100644 --- a/src/core/ao_viterbi.c +++ b/src/core/ao_viterbi.c @@ -55,16 +55,19 @@ struct ao_soft_sym { #define NUM_HIST 8 #define MOD_HIST(b) ((b) & 7) +#define V_0 0xc0 +#define V_1 0x40 + static const struct ao_soft_sym ao_fec_decode_table[NUM_STATE][2] = { /* next 0 1 state */ - { { 0x00, 0x00 }, { 0xff, 0xff } } , /* 000 */ - { { 0x00, 0xff }, { 0xff, 0x00 } }, /* 001 */ - { { 0xff, 0xff }, { 0x00, 0x00 } }, /* 010 */ - { { 0xff, 0x00 }, { 0x00, 0xff } }, /* 011 */ - { { 0xff, 0xff }, { 0x00, 0x00 } }, /* 100 */ - { { 0xff, 0x00 }, { 0x00, 0xff } }, /* 101 */ - { { 0x00, 0x00 }, { 0xff, 0xff } }, /* 110 */ - { { 0x00, 0xff }, { 0xff, 0x00 } } /* 111 */ + { { V_0, V_0 }, { V_1, V_1 } } , /* 000 */ + { { V_0, V_1 }, { V_1, V_0 } }, /* 001 */ + { { V_1, V_1 }, { V_0, V_0 } }, /* 010 */ + { { V_1, V_0 }, { V_0, V_1 } }, /* 011 */ + { { V_1, V_1 }, { V_0, V_0 } }, /* 100 */ + { { V_1, V_0 }, { V_0, V_1 } }, /* 101 */ + { { V_0, V_0 }, { V_1, V_1 } }, /* 110 */ + { { V_0, V_1 }, { V_1, V_0 } } /* 111 */ }; static inline uint8_t diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 67a36c5c..4378716d 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -19,6 +19,7 @@ #include #include #include +#include uint8_t ao_radio_wake; uint8_t ao_radio_mutex; @@ -102,6 +103,35 @@ ao_radio_reg_write(uint16_t addr, uint8_t value) ao_radio_deselect(); } +static void +ao_radio_burst_read_start (uint16_t addr) +{ + uint8_t data[2]; + uint8_t d; + + if (CC1120_IS_EXTENDED(addr)) { + data[0] = ((1 << CC1120_READ) | + (1 << CC1120_BURST) | + CC1120_EXTENDED); + data[1] = addr; + d = 2; + } else { + data[0] = ((1 << CC1120_READ) | + (1 << CC1120_BURST) | + addr); + d = 1; + } + ao_radio_select(); + ao_radio_spi_send(data, d); +} + +static void +ao_radio_burst_read_stop (void) +{ + ao_radio_deselect(); +} + + static uint8_t ao_radio_strobe(uint8_t addr) { @@ -247,10 +277,19 @@ ao_radio_rx_done(void) return ao_radio_marc_status() == CC1120_MARC_STATUS1_RX_FINISHED; } +static void +ao_radio_tx_isr(void) +{ + ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_wake = 1; + ao_wakeup(&ao_radio_wake); +} + static void ao_radio_start_tx(void) { ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); + ao_exti_set_callback(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr); ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); ao_radio_strobe(CC1120_STX); } @@ -336,29 +375,13 @@ void ao_radio_send(void *d, uint8_t size) { uint8_t marc_status; - uint8_t prepare[size + AO_FEC_PREPARE_EXTRA]; - uint8_t prepare_len; - uint8_t encode[sizeof(prepare) * 2]; + uint8_t encode[size + AO_FEC_PREPARE_EXTRA]; uint8_t encode_len; - uint8_t interleave[sizeof(encode)]; - uint8_t interleave_len; - fec_dump_bytes(d, size, "Input"); + encode_len = ao_fec_encode(d, size, encode); - prepare_len = ao_fec_prepare(d, size, prepare); - fec_dump_bytes(prepare, prepare_len, "Prepare"); - - ao_fec_whiten(prepare, prepare_len, prepare); - fec_dump_bytes(prepare, prepare_len, "Whiten"); - - encode_len = ao_fec_encode(prepare, prepare_len, encode); - fec_dump_bytes(encode, encode_len, "Encode"); - - interleave_len = ao_fec_interleave(encode, encode_len, interleave); - fec_dump_bytes(interleave, interleave_len, "Interleave"); - - ao_radio_get(interleave_len); - ao_radio_fifo_write(interleave, interleave_len); + ao_radio_get(encode_len); + ao_radio_fifo_write(encode, encode_len); ao_radio_wake = 0; @@ -373,34 +396,92 @@ ao_radio_send(void *d, uint8_t size) ao_radio_put(); } +#define AO_RADIO_MAX_RECV 90 + +static uint8_t rx_data[2048]; +static uint16_t rx_data_count; +static uint16_t rx_data_cur; +static uint8_t rx_started; + +static void +ao_radio_rx_isr(void) +{ + if (rx_started) { + rx_data[rx_data_cur++] = stm_spi2.dr; + if (rx_data_cur >= rx_data_count) { + ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_wake = 1; + ao_wakeup(&ao_radio_wake); + } + } else { + (void) stm_spi2.dr; + rx_started = 1; + } + stm_spi2.dr = 0x00; +} + uint8_t ao_radio_recv(__xdata void *d, uint8_t size) { - uint8_t marc_status = CC1120_MARC_STATUS1_NO_FAILURE; + uint8_t len = ((size - 2) + 4) * 2; /* two bytes for status */ + uint16_t i; + + rx_data_count = sizeof (rx_data); + rx_data_cur = 0; + rx_started = 0; + + printf ("len %d rx_data_count %d\n", len, rx_data_count); /* configure interrupt pin */ - ao_radio_get(size); + ao_radio_get(len); ao_radio_wake = 0; + ao_radio_abort = 0; + + ao_radio_reg_write(CC1120_PKT_CFG2, + (CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | + (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)); + + ao_radio_reg_write(CC1120_EXT_CTRL, 0); + + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT); + + stm_spi2.cr2 = 0; + + /* clear any RXNE */ + (void) stm_spi2.dr; + + ao_exti_set_callback(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr); ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_strobe(CC1120_SRX); - cli(); - for (;;) { - if (ao_radio_abort) - break; - if (ao_radio_wake) { - marc_status = ao_radio_marc_status(); - if (marc_status != CC1120_MARC_STATUS1_NO_FAILURE) - break; - ao_radio_wake = 0; - } + ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT); +#if 1 + cli(); + while (!ao_radio_wake && !ao_radio_abort) ao_sleep(&ao_radio_wake); - } sei(); - if (marc_status != CC1120_MARC_STATUS1_RX_FINISHED) - ao_radio_fifo_read(d, size); + +#else + printf ("Hit a character to stop..."); flush(); + getchar(); + putchar('\n'); + ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); +#endif + ao_radio_burst_read_stop(); + + ao_radio_strobe(CC1120_SIDLE); + ao_radio_put(); - return marc_status == CC1120_MARC_STATUS1_RX_FINISHED; + + printf ("Received data:"); + for (i = 0; i < rx_data_cur; i++) { + if ((i & 15) == 0) + printf ("\n"); + printf (" %02x", rx_data[i]); + } + printf ("\n"); + return 1; } /* @@ -477,13 +558,6 @@ static const uint16_t radio_setup[] = { static uint8_t ao_radio_configured = 0; -static void -ao_radio_isr(void) -{ - ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); - ao_radio_wake = 1; - ao_wakeup(&ao_radio_wake); -} static void ao_radio_setup(void) @@ -745,6 +819,12 @@ static void ao_radio_packet(void) { ao_radio_send(packet, sizeof (packet)); } +void +ao_radio_test_recv() +{ + ao_radio_recv(0, 34); +} + #endif static const struct ao_cmds ao_radio_cmds[] = { @@ -753,6 +833,7 @@ static const struct ao_cmds ao_radio_cmds[] = { { ao_radio_show, "R\0Show CC1120 status" }, { ao_radio_beep, "b\0Emit an RDF beacon" }, { ao_radio_packet, "p\0Send a test packet" }, + { ao_radio_test_recv, "q\0Recv a test packet" }, #endif { 0, NULL } }; @@ -776,7 +857,7 @@ ao_radio_init(void) /* Enable the EXTI interrupt for the appropriate pin */ ao_enable_port(AO_CC1120_INT_PORT); - ao_exti_setup(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_EXTI_MODE_FALLING, ao_radio_isr); + ao_exti_setup(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_EXTI_MODE_FALLING, ao_radio_tx_isr); ao_cmd_register(&ao_radio_cmds[0]); } diff --git a/src/megametrum-v0.1/ao_megametrum.c b/src/megametrum-v0.1/ao_megametrum.c index dc9c0d19..a2ac186b 100644 --- a/src/megametrum-v0.1/ao_megametrum.c +++ b/src/megametrum-v0.1/ao_megametrum.c @@ -44,9 +44,9 @@ main(void) ao_i2c_init(); ao_hmc5883_init(); ao_mpu6000_init(); - ao_flight_init(); - ao_log_init(); - ao_report_init(); +// ao_flight_init(); +// ao_log_init(); +// ao_report_init(); ao_telemetry_init(); ao_config_init(); diff --git a/src/megametrum-v0.1/ao_pins.h b/src/megametrum-v0.1/ao_pins.h index 5c5c5972..9d9113c8 100644 --- a/src/megametrum-v0.1/ao_pins.h +++ b/src/megametrum-v0.1/ao_pins.h @@ -255,7 +255,7 @@ struct ao_adc { #define AO_MPU6000_INT_PIN 13 #define AO_MPU6000_I2C_INDEX STM_I2C_INDEX(1) -#define HAS_HIGHG_ACCEL 1 +#define HAS_HIGHG_ACCEL 0 #define NUM_CMDS 16 diff --git a/src/stm/ao_exti.h b/src/stm/ao_exti.h index 43eaa52f..87a072e7 100644 --- a/src/stm/ao_exti.h +++ b/src/stm/ao_exti.h @@ -26,6 +26,9 @@ void ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)()); +void +ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)()); + void ao_exti_enable(struct stm_gpio *gpio, uint8_t pin); diff --git a/src/stm/ao_exti_stm.c b/src/stm/ao_exti_stm.c index 0fa24188..683a91b3 100644 --- a/src/stm/ao_exti_stm.c +++ b/src/stm/ao_exti_stm.c @@ -94,6 +94,11 @@ ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback stm_nvic_set_enable(irq); } +void +ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)()) { + ao_exti_callback[pin] = callback; +} + void ao_exti_enable(struct stm_gpio *gpio, uint8_t pin) { uint32_t mask = (1 << pin); diff --git a/src/test/ao_fec_test.c b/src/test/ao_fec_test.c index c7509728..98067486 100644 --- a/src/test/ao_fec_test.c +++ b/src/test/ao_fec_test.c @@ -126,6 +126,156 @@ ao_random_data(uint8_t *out, uint8_t out_len) } +static uint8_t real_packet[] = { + 0x00, 0x40, 0x38, 0xcd, 0x38, 0x3d, 0x34, 0xca, 0x31, 0xc3, 0xc1, 0xc6, 0x35, 0xcc, 0x3a, 0x3c, + 0x3c, 0x3d, 0x3c, 0x37, 0xc5, 0xc1, 0xc0, 0xc1, 0xc1, 0xc3, 0xc0, 0xc1, 0xc6, 0x38, 0x3b, 0xc6, + 0xc0, 0xc6, 0x32, 0xc9, 0xc9, 0x34, 0xcf, 0x35, 0xcf, 0x3a, 0x3b, 0xc6, 0xc7, 0x35, 0xcf, 0x36, + 0xce, 0x37, 0xc8, 0xc8, 0x3a, 0x3c, 0xc9, 0xc8, 0x3a, 0x3c, 0xcc, 0x32, 0xcd, 0x32, 0xce, 0x32, + 0xc9, 0xc6, 0x37, 0x3e, 0x3d, 0xc8, 0xc3, 0xc6, 0x38, 0x3d, 0xcf, 0x34, 0x3d, 0x3b, 0xcb, 0x31, + 0xca, 0x35, 0x38, 0xcb, 0x31, 0xcc, 0x31, 0x3b, 0xc7, 0xbf, 0xbe, 0xbe, 0xc3, 0x35, 0x38, 0xcb, + 0x2f, 0xc9, 0xc2, 0x34, 0x3c, 0xcc, 0x31, 0xca, 0xc1, 0xc0, 0xc3, 0x33, 0x3f, 0x3f, 0x3e, 0x3c, + 0xcc, 0x31, 0xcc, 0xc3, 0xc4, 0x32, 0xd1, 0x34, 0x3f, 0x3c, 0xcc, 0x31, 0xcc, 0xc3, 0x33, 0xd0, + 0x31, 0xd1, 0x35, 0x3f, 0x3e, 0x3c, 0xca, 0xc5, 0x34, 0xcc, 0xc2, 0xc3, 0xc3, 0xc5, 0x36, 0x40, + 0x3e, 0x41, 0x3e, 0x41, 0x3e, 0x3f, 0x41, 0x40, 0xce, 0xc5, 0x33, 0xcf, 0xc7, 0x36, 0xd2, 0x32, + 0xd1, 0xc5, 0xc6, 0x35, 0xd4, 0x32, 0xd1, 0xc6, 0x34, 0x41, 0xd2, 0x30, 0xd0, 0xc2, 0xc2, 0xc5, + 0x31, 0xd3, 0x31, 0xd1, 0xc7, 0x33, 0xd4, 0xc6, 0x34, 0x42, 0x40, 0x40, 0x40, 0x41, 0x41, 0xd2, + 0xc4, 0xc4, 0x39, 0x3e, 0xce, 0x35, 0x3c, 0xcd, 0x31, 0x3d, 0xc8, 0xc3, 0x32, 0x3d, 0xcc, 0x2f, + 0xce, 0x30, 0xd0, 0x2e, 0xcf, 0x30, 0x3d, 0x3c, 0x3c, 0x3a, 0xcb, 0xbf, 0xbf, 0xc1, 0x31, 0x3d, + 0x3d, 0x3c, 0x3c, 0x3c, 0x3d, 0x3b, 0xcf, 0x2e, 0xd2, 0x2e, 0xd0, 0x2c, 0x3b, 0xd1, 0x2a, 0xcf, + 0xbe, 0xc0, 0xc0, 0xbf, 0xc1, 0xc1, 0x2c, 0x3f, 0xd0, 0xc0, 0x2e, 0xd0, 0x31, 0xd2, 0xc2, 0x2f, + 0x3e, 0x3e, 0x3d, 0xcf, 0x31, 0xcb, 0xc3, 0x32, 0xd1, 0xc4, 0x37, 0x3f, 0xce, 0xc4, 0x35, 0xd0, + 0x33, 0x3f, 0xce, 0x31, 0x3c, 0x3b, 0xcc, 0x31, 0xcd, 0x2f, 0xd1, 0x32, 0x3a, 0x3b, 0xcb, 0xc1, + 0xc0, 0x32, 0x3e, 0x3e, 0x3c, 0x3d, 0x3d, 0xce, 0x2d, 0xcd, 0xc3, 0xc2, 0x30, 0x3d, 0xcf, 0xc1, + 0xc2, 0x30, 0xd0, 0xc4, 0x31, 0xd4, 0x30, 0x40, 0x3e, 0xd0, 0x2f, 0xd0, 0x2f, 0xd1, 0xc2, 0x2e, + 0xd4, 0x2e, 0x3f, 0xce, 0xc2, 0x34, 0x3e, 0x3f, 0xd0, 0x30, 0xcf, 0x31, 0x3d, 0x3d, 0xcc, 0x2d, + 0xcf, 0x2f, 0xcf, 0x2e, 0x3b, 0xcf, 0x2c, 0x3b, 0x3b, 0x3a, 0x3d, 0x38, 0xcc, 0x2d, 0x3b, 0xcc, + 0xbe, 0x2d, 0xd1, 0x2c, 0x3c, 0x3d, 0xce, 0xc0, 0x2d, 0xd1, 0x2f, 0x3f, 0x3f, 0x3c, 0x3f, 0x3e, + 0x3e, 0x3c, 0xd3, 0x2a, 0xd1, 0xc2, 0x2e, 0x3c, 0xd1, 0x2f, 0x3d, 0xd1, 0xbe, 0xc1, 0x2d, 0xd2, + 0x2d, 0x3d, 0x3d, 0x3b, 0xcd, 0x31, 0xcc, 0x31, 0xce, 0x2e, 0x3d, 0x3e, 0x3a, 0xcd, 0x2d, 0xcc, + 0xc1, 0xc1, 0xc3, 0x2e, 0x3f, 0x3f, 0x3c, 0xcf, 0xc0, 0x31, 0xd1, 0xc2, 0xc3, 0x33, 0xd2, 0xc7, + 0x32, 0x40, 0xd3, 0xc4, 0xc4, 0x33, 0x40, 0x40, 0xd2, 0x2f, 0xd0, 0x2f, 0x3c, 0xd1, 0x2c, 0x3a, + 0x3d, 0xd0, 0x2a, 0xd0, 0x28, 0xcf, 0xc3, 0x2c, 0xd2, 0x2d, 0xd3, 0xc3, 0xc3, 0x2e, 0x3e, 0x41, + 0xd2, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc4, 0x32, 0xd2, 0x34, 0x3e, 0x3e, 0x3c, 0xd1, 0x30, 0x3d, + 0x3c, 0xce, 0x2e, 0x3b, 0x38, 0xcb, 0xbe, 0xc1, 0x2e, 0x3e, 0x3c, 0x3d, 0xd1, 0x2c, 0x3b, 0x3b, + 0xcd, 0xbf, 0x2d, 0xd0, 0x2f, 0xd0, 0x2d, 0xd1, 0x2d, 0x3d, 0xd0, 0x2b, 0x3b, 0xcf, 0x2b, 0x3a, + 0xcc, 0xbc, 0xc1, 0x2a, 0x3c, 0xce, 0x28, 0xd1, 0x2a, 0x3c, 0x3a, 0xcf, 0xbf, 0x2b, 0x3e, 0x3c, + 0xd2, 0x2b, 0x3d, 0x3a, 0x3a, 0xcf, 0x2c, 0xcc, 0xbe, 0xc1, 0xc0, 0xbf, 0xc1, 0x31, 0x3c, 0xce, + 0xc0, 0xc1, 0xc0, 0xc1, 0x31, 0x3c, 0xd1, 0xc2, 0x2e, 0xd1, 0xc3, 0xc4, 0x30, 0x3f, 0xd3, 0x2c, + 0xd3, 0xc2, 0x30, 0xd5, 0xc3, 0xc5, 0x30, 0xd5, 0xc4, 0xc5, 0xc5, 0x31, 0x41, 0xd4, 0xc4, 0x31, + 0x40, 0xd4, 0x2d, 0xd5, 0xc0, 0xc3, 0x2c, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, 0xd6, 0x2c, 0x3e, 0xd2, + 0x27, 0x37, 0xde, 0xc9, 0xe9, 0x2e, 0xc7, 0x3c, 0xd9, 0x07, 0xf3, 0x28, 0x8d, 0xa5, 0xc9, 0xca, + 0xe7, 0xcb, 0xfc, 0xb3, 0x3c, 0xd4, 0xd3, 0x9a, 0xe7, 0x2c, 0xc8, 0xf8, 0x44, 0xb3, 0xb0, 0xfa, + 0x1c, 0xbf, 0xc9, 0xff, 0xbb, 0x1d, 0x02, 0xdb, 0x45, 0xc1, 0x40, 0x1c, 0xec, 0x48, 0xda, 0x21, + 0x4c, 0xe3, 0x38, 0xdf, 0x34, 0xd8, 0x35, 0xd8, 0x31, 0xd7, 0x30, 0xd4, 0x2f, 0xd6, 0x2d, 0xd5, + 0x2b, 0xd5, 0x33, 0xce, 0x33, 0xce, 0x33, 0xd0, 0x34, 0xcf, 0x31, 0xcf, 0x30, 0xce, 0x30, 0xcf, + 0x30, 0x3d, 0xce, 0x2f, 0xcf, 0xc2, 0x30, 0x3f, 0x3d, 0xcf, 0xc1, 0x31, 0xd0, 0xc5, 0xc4, 0x33, + 0x41, 0x3e, 0xd1, 0x30, 0x3c, 0x3d, 0xce, 0x2f, 0xce, 0xc1, 0xc3, 0x2e, 0xd3, 0x30, 0x3e, 0x3e, + 0x3c, 0x3f, 0x3c, 0xd1, 0xc0, 0xc0, 0xc0, 0xc1, 0xc2, 0xc0, 0xc1, 0xc3, 0x2c, 0x3f, 0xd2, 0xbe, + 0xc1, 0x2e, 0xcf, 0xc4, 0x33, 0xd3, 0x34, 0xd0, 0x33, 0x3d, 0xcf, 0xc3, 0x32, 0xce, 0x33, 0xd2, + 0x32, 0xce, 0xc5, 0x34, 0x40, 0xce, 0xc5, 0x32, 0x3e, 0xd0, 0x31, 0xd0, 0x2f, 0xd2, 0x30, 0xce, + 0xc2, 0x33, 0x40, 0x3e, 0xd0, 0xc3, 0xc2, 0x2e, 0xd3, 0x31, 0xd0, 0xc7, 0x32, 0x40, 0x3e, 0xd3, + 0x2f, 0xd3, 0x2e, 0xd0, 0x2d, 0xd3, 0x2d, 0xd3, 0x2f, 0x3c, 0x3d, 0xd1, 0x2a, 0x3b, 0xd1, 0x28, + 0x3b, 0x3b, 0xc8, 0x31, 0x39, 0x3b, 0x38, 0xc6, 0xbf, 0x31, 0x3d, 0x3a, 0xca, 0xc0, 0x33, 0x3c, + 0xca, 0xc0, 0xc1, 0xc1, 0xc2, 0x35, 0x3e, 0x3c, 0x3d, 0x3f, 0xcc, 0xc0, 0xc3, 0x31, 0xce, 0xc5, + 0x33, 0xd0, 0xc4, 0x35, 0xd3, 0x33, 0xd3, 0x32, 0xd1, 0xc4, 0xc3, 0x35, 0xd3, 0xc6, 0xc4, 0x35, + 0xd2, 0xc6, 0x35, 0x41, 0x41, 0xd4, 0x33, 0xd1, 0xc4, 0x30, 0x41, 0xd2, 0x30, 0x3e, 0xce, 0xc1, + 0xc3, 0xc0, 0x31, 0xce, 0xc5, 0x34, 0x40, 0x3d, 0xd1, 0xc4, 0x32, 0x3e, 0xcf, 0xc2, 0xc3, 0x30, + 0xd4, 0x32, 0x3e, 0x3f, 0x3e, 0x3f, 0x3e, 0xd0, 0xc2, 0x31, 0x3e, 0x3f, 0x3f, 0xd1, 0xc2, 0x2f, + 0xd5, 0x2e, 0xd3, 0xc3, 0x2f, 0xd7, 0x30, 0x3e, 0xd2, 0x2c, 0x3e, 0x3c, 0xd0, 0xc1, 0xc1, 0xc3, + 0xc0, 0xc3, 0x2c, 0xd4, 0xc2, 0x2e, 0x40, 0xd2, 0xc3, 0x2d, 0xd5, 0xc3, 0x2f, 0x42, 0x40, 0xd6, + 0x2d, 0xd4, 0xc2, 0xc2, 0xc2, 0x32, 0xd4, 0xc3, 0xc5, 0xc4, 0x32, 0x40, 0xd3, 0x30, 0xd0, 0xc3, + 0xc4, 0x30, 0xd3, 0xc5, 0xc5, 0xc4, 0xc4, 0x33, 0x40, 0x40, 0xd4, 0x2f, 0xd2, 0x2d, 0x3d, 0xd1, + 0xc1, 0xc2, 0x2c, 0xd4, 0x2e, 0xd4, 0x2d, 0x3d, 0xd3, 0xc1, 0xc1, 0xc1, 0x2d, 0xd5, 0xc2, 0xc2, + 0xc2, 0x2d, 0xd9, 0xc4, 0xc5, 0x2f, 0x43, 0x40, 0xd6, 0xd7, 0xd7, 0x2b, 0x3e, 0xd5, 0x29, 0x3d, + 0xd4, 0x24, 0x3b, 0x3a, 0x3b, 0xce, 0x2a, 0x3a, 0xcc, 0xbe, 0x2d, 0x3b, 0x3b, 0x3d, 0x3b, 0x3b, + 0xce, 0x2b, 0x3a, 0xcc, 0x2b, 0xd0, 0x2b, 0x3b, 0x3b, 0x39, 0xcf, 0xbf, 0x2a, 0xd1, 0xc0, 0x2f, + 0x3e, 0xd0, 0x2d, 0x3a, 0xd1, 0xbe, 0x2b, 0xd2, 0xc3, 0xc2, 0xc0, 0x2d, 0xd7, 0x2c, 0xd7, 0xc2, + 0xc3, 0x2f, 0x43, 0x41, 0x40, 0xd4, 0xc3, 0xc3, 0xc3, 0xc2, 0x2c, 0x40, 0xd7, 0x2a, 0x3d, 0xd3, + 0x26, 0xd5, 0x2f, 0x3a, 0x3c, 0xca, 0xc3, 0x2c, 0xd3, 0x2e, 0x3c, 0x3d, 0x3d, 0x3d, 0xd0, 0xc2, + 0x2e, 0xd3, 0x2e, 0xd1, 0xc5, 0x2e, 0x3f, 0xd3, 0x2e, 0x3c, 0xd1, 0xc0, 0xc2, 0x2a, 0xd2, 0xc2, + 0xc4, 0x2e, 0xd7, 0x2e, 0x3e, 0xd3, 0xc1, 0xc3, 0xc1, 0x2d, 0x3f, 0xd3, 0xc2, 0x2c, 0x3f, 0xd3, + 0x2b, 0x3b, 0xd1, 0xbf, 0xc1, 0xbe, 0x29, 0x3f, 0xd4, 0x29, 0xd5, 0xbf, 0x29, 0xd7, 0xc0, 0x2d, + 0xd8, 0xc2, 0x33, 0x41, 0xd3, 0x30, 0x3d, 0xd0, 0x2c, 0xcf, 0xc1, 0xc1, 0xc2, 0x2e, 0x3f, 0xd3, + 0x2b, 0xcf, 0xc3, 0x2f, 0x40, 0x3f, 0x3e, 0xd3, 0x2a, 0x3d, 0x3d, 0xce, 0xc1, 0x2b, 0x3d, 0xd0, + 0x2b, 0xd3, 0x2b, 0x3b, 0x3d, 0xce, 0x29, 0x3b, 0x3b, 0x3b, 0xd1, 0xbe, 0x2b, 0xd2, 0x29, 0x3d, + 0x3a, 0xd3, 0x29, 0x3a, 0x3b, 0x3b, 0xd2, 0x26, 0x3b, 0xd0, 0xbf, 0xbe, 0xbc, 0xbf, 0xbe, 0xbc, + 0x27, 0x3d, 0x3a, 0x3c, 0xce, 0xc1, 0x2c, 0xd2, 0xc2, 0xc2, 0x2f, 0x40, 0xd2, 0xc2, 0xc2, 0x2e, + 0x40, 0xd4, 0x2a, 0x3b, 0xcf, 0x2b, 0xd2, 0x2a, 0x3c, 0xd0, 0xc1, 0x2a, 0x3d, 0xd0, 0xc1, 0xc0, + 0xbe, 0x2b, 0x3f, 0x3e, 0xd2, 0xc1, 0xc0, 0xc1, 0xc0, 0xc2, 0x2a, 0xd6, 0xc2, 0xc3, 0xc3, 0xc3, + 0x2c, 0x3e, 0x41, 0xd6, 0xc0, 0xc3, 0xc2, 0xc2, 0x2a, 0xd9, 0x28, 0x3f, 0xd5, 0xc1, 0xc2, 0xc0, + 0xc3, 0x28, 0xd5, 0xc2, 0xc5, 0x30, 0xd6, 0xc4, 0xc5, 0xc5, 0x31, 0x43, 0xd4, 0xc3, 0xc5, 0xc2, + 0xc2, 0x2f, 0xd6, 0xc5, 0xc2, 0x2d, 0x41, 0x41, 0x43, 0x40, 0x41, 0xd8, 0x2a, 0x3f, 0x3f, 0x3e, + 0x2c, 0x0a, 0x0d, 0x2a, 0xbb, 0x91, 0x5e, 0x2a, 0xca, 0x23, 0xf0, 0x0f, 0xbe, 0xd6, 0xfb, 0xc0, + 0x2c, 0x34, 0x7f, 0xd1, 0xc9, 0xc1, 0x1c, 0x06, 0x97, 0x1f, 0x21, 0xa8, 0x04, 0x5d, 0x07, 0xb0, + 0x49, 0xaf, 0x10, 0x60, 0xd1, 0xf1, 0xf3, 0xcb, 0x72, 0x16, 0x24, 0xe9, 0xd4, 0x28, 0xb2, 0x8c, + 0xf3, 0x3b, 0xe8, 0x06, 0xeb, 0x09, 0xec, 0x0a, 0xec, 0x0b, 0xee, 0x0b, 0xee, 0x0b, 0xf0, 0x0b, + 0xf0, 0x0a, 0xf3, 0x0b, 0xf2, 0x0a, 0xf5, 0x08, 0xf5, 0x0a, 0xf4, 0x08, 0xf5, 0x08, 0xf5, 0x09, + 0xf4, 0x07, 0x3f, 0xf5, 0x05, 0xf6, 0xbf, 0x06, 0x3f, 0x3f, 0xf8, 0xbe, 0x07, 0xf8, 0xc3, 0xc3, + 0x06, 0x41, 0x40, 0xf0, 0x0f, 0x3c, 0x3d, 0xef, 0x0e, 0xee, 0xbe, 0xbf, 0x11, 0xf2, 0x0e, 0x3e, + 0x3c, 0x3f, 0x3e, 0x3e, 0xf0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc3, 0xc0, 0xc1, 0xc1, 0x0b, 0x3f, 0xf5, + 0xc0, 0xc0, 0x08, 0xf7, 0xc2, 0x0c, 0xf6, 0x0d, 0xf9, 0x0a, 0x3f, 0xf9, 0xc0, 0x0b, 0xf6, 0x06, + 0xf8, 0x06, 0xf9, 0xc3, 0x08, 0x40, 0xfa, 0xc2, 0x09, 0x3e, 0xf7, 0x05, 0xf6, 0x04, 0xf7, 0x05, + 0xf8, 0xc1, 0xc3, 0xc1, 0x0a, 0x3e, 0x41, 0xf6, 0x07, 0xf7, 0x08, 0xf6, 0x07, 0x3e, 0x3c, 0x3f, + 0xf4, 0xbf, 0xbe, 0x06, 0xf8, 0x07, 0xf8, 0x05, 0xfb, 0xc0, 0xc1, 0x02, 0x40, 0x40, 0x3e, 0xfb, + 0x02, 0x3e, 0x3e, 0xf6, 0x01, 0xf9, 0x00, 0x3f, 0xf8, 0xbd, 0x02, 0xfc, 0xc1, 0xc0, 0x03, 0xfe, + 0xc5, 0xc4, 0xc2, 0xc5, 0xc2, 0x02, 0x41, 0x40, 0x40, 0x41, 0x40, 0xff, 0xff, 0x40, 0xfd, 0xfd, + 0xfc, 0xfd, 0x3e, 0xfc, 0xbe, 0xbf, 0xfe, 0xfc, 0xc1, 0xc0, 0xc1, 0xc1, 0x00, 0x01, 0x01, 0x02, + 0xc0, 0x00, 0x02, 0xc3, 0xc5, 0x02, 0x07, 0xc4, 0xc6, 0xc4, 0x02, 0x06, 0xc3, 0x01, 0x43, 0x43, + 0x42, 0x05, 0xfc, 0x04, 0xfd, 0x41, 0x3e, 0x05, 0xbf, 0xfb, 0x41, 0x3e, 0x3e, 0x3f, 0x3f, 0x40, + 0x02, 0xf9, 0x3e, 0x03, 0xbf, 0xbe, 0xf6, 0x3f, 0x05, 0xf6, 0x3c, 0x05, 0xbd, 0xbf, 0xbe, 0xf2, + 0x3f, 0x3c, 0x3d, 0x3e, 0x08, 0xee, 0x3d, 0x3b, 0x07, 0xbd, 0xf3, 0x0e, 0xc0, 0xc0, 0xf2, 0x0f, + 0xf2, 0x40, 0x0d, 0xef, 0x3f, 0x3e, 0x0a, 0xbf, 0xf0, 0x0e, 0xf1, 0x40, 0x0a, 0xef, 0x0e, 0xc1, + 0xc0, 0xc1, 0xc2, 0xc0, 0xee, 0x13, 0xc1, 0xee, 0x43, 0x10, 0xea, 0x15, 0xc0, 0xc0, 0xc0, 0xc3, + 0xc0, 0xec, 0x15, 0xc2, 0xf0, 0x16, 0xc2, 0xef, 0x1b, 0xc2, 0xf1, 0x44, 0x42, 0x19, 0xc2, 0xc3, + 0xed, 0x17, 0xe7, 0x21, 0xe4, 0x40, 0x3f, 0x20, 0xc0, 0xe2, 0x40, 0x3e, 0x1d, 0xc1, 0xc2, 0xc0, + 0xe2, 0x20, 0xe2, 0x3f, 0x3f, 0x3e, 0x1c, 0xdf, 0x3c, 0x3f, 0x1e, 0xbf, 0xc1, 0xbe, 0xdf, 0x3e, + 0x3d, 0x1f, 0xdc, 0x3c, 0x3b, 0x3d, 0x3a, 0x3d, 0x1f, 0xdb, 0x1e, 0xda, 0x20, 0xda, 0x21, 0xc1, + 0xc0, 0xc1, 0xdc, 0x3e, 0x23, 0xda, 0x3e, 0x20, 0xbf, 0xbd, 0xdb, 0x23, 0xbf, 0xdf, 0x26, 0xdc, + 0x26, 0xdc, 0x2e, 0xc2, 0xc3, 0xc3, 0xd4, 0x40, 0x2f, 0xc2, 0xd2, 0x3f, 0x3f, 0x3f, 0x2e, 0xd1, + 0x2d, 0xd3, 0x2c, 0xc3, 0xc3, 0xc3, 0xc2, 0xc3, 0xc2, 0xd3, 0x3e, 0x31, 0xd0, 0x2d, 0xc3, 0xc0, + 0xc1, 0xd1, 0x2f, 0xd3, 0x3f, 0x3f, 0x31, 0xc1, 0xcf, 0x31, 0xd2, 0x3e, 0x3f, 0x3c, 0x41, 0x3e, + 0x3e, 0x3f, 0x31, 0xd1, 0x30, 0xc0, 0xcf, 0x33, 0xd1, 0x3d, 0x41, 0x32, 0xc0, 0xc3, 0xce, 0x3e, + 0x32, 0xc3, 0xc3, 0xc2, 0xc0, 0xc3, 0xca, 0x3c, 0x37, 0xc5, 0xc3, 0xca, 0x34, 0xcf, 0x35, 0xc6, + 0xca, 0x3c, 0x39, 0xce, 0x3c, 0x37, 0xc2, 0xc8, 0x3c, 0x36, 0xcc, 0x30, 0xcb, 0x33, 0xc6, 0xc3, + 0xc8, 0x34, 0xcc, 0x3d, 0x37, 0xc5, 0xc9, 0x38, 0xc6, 0xca, 0x3b, 0x40, 0x40, 0x40, 0x3a, 0xc5, + 0xc8, 0x3f, 0x3e, 0x3b, 0xce, 0x3a, 0x3e, 0x38, 0xca, 0x39, 0x3c, 0x3c, 0x36, 0xcb, 0x36, 0x3b, + 0x37, 0xc8, 0x35, 0x3a, 0x36, 0xc8, 0x2f, 0xc4, 0xc5, 0x36, 0x38, 0xc7, 0xc0, 0xc7, 0x33, 0xc8, + 0xc3, 0xc5, 0x39, 0x3b, 0xc9, 0xc7, 0x34, 0xd1, 0x34, 0xcf, 0x35, 0xca, 0xc9, 0x36, 0xd0, 0x36, + 0xcc, 0xc7, 0x39, 0x41, 0x42, 0x42, 0x3e, 0xca, 0xc1, 0xc3, 0xc3, 0xc2, 0xc3, 0xc2, 0xc4, 0xc6, + 0x34, 0xd1, 0x35, 0xcf, 0x37, 0x3c, 0xce, 0x35, 0x3b, 0xcc, 0x30, 0xca, 0x33, 0x39, 0xc9, 0xbf, + 0xbf, 0xbf, 0xc3, 0x34, 0x3c, 0x3f, 0x3a, 0xcc, 0x2f, 0xcd, 0x32, 0x3c, 0x3a, 0xc8, 0xc2, 0x34, + 0x3a, 0xcb, 0xc0, 0xc0, 0x35, 0x3c, 0xce, 0x32, 0x3c, 0x3c, 0x3d, 0x3a, 0xcd, 0x2e, 0x3b, 0x39, + 0xc9, 0xbc, 0xbf, 0x30, 0xcc, 0xc0, 0xc3, 0x33, 0xce, 0xc5, 0xc2, 0xc4, 0x36, 0x3e, 0xd1, 0xc3, + 0xc2, 0xc3, 0xc5, 0x33, 0xd0, 0xc5, 0xc4, 0x35, 0x40, 0x40, 0x3e, 0x41, 0x3e, 0xd2, 0x30, 0x3f, + 0x3e, 0x3d, 0x21, 0xc8, 0x0d, 0x23, 0xec, 0xb1, 0x1a, 0xf0, 0xf3, 0x10, 0xc6, 0xbd, 0x5b, 0x0d, + 0xff, 0xe2, 0xe6, 0xd4, 0x72, 0xe2, 0xda, 0x0c, 0xf8, 0x1b, 0x04, 0x0b, 0xf7, 0xb4, 0xf0, 0x44, + 0xcd, 0xaf, 0x12, 0x1f, 0x11, 0xa1, 0x29, 0xb8, 0x1a, 0xdb, 0x09, 0x69, 0xf7, 0x20, 0xc4, 0x1c, + 0xc0, 0xc8, 0x1d, 0x45, 0xd9, 0x30, 0xd8, 0x2e, 0xd8, 0x2e, 0xd6, 0x2c, 0xd5, 0x2d, 0xd4, 0x2b, + 0xd5, 0x2b, 0xd1, 0x31, 0xd0, 0x32, 0xd2, 0x30, 0xd0, 0x31, 0xd0, 0x31, 0xce, 0x2f, 0xd3, 0x2e, + 0xce, 0x2f, 0xd1, 0x31, 0x3c, 0xd1, 0x2d, 0xd0, 0xc0, 0x2e, 0x3c, 0x3d, 0xd1, 0xc3, 0x2c, 0xd2, + 0xc3, 0xc5, 0x31, 0x40, 0x40, 0xd5, 0x2c, 0x3a, 0x3d, 0xd0, 0x2b, 0xd3, 0xc0, 0xc0, 0x2d, 0xd4, + 0x2c, 0x3f, 0x3e, 0x3c, 0x3f, 0x3c, 0xd2, 0xc1, 0xc2, 0xc0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0x2a, +}; + + +void +ao_real_packet(void) +{ + uint8_t decode[64]; + uint8_t decode_len; + int off; + + for (off = 0; off < sizeof (real_packet) - 576; off++) { + decode_len = ao_fec_decode(real_packet+off, 576, decode); + + if (ao_fec_check_crc(decode, 32)) { + printf ("match at %d\n", off); + + ao_fec_dump_bytes(decode, decode_len, "Decode"); + } + } +} + int main(int argc, char **argv) { @@ -149,6 +299,7 @@ main(int argc, char **argv) int errors = 0; int error; + ao_real_packet(); exit(0); srandom(0); for (trial = 0; trial < 10000; trial++) { -- cgit v1.2.3 From 09761fe0f6ed40ff74317fbb47d6a74068fb4ce4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jun 2012 06:51:36 -0700 Subject: altos: Incremental viterbi decode Decode radio input one interleave block at a time. This overlaps the decode computation with the packet reception, leading to lower latency in an attempt to keep up with the transmitter. Signed-off-by: Keith Packard --- src/core/ao_fec.h | 4 +++- src/core/ao_viterbi.c | 14 +++++++++++++- src/drivers/ao_cc1120.c | 28 +++++++++++++++++++++------- src/test/ao_fec_test.c | 4 ++-- 4 files changed, 39 insertions(+), 11 deletions(-) (limited to 'src/test') diff --git a/src/core/ao_fec.h b/src/core/ao_fec.h index e3c55d6e..4fd398eb 100644 --- a/src/core/ao_fec.h +++ b/src/core/ao_fec.h @@ -66,8 +66,10 @@ ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out); * 'out' must be len/8 bytes long */ +#define AO_FEC_DECODE_BLOCK (8 * 32) /* callback must return multiples of this many bits */ + uint8_t -ao_fec_decode(uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len); +ao_fec_decode(uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()); /* * Interleave data packed in bytes. 'out' must be 'len' bytes long. diff --git a/src/core/ao_viterbi.c b/src/core/ao_viterbi.c index 77681556..69e9c1f5 100644 --- a/src/core/ao_viterbi.c +++ b/src/core/ao_viterbi.c @@ -91,7 +91,7 @@ ao_cost(struct ao_soft_sym a, struct ao_soft_sym b) */ uint8_t -ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len) +ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()) { static uint16_t cost[2][NUM_STATE]; /* path cost */ static uint16_t bits[2][NUM_STATE]; /* save bits to quickly output them */ @@ -105,6 +105,7 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len) const uint8_t *whiten = ao_fec_whiten_table; uint16_t interleave; /* input byte array index */ struct ao_soft_sym s; /* input symbol pair */ + uint16_t avail; p = 0; for (state = 0; state < NUM_STATE; state++) { @@ -113,11 +114,22 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len) } cost[0][0] = 0; + if (callback) + avail = 0; + else + avail = len; + o = 0; for (i = 0; i < len; i += 2) { b = i/2; n = p ^ 1; + if (!avail) { + avail = callback(); + if (!avail) + break; + } + /* Fetch one pair of input bytes, de-interleaving * the input. */ diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index b42ca54c..394cf7c5 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -400,6 +400,7 @@ ao_radio_send(void *d, uint8_t size) static uint8_t rx_data[2048]; static uint16_t rx_data_count; +static uint16_t rx_data_consumed; static uint16_t rx_data_cur; static uint8_t rx_ignore; @@ -408,9 +409,9 @@ ao_radio_rx_isr(void) { if (rx_ignore == 0) { rx_data[rx_data_cur++] = stm_spi2.dr; - if (rx_data_cur >= rx_data_count) { + if (rx_data_cur >= rx_data_count) ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); - ao_radio_wake = 1; + if (rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) { ao_wakeup(&ao_radio_wake); } } else { @@ -420,6 +421,19 @@ ao_radio_rx_isr(void) stm_spi2.dr = 0x00; } +static uint16_t +ao_radio_rx_wait(void) +{ + cli(); + while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK && + !ao_radio_abort) + ao_sleep(&ao_radio_wake); + sei(); + if (ao_radio_abort) + return 0; + return AO_FEC_DECODE_BLOCK; +} + uint8_t ao_radio_recv(__xdata void *d, uint8_t size) { @@ -433,6 +447,7 @@ ao_radio_recv(__xdata void *d, uint8_t size) len *= 2; /* 1/2 rate convolution */ rx_data_count = len * 8; /* bytes to bits */ rx_data_cur = 0; + rx_data_consumed = 0; rx_ignore = 2; printf ("len %d rx_data_count %d\n", len, rx_data_count); @@ -461,10 +476,9 @@ ao_radio_recv(__xdata void *d, uint8_t size) ao_radio_strobe(CC1120_SRX); ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT); - cli(); - while (!ao_radio_wake && !ao_radio_abort) - ao_sleep(&ao_radio_wake); - sei(); + + ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait); + ao_radio_burst_read_stop(); /* Convert from 'real' rssi to cc1111-style values */ @@ -477,7 +491,7 @@ ao_radio_recv(__xdata void *d, uint8_t size) /* Construct final packet */ - ao_fec_decode(rx_data, rx_data_cur, d, size + 2); + ao_fec_decode(rx_data, rx_data_cur, d, size + 2, 0); if (ao_fec_check_crc(d, size)) ((uint8_t *) d)[size + 1] = 0x80; diff --git a/src/test/ao_fec_test.c b/src/test/ao_fec_test.c index 98067486..e8d3d8b1 100644 --- a/src/test/ao_fec_test.c +++ b/src/test/ao_fec_test.c @@ -266,7 +266,7 @@ ao_real_packet(void) int off; for (off = 0; off < sizeof (real_packet) - 576; off++) { - decode_len = ao_fec_decode(real_packet+off, 576, decode); + decode_len = ao_fec_decode(real_packet+off, 576, decode, 34, NULL); if (ao_fec_check_crc(decode, 32)) { printf ("match at %d\n", off); @@ -317,7 +317,7 @@ main(int argc, char **argv) receive_len = transmit_len; /* Decode it */ - decode_len = ao_fec_decode(receive, receive_len, decode); + decode_len = ao_fec_decode(receive, receive_len, decode, original_len + 2, NULL); /* Check to see if we received the right data */ error = 0; -- cgit v1.2.3 From eab18714ed9eabbcef0ff81b07427da042a58ccc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Jun 2012 22:16:44 -0700 Subject: altos: rename ao_viterbi.c to ao_fec_rx.c Keep it parallel with ao_fec_tx.c Signed-off-by: Keith Packard --- src/core/ao_fec_rx.c | 226 +++++++++++++++++++++++++++++++++++++++++++ src/core/ao_viterbi.c | 226 ------------------------------------------- src/megametrum-v0.1/Makefile | 2 +- src/test/Makefile | 4 +- 4 files changed, 229 insertions(+), 229 deletions(-) create mode 100644 src/core/ao_fec_rx.c delete mode 100644 src/core/ao_viterbi.c (limited to 'src/test') diff --git a/src/core/ao_fec_rx.c b/src/core/ao_fec_rx.c new file mode 100644 index 00000000..69e9c1f5 --- /dev/null +++ b/src/core/ao_fec_rx.c @@ -0,0 +1,226 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 +#include + +/* + * byte order repeats through 3 2 1 0 + * + * bit-pair order repeats through + * + * 1/0 3/2 5/4 7/6 + * + * So, the over all order is: + * + * 3,1/0 2,1/0 1,1/0 0,1/0 + * 3,3/2 2,3/2 1,3/2 0,3/2 + * 3,5/4 2,5/4 1,5/4 0,5/4 + * 3,7/6 2,7/6 1,7/6 0,7/6 + * + * The raw bit order is thus + * + * 1e/1f 16/17 0e/0f 06/07 + * 1c/1d 14/15 0c/0d 04/05 + * 1a/1b 12/13 0a/0b 02/03 + * 18/19 10/11 08/09 00/01 + */ + +static inline uint16_t ao_interleave_index(uint16_t i) { + uint8_t l = i & 0x1e; + uint16_t h = i & ~0x1e; + uint8_t o = 0x1e ^ (((l >> 2) & 0x6) | ((l << 2) & 0x18)); + return h | o; +} + +struct ao_soft_sym { + uint8_t a, b; +}; + +#define NUM_STATE 8 +#define NUM_HIST 8 +#define MOD_HIST(b) ((b) & 7) + +#define V_0 0xc0 +#define V_1 0x40 + +static const struct ao_soft_sym ao_fec_decode_table[NUM_STATE][2] = { +/* next 0 1 state */ + { { V_0, V_0 }, { V_1, V_1 } } , /* 000 */ + { { V_0, V_1 }, { V_1, V_0 } }, /* 001 */ + { { V_1, V_1 }, { V_0, V_0 } }, /* 010 */ + { { V_1, V_0 }, { V_0, V_1 } }, /* 011 */ + { { V_1, V_1 }, { V_0, V_0 } }, /* 100 */ + { { V_1, V_0 }, { V_0, V_1 } }, /* 101 */ + { { V_0, V_0 }, { V_1, V_1 } }, /* 110 */ + { { V_0, V_1 }, { V_1, V_0 } } /* 111 */ +}; + +static inline uint8_t +ao_next_state(uint8_t state, uint8_t bit) +{ + return ((state << 1) | bit) & 0x7; +} + +static inline uint16_t ao_abs(int16_t x) { return x < 0 ? -x : x; } + +static inline uint16_t +ao_cost(struct ao_soft_sym a, struct ao_soft_sym b) +{ + return ao_abs(a.a - b.a) + ao_abs(a.b - b.b); +} + +/* + * 'in' is 8-bits per symbol soft decision data + * 'len' is input byte length. 'out' must be + * 'len'/16 bytes long + */ + +uint8_t +ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()) +{ + static uint16_t cost[2][NUM_STATE]; /* path cost */ + static uint16_t bits[2][NUM_STATE]; /* save bits to quickly output them */ + uint16_t i; /* input byte index */ + uint16_t b; /* encoded symbol index (bytes/2) */ + uint16_t o; /* output bit index */ + uint8_t p; /* previous cost/bits index */ + uint8_t n; /* next cost/bits index */ + uint8_t state; /* state index */ + uint8_t bit; /* original encoded bit index */ + const uint8_t *whiten = ao_fec_whiten_table; + uint16_t interleave; /* input byte array index */ + struct ao_soft_sym s; /* input symbol pair */ + uint16_t avail; + + p = 0; + for (state = 0; state < NUM_STATE; state++) { + cost[0][state] = 0xffff; + bits[0][state] = 0; + } + cost[0][0] = 0; + + if (callback) + avail = 0; + else + avail = len; + + o = 0; + for (i = 0; i < len; i += 2) { + b = i/2; + n = p ^ 1; + + if (!avail) { + avail = callback(); + if (!avail) + break; + } + + /* Fetch one pair of input bytes, de-interleaving + * the input. + */ + interleave = ao_interleave_index(i); + s.a = in[interleave]; + s.b = in[interleave+1]; + + /* Reset next costs to 'impossibly high' values so that + * the first path through this state is cheaper than this + */ + for (state = 0; state < NUM_STATE; state++) + cost[n][state] = 0xffff; + + /* Compute path costs and accumulate output bit path + * for each state and encoded bit value + */ + for (state = 0; state < NUM_STATE; state++) { + for (bit = 0; bit < 2; bit++) { + int bit_cost = cost[p][state] + ao_cost(s, ao_fec_decode_table[state][bit]); + uint8_t bit_state = ao_next_state(state, bit); + + /* Only track the minimal cost to reach + * this state; the best path can never + * go through the higher cost paths as + * total path cost is cumulative + */ + if (bit_cost < cost[n][bit_state]) { + cost[n][bit_state] = bit_cost; + bits[n][bit_state] = (bits[p][state] << 1) | (state & 1); + } + } + } + +#if 0 + printf ("bit %3d symbol %2x %2x:", i/2, s.a, s.b); + for (state = 0; state < NUM_STATE; state++) { + printf (" %5d(%04x)", cost[n][state], bits[n][state]); + } + printf ("\n"); +#endif + p = n; + + /* A loop is needed to handle the last output byte. It + * won't have any bits of future data to perform full + * error correction, but we might as well give the + * best possible answer anyways. + */ + while ((b - o) >= (8 + NUM_HIST) || (i + 2 >= len && b > o)) { + + /* Compute number of bits to the end of the + * last full byte of data. This is generally + * NUM_HIST, unless we've reached + * the end of the input, in which case + * it will be seven. + */ + int8_t dist = b - (o + 8); /* distance to last ready-for-writing bit */ + uint16_t min_cost; /* lowest cost */ + uint8_t min_state; /* lowest cost state */ + + /* Find the best fit at the current point + * of the decode. + */ + min_cost = cost[p][0]; + min_state = 0; + for (state = 1; state < NUM_STATE; state++) { + if (cost[p][state] < min_cost) { + min_cost = cost[p][state]; + min_state = state; + } + } + + /* The very last byte of data has the very last bit + * of data left in the state value; just smash the + * bits value in place and reset the 'dist' from + * -1 to 0 so that the full byte is read out + */ + if (dist < 0) { + bits[p][min_state] = (bits[p][min_state] << 1) | (min_state & 1); + dist = 0; + } + +#if 0 + printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x whiten %0x\n", + i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten); +#endif + if (out_len) { + *out++ = (bits[p][min_state] >> dist) ^ *whiten++; + --out_len; + } + o += 8; + } + } + return len/16; +} diff --git a/src/core/ao_viterbi.c b/src/core/ao_viterbi.c deleted file mode 100644 index 69e9c1f5..00000000 --- a/src/core/ao_viterbi.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright © 2012 Keith Packard - * - * 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 -#include - -/* - * byte order repeats through 3 2 1 0 - * - * bit-pair order repeats through - * - * 1/0 3/2 5/4 7/6 - * - * So, the over all order is: - * - * 3,1/0 2,1/0 1,1/0 0,1/0 - * 3,3/2 2,3/2 1,3/2 0,3/2 - * 3,5/4 2,5/4 1,5/4 0,5/4 - * 3,7/6 2,7/6 1,7/6 0,7/6 - * - * The raw bit order is thus - * - * 1e/1f 16/17 0e/0f 06/07 - * 1c/1d 14/15 0c/0d 04/05 - * 1a/1b 12/13 0a/0b 02/03 - * 18/19 10/11 08/09 00/01 - */ - -static inline uint16_t ao_interleave_index(uint16_t i) { - uint8_t l = i & 0x1e; - uint16_t h = i & ~0x1e; - uint8_t o = 0x1e ^ (((l >> 2) & 0x6) | ((l << 2) & 0x18)); - return h | o; -} - -struct ao_soft_sym { - uint8_t a, b; -}; - -#define NUM_STATE 8 -#define NUM_HIST 8 -#define MOD_HIST(b) ((b) & 7) - -#define V_0 0xc0 -#define V_1 0x40 - -static const struct ao_soft_sym ao_fec_decode_table[NUM_STATE][2] = { -/* next 0 1 state */ - { { V_0, V_0 }, { V_1, V_1 } } , /* 000 */ - { { V_0, V_1 }, { V_1, V_0 } }, /* 001 */ - { { V_1, V_1 }, { V_0, V_0 } }, /* 010 */ - { { V_1, V_0 }, { V_0, V_1 } }, /* 011 */ - { { V_1, V_1 }, { V_0, V_0 } }, /* 100 */ - { { V_1, V_0 }, { V_0, V_1 } }, /* 101 */ - { { V_0, V_0 }, { V_1, V_1 } }, /* 110 */ - { { V_0, V_1 }, { V_1, V_0 } } /* 111 */ -}; - -static inline uint8_t -ao_next_state(uint8_t state, uint8_t bit) -{ - return ((state << 1) | bit) & 0x7; -} - -static inline uint16_t ao_abs(int16_t x) { return x < 0 ? -x : x; } - -static inline uint16_t -ao_cost(struct ao_soft_sym a, struct ao_soft_sym b) -{ - return ao_abs(a.a - b.a) + ao_abs(a.b - b.b); -} - -/* - * 'in' is 8-bits per symbol soft decision data - * 'len' is input byte length. 'out' must be - * 'len'/16 bytes long - */ - -uint8_t -ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()) -{ - static uint16_t cost[2][NUM_STATE]; /* path cost */ - static uint16_t bits[2][NUM_STATE]; /* save bits to quickly output them */ - uint16_t i; /* input byte index */ - uint16_t b; /* encoded symbol index (bytes/2) */ - uint16_t o; /* output bit index */ - uint8_t p; /* previous cost/bits index */ - uint8_t n; /* next cost/bits index */ - uint8_t state; /* state index */ - uint8_t bit; /* original encoded bit index */ - const uint8_t *whiten = ao_fec_whiten_table; - uint16_t interleave; /* input byte array index */ - struct ao_soft_sym s; /* input symbol pair */ - uint16_t avail; - - p = 0; - for (state = 0; state < NUM_STATE; state++) { - cost[0][state] = 0xffff; - bits[0][state] = 0; - } - cost[0][0] = 0; - - if (callback) - avail = 0; - else - avail = len; - - o = 0; - for (i = 0; i < len; i += 2) { - b = i/2; - n = p ^ 1; - - if (!avail) { - avail = callback(); - if (!avail) - break; - } - - /* Fetch one pair of input bytes, de-interleaving - * the input. - */ - interleave = ao_interleave_index(i); - s.a = in[interleave]; - s.b = in[interleave+1]; - - /* Reset next costs to 'impossibly high' values so that - * the first path through this state is cheaper than this - */ - for (state = 0; state < NUM_STATE; state++) - cost[n][state] = 0xffff; - - /* Compute path costs and accumulate output bit path - * for each state and encoded bit value - */ - for (state = 0; state < NUM_STATE; state++) { - for (bit = 0; bit < 2; bit++) { - int bit_cost = cost[p][state] + ao_cost(s, ao_fec_decode_table[state][bit]); - uint8_t bit_state = ao_next_state(state, bit); - - /* Only track the minimal cost to reach - * this state; the best path can never - * go through the higher cost paths as - * total path cost is cumulative - */ - if (bit_cost < cost[n][bit_state]) { - cost[n][bit_state] = bit_cost; - bits[n][bit_state] = (bits[p][state] << 1) | (state & 1); - } - } - } - -#if 0 - printf ("bit %3d symbol %2x %2x:", i/2, s.a, s.b); - for (state = 0; state < NUM_STATE; state++) { - printf (" %5d(%04x)", cost[n][state], bits[n][state]); - } - printf ("\n"); -#endif - p = n; - - /* A loop is needed to handle the last output byte. It - * won't have any bits of future data to perform full - * error correction, but we might as well give the - * best possible answer anyways. - */ - while ((b - o) >= (8 + NUM_HIST) || (i + 2 >= len && b > o)) { - - /* Compute number of bits to the end of the - * last full byte of data. This is generally - * NUM_HIST, unless we've reached - * the end of the input, in which case - * it will be seven. - */ - int8_t dist = b - (o + 8); /* distance to last ready-for-writing bit */ - uint16_t min_cost; /* lowest cost */ - uint8_t min_state; /* lowest cost state */ - - /* Find the best fit at the current point - * of the decode. - */ - min_cost = cost[p][0]; - min_state = 0; - for (state = 1; state < NUM_STATE; state++) { - if (cost[p][state] < min_cost) { - min_cost = cost[p][state]; - min_state = state; - } - } - - /* The very last byte of data has the very last bit - * of data left in the state value; just smash the - * bits value in place and reset the 'dist' from - * -1 to 0 so that the full byte is read out - */ - if (dist < 0) { - bits[p][min_state] = (bits[p][min_state] << 1) | (min_state & 1); - dist = 0; - } - -#if 0 - printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x whiten %0x\n", - i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten); -#endif - if (out_len) { - *out++ = (bits[p][min_state] >> dist) ^ *whiten++; - --out_len; - } - o += 8; - } - } - return len/16; -} diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index 857667b0..22a58ff4 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -48,7 +48,7 @@ ALTOS_SRC = \ ao_spi_stm.c \ ao_cc1120.c \ ao_fec_tx.c \ - ao_viterbi.c \ + ao_fec_rx.c \ ao_ms5607.c \ ao_adc_stm.c \ ao_beep_stm.c \ diff --git a/src/test/Makefile b/src/test/Makefile index cdcecd51..4631fb78 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -40,5 +40,5 @@ ao_convert_pa_test: ao_convert_pa_test.c ao_convert_pa.c altitude-pa.h ao_kalman.h: $(KALMAN) (cd .. && make ao_kalman.h) -ao_fec_test: ao_fec_test.c ao_fec_tx.c ao_viterbi.c - cc $(CFLAGS) -o $@ ao_fec_test.c ../core/ao_fec_tx.c ../core/ao_viterbi.c -lm +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 -- cgit v1.2.3 From f1ae622eff60e05c1f5d8f822a3cf6a85750c6cc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Jun 2012 23:11:10 -0700 Subject: altos: Optimize FEC encode and decode Integrate interleaving, CRC and padding within the decode/encode functions. Provide for ISR priorities so that the 1120 RX interrupt takes precedence over the other interrupts or we risk losing bits. Optimize the viterbi decoder a bit (goes from 10ms per packet to 7ms per packet). Signed-off-by: Keith Packard --- src/core/ao_fec.h | 46 ++-- src/core/ao_fec_rx.c | 145 ++++++++----- src/core/ao_fec_tx.c | 68 +----- src/drivers/ao_cc1120.c | 483 ++++++++++++++++++++++++++--------------- src/drivers/ao_cc1120.h | 9 + src/drivers/ao_cc1120_CC1120.h | 27 ++- src/stm/ao_arch.h | 23 +- src/stm/ao_exti.h | 3 + src/stm/ao_exti_stm.c | 73 ++++--- src/stm/ao_spi_stm.c | 6 +- src/stm/ao_timer.c | 2 +- src/test/ao_fec_test.c | 39 ++-- 12 files changed, 560 insertions(+), 364 deletions(-) (limited to 'src/test') diff --git a/src/core/ao_fec.h b/src/core/ao_fec.h index 4fd398eb..f1192b62 100644 --- a/src/core/ao_fec.h +++ b/src/core/ao_fec.h @@ -26,11 +26,28 @@ extern const uint8_t ao_fec_whiten_table[]; +#if AO_FEC_DEBUG void -ao_fec_dump_bytes(uint8_t *bytes, uint16_t len, char *name); +ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name); +#endif + +static uint16_t inline +ao_fec_crc_byte(uint8_t byte, uint16_t crc) +{ + uint8_t bit; + + for (bit = 0; bit < 8; bit++) { + if (((crc & 0x8000) >> 8) ^ (byte & 0x80)) + crc = (crc << 1) ^ 0x8005; + else + crc = (crc << 1); + byte <<= 1; + } + return crc; +} uint16_t -ao_fec_crc(uint8_t *bytes, uint8_t len); +ao_fec_crc(const uint8_t *bytes, uint8_t len); /* * 'len' is the length of the original data; 'bytes' @@ -38,38 +55,23 @@ ao_fec_crc(uint8_t *bytes, uint8_t len); * two after 'len' must be the received crc */ uint8_t -ao_fec_check_crc(uint8_t *bytes, uint8_t len); - -/* - * Append CRC and terminator bytes, returns resulting length. - * 'out' must be at least len + AO_FEC_PREPARE_EXTRA bytes long - */ -uint8_t -ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *out); - -/* - * Whiten data using the cc1111 PN9 sequence. 'out' - * must be 'len' bytes long. 'out' and 'in' can be - * the same array - */ -void -ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out); +ao_fec_check_crc(const uint8_t *bytes, uint8_t len); /* - * Encode and interleave data. 'out' must be len*2 bytes long + * Compute CRC, whiten, convolve and interleave data. 'out' must be (len + 4) * 2 bytes long */ uint8_t -ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out); +ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out); /* * Decode data. 'in' is one byte per bit, soft decision * 'out' must be len/8 bytes long */ -#define AO_FEC_DECODE_BLOCK (8 * 32) /* callback must return multiples of this many bits */ +#define AO_FEC_DECODE_BLOCK (32) /* callback must return multiples of this many bits */ uint8_t -ao_fec_decode(uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()); +ao_fec_decode(const uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()); /* * Interleave data packed in bytes. 'out' must be 'len' bytes long. diff --git a/src/core/ao_fec_rx.c b/src/core/ao_fec_rx.c index 69e9c1f5..0d400bb0 100644 --- a/src/core/ao_fec_rx.c +++ b/src/core/ao_fec_rx.c @@ -18,6 +18,16 @@ #include #include +#ifdef MEGAMETRUM +#include +#endif + +#if AO_PROFILE +#include + +uint32_t ao_fec_decode_start, ao_fec_decode_end; +#endif + /* * byte order repeats through 3 2 1 0 * @@ -40,34 +50,35 @@ * 18/19 10/11 08/09 00/01 */ +static const uint8_t ao_interleave_order[] = { + 0x1e, 0x16, 0x0e, 0x06, + 0x1c, 0x14, 0x0c, 0x04, + 0x1a, 0x12, 0x0a, 0x02, + 0x18, 0x10, 0x08, 0x00 +}; + static inline uint16_t ao_interleave_index(uint16_t i) { - uint8_t l = i & 0x1e; - uint16_t h = i & ~0x1e; - uint8_t o = 0x1e ^ (((l >> 2) & 0x6) | ((l << 2) & 0x18)); - return h | o; + return (i & ~0x1e) | ao_interleave_order[(i & 0x1e) >> 1]; } -struct ao_soft_sym { - uint8_t a, b; -}; - #define NUM_STATE 8 #define NUM_HIST 8 -#define MOD_HIST(b) ((b) & 7) - -#define V_0 0xc0 -#define V_1 0x40 - -static const struct ao_soft_sym ao_fec_decode_table[NUM_STATE][2] = { -/* next 0 1 state */ - { { V_0, V_0 }, { V_1, V_1 } } , /* 000 */ - { { V_0, V_1 }, { V_1, V_0 } }, /* 001 */ - { { V_1, V_1 }, { V_0, V_0 } }, /* 010 */ - { { V_1, V_0 }, { V_0, V_1 } }, /* 011 */ - { { V_1, V_1 }, { V_0, V_0 } }, /* 100 */ - { { V_1, V_0 }, { V_0, V_1 } }, /* 101 */ - { { V_0, V_0 }, { V_1, V_1 } }, /* 110 */ - { { V_0, V_1 }, { V_1, V_0 } } /* 111 */ + +#define V_0 0xff +#define V_1 0x00 + +/* + * These are just the 'zero' states; the 'one' states mirror them + */ +static const uint8_t ao_fec_decode_table[NUM_STATE*2] = { + V_0, V_0, /* 000 */ + V_0, V_1, /* 001 */ + V_1, V_1, /* 010 */ + V_1, V_0, /* 011 */ + V_1, V_1, /* 100 */ + V_1, V_0, /* 101 */ + V_0, V_0, /* 110 */ + V_0, V_1 /* 111 */ }; static inline uint8_t @@ -76,14 +87,6 @@ ao_next_state(uint8_t state, uint8_t bit) return ((state << 1) | bit) & 0x7; } -static inline uint16_t ao_abs(int16_t x) { return x < 0 ? -x : x; } - -static inline uint16_t -ao_cost(struct ao_soft_sym a, struct ao_soft_sym b) -{ - return ao_abs(a.a - b.a) + ao_abs(a.b - b.b); -} - /* * 'in' is 8-bits per symbol soft decision data * 'len' is input byte length. 'out' must be @@ -91,25 +94,29 @@ ao_cost(struct ao_soft_sym a, struct ao_soft_sym b) */ uint8_t -ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()) +ao_fec_decode(const uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()) { - static uint16_t cost[2][NUM_STATE]; /* path cost */ + static uint32_t cost[2][NUM_STATE]; /* path cost */ static uint16_t bits[2][NUM_STATE]; /* save bits to quickly output them */ + uint16_t i; /* input byte index */ uint16_t b; /* encoded symbol index (bytes/2) */ uint16_t o; /* output bit index */ uint8_t p; /* previous cost/bits index */ uint8_t n; /* next cost/bits index */ uint8_t state; /* state index */ - uint8_t bit; /* original encoded bit index */ const uint8_t *whiten = ao_fec_whiten_table; uint16_t interleave; /* input byte array index */ - struct ao_soft_sym s; /* input symbol pair */ + uint8_t s0, s1; uint16_t avail; + uint16_t crc = AO_FEC_CRC_INIT; +#if AO_PROFILE + uint32_t start_tick; +#endif p = 0; for (state = 0; state < NUM_STATE; state++) { - cost[0][state] = 0xffff; + cost[0][state] = 0x7fffffff; bits[0][state] = 0; } cost[0][0] = 0; @@ -119,6 +126,14 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t else avail = len; +#if AO_PROFILE + if (!avail) { + avail = callback(); + if (!avail) + return 0; + } + start_tick = ao_profile_tick(); +#endif o = 0; for (i = 0; i < len; i += 2) { b = i/2; @@ -127,44 +142,52 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t if (!avail) { avail = callback(); if (!avail) - break; + return 0; } /* Fetch one pair of input bytes, de-interleaving * the input. */ interleave = ao_interleave_index(i); - s.a = in[interleave]; - s.b = in[interleave+1]; + s0 = in[interleave]; + s1 = in[interleave+1]; + + avail -= 2; /* Reset next costs to 'impossibly high' values so that * the first path through this state is cheaper than this */ for (state = 0; state < NUM_STATE; state++) - cost[n][state] = 0xffff; + cost[n][state] = 0x7fffffff; /* Compute path costs and accumulate output bit path * for each state and encoded bit value */ for (state = 0; state < NUM_STATE; state++) { - for (bit = 0; bit < 2; bit++) { - int bit_cost = cost[p][state] + ao_cost(s, ao_fec_decode_table[state][bit]); - uint8_t bit_state = ao_next_state(state, bit); - - /* Only track the minimal cost to reach - * this state; the best path can never - * go through the higher cost paths as - * total path cost is cumulative - */ - if (bit_cost < cost[n][bit_state]) { - cost[n][bit_state] = bit_cost; - bits[n][bit_state] = (bits[p][state] << 1) | (state & 1); + uint32_t bitcost = ((uint32_t) (s0 ^ ao_fec_decode_table[(state<<1)]) + + (uint32_t) (s1 ^ ao_fec_decode_table[(state<<1)+1])); + { + uint32_t cost0 = cost[p][state] + bitcost; + uint8_t state0 = ao_next_state(state, 0); + + if (cost0 < cost[n][state0]) { + cost[n][state0] = cost0; + bits[n][state0] = (bits[p][state] << 1) | (state & 1); + } + } + { + uint32_t cost1 = cost[p][state] + 510 - bitcost; + uint8_t state1 = ao_next_state(state, 1); + + if (cost1 < cost[n][state1]) { + cost[n][state1] = cost1; + bits[n][state1] = (bits[p][state] << 1) | (state & 1); } } } #if 0 - printf ("bit %3d symbol %2x %2x:", i/2, s.a, s.b); + printf ("bit %3d symbol %2x %2x:", i/2, s0, s1); for (state = 0; state < NUM_STATE; state++) { printf (" %5d(%04x)", cost[n][state], bits[n][state]); } @@ -186,7 +209,7 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t * it will be seven. */ int8_t dist = b - (o + 8); /* distance to last ready-for-writing bit */ - uint16_t min_cost; /* lowest cost */ + uint32_t min_cost; /* lowest cost */ uint8_t min_state; /* lowest cost state */ /* Find the best fit at the current point @@ -216,11 +239,23 @@ ao_fec_decode(uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten); #endif if (out_len) { - *out++ = (bits[p][min_state] >> dist) ^ *whiten++; + uint8_t byte = (bits[p][min_state] >> dist) ^ *whiten++; + + if (out_len > 2) { + crc = ao_fec_crc_byte(byte, crc); + *out++ = byte; + } else { + *out++ = byte ^ (crc >> 8); + crc <<= 8; + } --out_len; } o += 8; } } +#if AO_PROFILE + ao_fec_decode_start = start_tick; + ao_fec_decode_end = ao_profile_tick(); +#endif return len/16; } diff --git a/src/core/ao_fec_tx.c b/src/core/ao_fec_tx.c index c9c0a3d6..4941d745 100644 --- a/src/core/ao_fec_tx.c +++ b/src/core/ao_fec_tx.c @@ -18,8 +18,9 @@ #include #include +#if AO_FEC_DEBUG void -ao_fec_dump_bytes(uint8_t *bytes, uint16_t len, char *name) +ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name) { uint16_t i; @@ -31,29 +32,15 @@ ao_fec_dump_bytes(uint8_t *bytes, uint16_t len, char *name) } printf ("\n"); } - -static uint16_t inline -crc_byte(uint8_t byte, uint16_t crc) -{ - uint8_t bit; - - for (bit = 0; bit < 8; bit++) { - if (((crc & 0x8000) >> 8) ^ (byte & 0x80)) - crc = (crc << 1) ^ 0x8005; - else - crc = (crc << 1); - byte <<= 1; - } - return crc; -} +#endif uint16_t -ao_fec_crc(uint8_t *bytes, uint8_t len) +ao_fec_crc(const uint8_t *bytes, uint8_t len) { uint16_t crc = AO_FEC_CRC_INIT; while (len--) - crc = crc_byte(*bytes++, crc); + crc = ao_fec_crc_byte(*bytes++, crc); return crc; } @@ -63,7 +50,7 @@ ao_fec_crc(uint8_t *bytes, uint8_t len) */ uint8_t -ao_fec_check_crc(uint8_t *bytes, uint8_t len) +ao_fec_check_crc(const uint8_t *bytes, uint8_t len) { uint16_t computed_crc = ao_fec_crc(bytes, len); uint16_t received_crc = (bytes[len] << 8) | (bytes[len+1]); @@ -71,8 +58,11 @@ ao_fec_check_crc(uint8_t *bytes, uint8_t len) return computed_crc == received_crc; } -uint8_t -ao_fec_prepare(uint8_t *in, uint8_t len, uint8_t *extra) +/* + * Compute CRC and trellis-terminator/interleave-pad bytes + */ +static uint8_t +ao_fec_prepare(const uint8_t *in, uint8_t len, uint8_t *extra) { uint16_t crc = ao_fec_crc (in, len); uint8_t i = 0; @@ -93,40 +83,6 @@ const uint8_t ao_fec_whiten_table[] = { #include "ao_whiten.h" }; -#if 0 -void -ao_fec_whiten(uint8_t *in, uint8_t len, uint8_t *out) -{ - const uint8_t *w = ao_fec_whiten_table; - - while (len--) - *out++ = *in++ ^ *w++; -} - -/* - * Unused as interleaving is now built in to ao_fec_encode - */ - -static void -ao_fec_interleave(uint8_t *d, uint8_t len) -{ - uint8_t i, j; - - for (i = 0; i < len; i += 4) { - uint32_t interleaved = 0; - - for (j = 0; j < 4 * 4; j++) { - interleaved <<= 2; - interleaved |= (d[i + (~j & 0x3)] >> (2 * ((j & 0xc) >> 2))) & 0x03; - } - d[i+0] = interleaved >> 24; - d[i+1] = interleaved >> 16; - d[i+2] = interleaved >> 8; - d[i+3] = interleaved; - } -} -#endif - static const uint8_t ao_fec_encode_table[16] = { /* next 0 1 state */ 0, 3, /* 000 */ @@ -140,7 +96,7 @@ static const uint8_t ao_fec_encode_table[16] = { }; uint8_t -ao_fec_encode(uint8_t *in, uint8_t len, uint8_t *out) +ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out) { uint8_t extra[AO_FEC_PREPARE_EXTRA]; uint8_t extra_len; diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 394cf7c5..501b9370 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -24,8 +24,9 @@ uint8_t ao_radio_wake; uint8_t ao_radio_mutex; uint8_t ao_radio_abort; +uint8_t ao_radio_in_recv; -#define CC1120_DEBUG 1 +#define CC1120_DEBUG AO_FEC_DEBUG #define CC1120_TRACE 0 #if CC1120_TRACE @@ -34,7 +35,7 @@ uint8_t ao_radio_abort; #define fec_dump_bytes(b,l,n) #endif -uint32_t ao_radio_cal = 0x6ca333; +const uint32_t ao_radio_cal = 0x6ca333; #define FOSC 32000000 @@ -194,6 +195,12 @@ ao_radio_fifo_write_fixed(uint8_t data, uint8_t len) return status; } +static uint8_t +ao_radio_tx_fifo_space(void) +{ + return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES); +} + static uint8_t ao_radio_status(void) { @@ -209,6 +216,97 @@ ao_radio_recv_abort(void) #define ao_radio_rdf_value 0x55 +static uint8_t +ao_radio_marc_status(void) +{ + return ao_radio_reg_read(CC1120_MARC_STATUS1); +} + +static void +ao_radio_tx_isr(void) +{ + ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_wake = 1; + ao_wakeup(&ao_radio_wake); +} + +static void +ao_radio_start_tx(void) +{ + ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr); + ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_strobe(CC1120_STX); +} + +static void +ao_radio_idle(void) +{ + for (;;) { + uint8_t state = ao_radio_strobe(CC1120_SIDLE); + if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE) + break; + } +} + +/* + * Packet deviation is 20.5kHz + * + * fdev = fosc >> 24 * (256 + dev_m) << dev_e + * + * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz + */ + +#define PACKET_DEV_E 5 +#define PACKET_DEV_M 80 + +/* + * For our packet data, set the symbol rate to 38360 Baud + * + * (2**20 + DATARATE_M) * 2 ** DATARATE_E + * Rdata = -------------------------------------- * fosc + * 2 ** 39 + * + * + * DATARATE_M = 239914 + * DATARATE_E = 9 + */ +#define PACKET_DRATE_E 9 +#define PACKET_DRATE_M 239914 + +static const uint16_t packet_setup[] = { + CC1120_DEVIATION_M, PACKET_DEV_M, + CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) | + (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) | + (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)), + CC1120_DRATE2, ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) | + (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)), + CC1120_DRATE1, ((PACKET_DRATE_M >> 8) & 0xff), + CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff), + CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | + (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)), + CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) | + (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) | + (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) | + (0 << CC1120_PKT_CFG1_APPEND_STATUS)), + CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) | + (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | + (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | + (0 << CC1120_PKT_CFG0_UART_MODE_EN) | + (0 << CC1120_PKT_CFG0_UART_SWAP_EN)), +}; + +static const uint16_t packet_tx_setup[] = { + CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | + (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)), + CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG, +}; + +static const uint16_t packet_rx_setup[] = { + CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | + (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)), + CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT, +}; + /* * RDF deviation is 5kHz * @@ -259,50 +357,111 @@ static const uint16_t rdf_setup[] = { (0 << CC1120_PKT_CFG0_UART_SWAP_EN)), }; -static uint8_t -ao_radio_marc_status(void) -{ - return ao_radio_reg_read(CC1120_MARC_STATUS1); -} +static uint8_t ao_radio_mode; -static uint8_t -ao_radio_tx_done(void) -{ - return ao_radio_marc_status() == CC1120_MARC_STATUS1_TX_FINISHED; -} +#define AO_RADIO_MODE_BITS_PACKET 1 +#define AO_RADIO_MODE_BITS_PACKET_TX 2 +#define AO_RADIO_MODE_BITS_TX_BUF 4 +#define AO_RADIO_MODE_BITS_TX_FINISH 8 +#define AO_RADIO_MODE_BITS_PACKET_RX 16 +#define AO_RADIO_MODE_BITS_RDF 32 -static uint8_t -ao_radio_rx_done(void) +#define AO_RADIO_MODE_NONE 0 +#define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH) +#define AO_RADIO_MODE_PACKET_RX (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX) +#define AO_RADIO_MODE_RDF (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH) + +static void +ao_radio_set_mode(uint8_t new_mode) { - return ao_radio_marc_status() == CC1120_MARC_STATUS1_RX_FINISHED; + uint8_t changes; + int i; + + if (new_mode == ao_radio_mode) + return; + + changes = new_mode & (~ao_radio_mode); + if (changes & AO_RADIO_MODE_BITS_PACKET) + for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2) + ao_radio_reg_write(packet_setup[i], packet_setup[i+1]); + + if (changes & AO_RADIO_MODE_BITS_PACKET_TX) + for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2) + ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]); + + if (changes & AO_RADIO_MODE_BITS_TX_BUF) + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR); + + if (changes & AO_RADIO_MODE_BITS_TX_FINISH) + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); + + if (changes & AO_RADIO_MODE_BITS_PACKET_RX) + for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2) + ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]); + + if (changes & AO_RADIO_MODE_BITS_RDF) + for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) + ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]); + ao_radio_mode = new_mode; } +static const uint16_t radio_setup[] = { +#include "ao_cc1120_CC1120.h" +}; + +static uint8_t ao_radio_configured = 0; + static void -ao_radio_tx_isr(void) +ao_radio_setup(void) { - ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); - ao_radio_wake = 1; - ao_wakeup(&ao_radio_wake); + int i; + + ao_radio_strobe(CC1120_SRES); + + for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) + ao_radio_reg_write(radio_setup[i], radio_setup[i+1]); + + ao_radio_mode = 0; + + ao_config_get(); + + ao_radio_configured = 1; } static void -ao_radio_start_tx(void) +ao_radio_get(uint8_t len) { - ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); - ao_exti_set_callback(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr); - ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); - ao_radio_strobe(CC1120_STX); + static uint32_t last_radio_setting; + static uint8_t last_len; + + ao_mutex_get(&ao_radio_mutex); + if (!ao_radio_configured) + ao_radio_setup(); + if (ao_config.radio_setting != last_radio_setting) { + ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16); + ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8); + ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting); + last_radio_setting = ao_config.radio_setting; + } + if (len != last_len) { + ao_radio_reg_write(CC1120_PKT_LEN, len); + last_len = len; + } } +#define ao_radio_put() ao_mutex_put(&ao_radio_mutex) + void ao_radio_rdf(uint8_t len) { int i; + ao_radio_abort = 0; ao_radio_get(len); + + ao_radio_set_mode(AO_RADIO_MODE_RDF); ao_radio_wake = 0; - for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) - ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]); ao_radio_fifo_write_fixed(ao_radio_rdf_value, len); @@ -311,11 +470,9 @@ ao_radio_rdf(uint8_t len) cli(); while (!ao_radio_wake && !ao_radio_abort) ao_sleep(&ao_radio_wake); - sei(); - if (!ao_radio_tx_done()) + if (!ao_radio_wake) ao_radio_idle(); - ao_radio_set_packet(); ao_radio_put(); } @@ -372,65 +529,113 @@ ao_radio_test(void) } void -ao_radio_send(void *d, uint8_t size) +ao_radio_send(const void *d, uint8_t size) { uint8_t marc_status; - uint8_t encode[size + AO_FEC_PREPARE_EXTRA]; + static uint8_t encode[256]; + uint8_t *e = encode; uint8_t encode_len; + uint8_t this_len; + uint8_t started = 0; + uint8_t fifo_space; encode_len = ao_fec_encode(d, size, encode); ao_radio_get(encode_len); - ao_radio_fifo_write(encode, encode_len); - ao_radio_wake = 0; + started = 0; + fifo_space = CC1120_FIFO_SIZE; + while (encode_len) { + this_len = encode_len; - ao_radio_start_tx(); + if (this_len > fifo_space) { + this_len = fifo_space; + ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF); + } else { + ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH); + } - cli(); - while (!ao_radio_wake && !ao_radio_abort) - ao_sleep(&ao_radio_wake); - sei(); - if (!ao_radio_tx_done()) - ao_radio_idle(); + ao_radio_fifo_write(e, this_len); + e += this_len; + encode_len -= this_len; + + if (!started) { + ao_radio_start_tx(); + started = 1; + } else { + ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + } + + do { + ao_radio_wake = 0; + cli(); + while (!ao_radio_wake) + ao_sleep(&ao_radio_wake); + sei(); + if (!encode_len) + break; + fifo_space = ao_radio_tx_fifo_space(); + } while (!fifo_space); + } ao_radio_put(); } #define AO_RADIO_MAX_RECV 90 -static uint8_t rx_data[2048]; -static uint16_t rx_data_count; -static uint16_t rx_data_consumed; -static uint16_t rx_data_cur; -static uint8_t rx_ignore; +uint8_t rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8]; +uint16_t rx_data_count; +uint16_t rx_data_consumed; +uint16_t rx_data_cur; +uint8_t rx_ignore; +uint8_t rx_waiting; + +#if AO_PROFILE +static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick; + +uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick; + +#include +#endif static void ao_radio_rx_isr(void) { + uint8_t d; + + d = stm_spi2.dr; + stm_spi2.dr = 0; if (rx_ignore == 0) { - rx_data[rx_data_cur++] = stm_spi2.dr; if (rx_data_cur >= rx_data_count) - ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); - if (rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) { + ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + else + rx_data[rx_data_cur++] = d; + if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) { +#if AO_PROFILE + if (rx_data_consumed == 0) + rx_packet_tick = ao_profile_tick(); +#endif + rx_waiting = 0; ao_wakeup(&ao_radio_wake); } } else { - (void) stm_spi2.dr; --rx_ignore; } - stm_spi2.dr = 0x00; } static uint16_t ao_radio_rx_wait(void) { cli(); + rx_waiting = 1; while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK && - !ao_radio_abort) + !ao_radio_abort) { ao_sleep(&ao_radio_wake); + } + rx_waiting = 0; sei(); if (ao_radio_abort) return 0; + rx_data_consumed += AO_FEC_DECODE_BLOCK; return AO_FEC_DECODE_BLOCK; } @@ -440,8 +645,17 @@ ao_radio_recv(__xdata void *d, uint8_t size) uint8_t len; uint16_t i; uint8_t rssi; + uint8_t ret; + static int been_here = 0; size -= 2; /* status bytes */ + if (size > AO_RADIO_MAX_RECV) { + ao_delay(AO_SEC_TO_TICKS(1)); + return 0; + } +#if AO_PROFILE + rx_start_tick = ao_profile_tick(); +#endif len = size + 2; /* CRC bytes */ len += 1 + ~(len & 1); /* 1 or two pad bytes */ len *= 2; /* 1/2 rate convolution */ @@ -450,162 +664,65 @@ ao_radio_recv(__xdata void *d, uint8_t size) rx_data_consumed = 0; rx_ignore = 2; - printf ("len %d rx_data_count %d\n", len, rx_data_count); - + ao_radio_abort = 0; + ao_radio_in_recv = 1; /* configure interrupt pin */ ao_radio_get(len); - ao_radio_wake = 0; - ao_radio_abort = 0; - - ao_radio_reg_write(CC1120_PKT_CFG2, - (CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | - (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)); + ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX); - ao_radio_reg_write(CC1120_EXT_CTRL, 0); - - ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT); + ao_radio_wake = 0; stm_spi2.cr2 = 0; /* clear any RXNE */ (void) stm_spi2.dr; - ao_exti_set_callback(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr); - ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr); + ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); ao_radio_strobe(CC1120_SRX); ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT); - ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait); + ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait); ao_radio_burst_read_stop(); + ao_radio_strobe(CC1120_SIDLE); + /* Convert from 'real' rssi to cc1111-style values */ rssi = (((int8_t) ao_radio_reg_read(CC1120_RSSI1)) + 74) * 2; - ao_radio_strobe(CC1120_SIDLE); - ao_radio_put(); /* Construct final packet */ - ao_fec_decode(rx_data, rx_data_cur, d, size + 2, 0); - - if (ao_fec_check_crc(d, size)) + if (ret && ((uint8_t *) d)[size] == 0 && ((uint8_t *)d)[size+1] == 0) ((uint8_t *) d)[size + 1] = 0x80; else ((uint8_t *) d)[size + 1] = 0x00; ((uint8_t *) d)[size] = (uint8_t) rssi; - return 1; -} - -/* - * Packet deviation is 20.5kHz - * - * fdev = fosc >> 24 * (256 + dev_m) << dev_e - * - * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz - */ - -#define PACKET_DEV_E 5 -#define PACKET_DEV_M 80 - -/* - * For our packet data, set the symbol rate to 38360 Baud - * - * (2**20 + DATARATE_M) * 2 ** DATARATE_E - * Rdata = -------------------------------------- * fosc - * 2 ** 39 - * - * - * DATARATE_M = 239914 - * DATARATE_E = 9 - */ -#define PACKET_DRATE_E 9 -#define PACKET_DRATE_M 239914 + ao_radio_in_recv = 0; -static const uint16_t packet_setup[] = { - CC1120_DEVIATION_M, PACKET_DEV_M, - CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) | - (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) | - (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)), - CC1120_DRATE2, ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) | - (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)), - CC1120_DRATE1, ((PACKET_DRATE_M >> 8) & 0xff), - CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff), - CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | - (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)), - CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) | - (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) | - (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) | - (1 << CC1120_PKT_CFG1_APPEND_STATUS)), - CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) | - (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | - (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | - (0 << CC1120_PKT_CFG0_UART_MODE_EN) | - (0 << CC1120_PKT_CFG0_UART_SWAP_EN)), -}; - -void -ao_radio_set_packet(void) -{ - int i; - - for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) - ao_radio_reg_write(packet_setup[i], packet_setup[i+1]); -} - -void -ao_radio_idle(void) -{ - for (;;) { - uint8_t state = ao_radio_strobe(CC1120_SIDLE); - if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE) - break; - } - ao_radio_strobe(CC1120_SFTX); - ao_radio_strobe(CC1120_SFRX); -} - -static const uint16_t radio_setup[] = { -#include "ao_cc1120_CC1120.h" -}; - -static uint8_t ao_radio_configured = 0; - - -static void -ao_radio_setup(void) -{ - int i; - - ao_radio_strobe(CC1120_SRES); - - for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) - ao_radio_reg_write(radio_setup[i], radio_setup[i+1]); + if (ao_radio_abort) + ao_delay(1); - ao_radio_set_packet(); +#if AO_PROFILE + rx_last_done_tick = rx_done_tick; + rx_done_tick = ao_profile_tick(); - ao_config_get(); + ao_rx_start_tick = rx_start_tick; + ao_rx_packet_tick = rx_packet_tick; + ao_rx_done_tick = rx_done_tick; + ao_rx_last_done_tick = rx_last_done_tick; +#endif - ao_radio_configured = 1; + return ret; } -void -ao_radio_get(uint8_t len) -{ - ao_mutex_get(&ao_radio_mutex); - if (!ao_radio_configured) - ao_radio_setup(); - ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16); - ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8); - ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting); - ao_radio_reg_write(CC1120_PKT_LEN, len); -} #if CC1120_DEBUG static char *cc1120_state_name[] = { @@ -824,7 +941,7 @@ static void ao_radio_beep(void) { } static void ao_radio_packet(void) { - static uint8_t packet[] = { + static const uint8_t packet[] = { #if 1 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -841,7 +958,19 @@ static void ao_radio_packet(void) { void ao_radio_test_recv() { - ao_radio_recv(0, 34); + uint8_t bytes[34]; + uint8_t b; + + if (ao_radio_recv(bytes, 34)) { + if (bytes[33] & 0x80) + printf ("CRC OK"); + else + printf ("CRC BAD"); + printf (" RSSI %d", (int16_t) ((int8_t) bytes[32] >> 1) - 74); + for (b = 0; b < 32; b++) + printf (" %02x", bytes[b]); + printf ("\n"); + } } #endif @@ -865,18 +994,20 @@ ao_radio_init(void) ao_radio_configured = 0; ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN)); - AO_CC1120_SPI_CS_PORT.bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN)); + AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN)); for (i = 0; i < 10000; i++) { - if ((SPI_2_GPIO.idr & (1 << SPI_2_MISO)) == 0) + if ((SPI_2_GPIO->idr & (1 << SPI_2_MISO)) == 0) break; } - AO_CC1120_SPI_CS_PORT.bsrr = (1 << AO_CC1120_SPI_CS_PIN); + AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN); if (i == 10000) ao_panic(AO_PANIC_SELF_TEST); /* Enable the EXTI interrupt for the appropriate pin */ ao_enable_port(AO_CC1120_INT_PORT); - ao_exti_setup(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_EXTI_MODE_FALLING, ao_radio_tx_isr); + ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, + AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH, + ao_radio_tx_isr); ao_cmd_register(&ao_radio_cmds[0]); } diff --git a/src/drivers/ao_cc1120.h b/src/drivers/ao_cc1120.h index 5822a21a..60b9621e 100644 --- a/src/drivers/ao_cc1120.h +++ b/src/drivers/ao_cc1120.h @@ -181,6 +181,11 @@ #define CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_MASK 3 #define CC1120_PREAMBLE_CFG0 0x0e +#define CC1120_PREAMBLE_CFG0_PQT_EN 5 +#define CC1120_PREAMBLE_CFG0_PQT_VALID_TIMEOUT 4 +#define CC1120_PREAMBLE_CFG0_PQT 0 +#define CC1120_PREAMBLE_CFG0_PQT_MASK 0xf + #define CC1120_FREQ_IF_CFG 0x0f #define CC1120_IQIC 0x10 #define CC1120_CHAN_BW 0x11 @@ -215,6 +220,8 @@ #define CC1120_AGC_CFG1 0x1c #define CC1120_AGC_CFG0 0x1d #define CC1120_FIFO_CFG 0x1e +#define CC1120_FIFO_CFG_CRC_AUTOFLUSH 7 +#define CC1120_FIFO_CFG_FIFO_THR 0 #define CC1120_DEV_ADDR 0x1f #define CC1120_SETTLING_CFG 0x20 #define CC1120_SETTLING_CFG_FS_AUTOCAL 3 @@ -321,6 +328,8 @@ #define CC1120_DIRECT_FIFO 0x3e #define CC1120_FIFO 0x3f +#define CC1120_FIFO_SIZE 128 + /* Extended register space */ #define CC1120_EXTENDED_BIT 0x8000 diff --git a/src/drivers/ao_cc1120_CC1120.h b/src/drivers/ao_cc1120_CC1120.h index c0f35a23..5376afd5 100644 --- a/src/drivers/ao_cc1120_CC1120.h +++ b/src/drivers/ao_cc1120_CC1120.h @@ -26,7 +26,9 @@ CC1120_SYNC1, 0xD3, /* Sync Word Configuration [15:8] */ CC1120_SYNC0, 0x91, /* Sync Word Configuration [7:0] */ - CC1120_SYNC_CFG1, 0x08, /* Sync Word Detection Configuration */ + CC1120_SYNC_CFG1, /* Sync Word Detection Configuration */ + (CC1120_SYNC_CFG1_DEM_CFG_PQT_GATING_ENABLED << CC1120_SYNC_CFG1_DEM_CFG) | + (0x07 << CC1120_SYNC_CFG1_SYNC_THR), CC1120_SYNC_CFG0, (CC1120_SYNC_CFG0_SYNC_MODE_16_BITS << CC1120_SYNC_CFG0_SYNC_MODE) | (CC1120_SYNC_CFG0_SYNC_NUM_ERROR_2 << CC1120_SYNC_CFG0_SYNC_NUM_ERROR), @@ -34,12 +36,21 @@ CC1120_PREAMBLE_CFG1, /* Preamble Length Configuration */ (CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) | (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD), - CC1120_PREAMBLE_CFG0, 0x2a, /* */ + CC1120_PREAMBLE_CFG0, + (1 << CC1120_PREAMBLE_CFG0_PQT_EN) | + (0x6 << CC1120_PREAMBLE_CFG0_PQT), CC1120_FREQ_IF_CFG, 0x40, /* RX Mixer Frequency Configuration */ CC1120_IQIC, 0x46, /* Digital Image Channel Compensation Configuration */ CC1120_CHAN_BW, 0x02, /* Channel Filter Configuration */ - CC1120_MDMCFG1, 0x46, /* General Modem Parameter Configuration */ + CC1120_MDMCFG1, /* General Modem Parameter Configuration */ + (0 << CC1120_MDMCFG1_CARRIER_SENSE_GATE) | + (1 << CC1120_MDMCFG1_FIFO_EN) | + (0 << CC1120_MDMCFG1_MANCHESTER_EN) | + (0 << CC1120_MDMCFG1_INVERT_DATA_EN) | + (0 << CC1120_MDMCFG1_COLLISION_DETECT_EN) | + (CC1120_MDMCFG1_DVGA_GAIN_9 << CC1120_MDMCFG1_DVGA_GAIN) | + (0 << CC1120_MDMCFG1_SINGLE_ADC_EN), CC1120_MDMCFG0, 0x05, /* General Modem Parameter Configuration */ CC1120_AGC_REF, 0x20, /* AGC Reference Level Configuration */ @@ -49,7 +60,9 @@ CC1120_AGC_CFG2, 0x20, /* AGC Configuration */ CC1120_AGC_CFG1, 0xa9, /* AGC Configuration */ CC1120_AGC_CFG0, 0xcf, /* AGC Configuration */ - CC1120_FIFO_CFG, 0x00, /* FIFO Configuration */ + CC1120_FIFO_CFG, /* FIFO Configuration */ + (0 << CC1120_FIFO_CFG_CRC_AUTOFLUSH) | + (0x40 << CC1120_FIFO_CFG_FIFO_THR), CC1120_DEV_ADDR, 0x00, /* Device Address Configuration */ CC1120_SETTLING_CFG, /* Frequency Synthesizer Calibration and Settling Configuration */ (CC1120_SETTLING_CFG_FS_AUTOCAL_IDLE_TO_ON << CC1120_SETTLING_CFG_FS_AUTOCAL) | @@ -65,12 +78,12 @@ #if 0 CC1120_PKT_CFG2, 0x04, /* Packet Configuration, Reg 2 */ CC1120_PKT_CFG1, 0x45, /* Packet Configuration, Reg 1 */ -#endif CC1120_PKT_CFG0, 0x00, /* Packet Configuration, Reg 0 */ +#endif CC1120_RFEND_CFG1, 0x0f, /* RFEND Configuration, Reg 1 */ CC1120_RFEND_CFG0, 0x00, /* RFEND Configuration, Reg 0 */ // CC1120_PA_CFG2, 0x3f, /* Power Amplifier Configuration, Reg 2 */ - CC1120_PA_CFG2, 0x23, /* Power Amplifier Configuration, Reg 2 */ + CC1120_PA_CFG2, 0x04, /* Power Amplifier Configuration, Reg 2 */ CC1120_PA_CFG1, 0x56, /* Power Amplifier Configuration, Reg 1 */ CC1120_PA_CFG0, 0x7b, /* Power Amplifier Configuration, Reg 0 */ CC1120_PKT_LEN, 0xff, /* Packet Length Configuration */ @@ -80,7 +93,7 @@ CC1120_MARC_SPARE, 0x00, /* MARC Spare */ CC1120_ECG_CFG, 0x00, /* External Clock Frequency Configuration */ CC1120_SOFT_TX_DATA_CFG, 0x00, /* Soft TX Data Configuration */ - CC1120_EXT_CTRL, 0x01, /* External Control Configuration */ + CC1120_EXT_CTRL, 0x00, /* External Control Configuration */ CC1120_RCCAL_FINE, 0x00, /* RC Oscillator Calibration (fine) */ CC1120_RCCAL_COARSE, 0x00, /* RC Oscillator Calibration (coarse) */ CC1120_RCCAL_OFFSET, 0x00, /* RC Oscillator Calibration Clock Offset */ diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index bbd1b3b1..30cd9ea5 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -25,7 +25,7 @@ * STM32L definitions and code fragments for AltOS */ -#define AO_STACK_SIZE 1024 +#define AO_STACK_SIZE 512 #define AO_LED_TYPE uint16_t @@ -111,14 +111,22 @@ extern const uint16_t ao_serial_number; uint32_t *sp; \ asm("mov %0,sp" : "=&r" (sp) ); \ ao_cur_task->sp = (sp); \ - if ((uint8_t *) sp < ao_cur_task->stack) \ + if ((uint8_t *) sp < &ao_cur_task->stack[0]) \ ao_panic (AO_PANIC_STACK); \ } while (0) -#define ao_arch_isr_stack() /* nothing */ +#if 0 +#define ao_arch_isr_stack() do { \ + uint32_t *sp = (uint32_t *) 0x20004000; \ + asm("mov %0,sp" : "=&r" (sp) ); \ + } while (0) +#else +#define ao_arch_isr_stack() +#endif + #define ao_arch_cpu_idle() do { \ - asm("wfi"); \ + asm("wfi"); \ } while (0) #define ao_arch_restore_stack() do { \ @@ -173,6 +181,11 @@ extern const uint16_t ao_serial_number; #define AO_TIM91011_CLK (2 * AO_PCLK2) #endif +#define AO_STM_NVIC_HIGH_PRIORITY 4 +#define AO_STM_NVIC_CLOCK_PRIORITY 6 +#define AO_STM_NVIC_MED_PRIORITY 8 +#define AO_STM_NVIC_LOW_PRIORITY 10 + void ao_lcd_stm_init(void); void ao_lcd_font_init(void); @@ -215,7 +228,7 @@ ao_serial3_pollchar(void); void ao_serial3_set_speed(uint8_t speed); -extern uint32_t ao_radio_cal; +extern const uint32_t ao_radio_cal; void ao_adc_init(); diff --git a/src/stm/ao_exti.h b/src/stm/ao_exti.h index 87a072e7..b579ad9f 100644 --- a/src/stm/ao_exti.h +++ b/src/stm/ao_exti.h @@ -22,6 +22,9 @@ #define AO_EXTI_MODE_FALLING 2 #define AO_EXTI_MODE_PULL_UP 4 #define AO_EXTI_MODE_PULL_DOWN 8 +#define AO_EXTI_PRIORITY_LOW 16 +#define AO_EXTI_PRIORITY_MED 0 +#define AO_EXTI_PRIORITY_HIGH 32 void ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)()); diff --git a/src/stm/ao_exti_stm.c b/src/stm/ao_exti_stm.c index 683a91b3..d54e6ee6 100644 --- a/src/stm/ao_exti_stm.c +++ b/src/stm/ao_exti_stm.c @@ -20,37 +20,50 @@ static void (*ao_exti_callback[16])(void); -static void -ao_exti_isr(void) { - uint32_t pending = stm_exti.pr; - uint8_t pin; +uint32_t ao_last_exti; + +static void ao_exti_one_isr(uint8_t pin) { + uint32_t pending = (ao_last_exti = stm_exti.pr) & (1 << pin); - /* Clear pending interrupts */ stm_exti.pr = pending; - for (pin = 0; pin < 16 && pending; pin++) { - uint32_t mask = (1 << pin); + if (pending && ao_exti_callback[pin]) + (*ao_exti_callback[pin])(); +} - if (pending & mask) { - pending &= ~mask; - if (ao_exti_callback[pin]) - (*ao_exti_callback[pin])(); - } +static void ao_exti_range_isr(uint8_t first, uint8_t last, uint16_t mask) { + uint16_t pending = (ao_last_exti = stm_exti.pr) & mask; + uint8_t pin; + static uint16_t last_mask; + static uint8_t last_pin; + + if (pending == last_mask) { + stm_exti.pr = last_mask; + (*ao_exti_callback[last_pin])(); + return; } + stm_exti.pr = pending; + for (pin = first; pin <= last; pin++) + if ((pending & ((uint32_t) 1 << pin)) && ao_exti_callback[pin]) { + last_mask = (1 << pin); + last_pin = pin; + (*ao_exti_callback[pin])(); + } } -void stm_exti0_isr(void) { ao_exti_isr(); } -void stm_exti1_isr(void) { ao_exti_isr(); } -void stm_exti2_isr(void) { ao_exti_isr(); } -void stm_exti3_isr(void) { ao_exti_isr(); } -void stm_exti4_isr(void) { ao_exti_isr(); } -void stm_exti9_5_isr(void) { ao_exti_isr(); } -void stm_exti15_10_isr(void) { ao_exti_isr(); } +void stm_exti0_isr(void) { ao_exti_one_isr(0); } +void stm_exti1_isr(void) { ao_exti_one_isr(1); } +void stm_exti2_isr(void) { ao_exti_one_isr(2); } +void stm_exti3_isr(void) { ao_exti_one_isr(3); } +void stm_exti4_isr(void) { ao_exti_one_isr(4); } +void stm_exti9_5_isr(void) { ao_exti_range_isr(5, 9, 0x3e0); } +void stm_exti15_10_isr(void) { ao_exti_range_isr(10, 15, 0xfc00); } void ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void)) { uint32_t mask = 1 << pin; uint32_t pupdr; uint8_t irq; + uint8_t prio; ao_exti_callback[pin] = callback; @@ -90,7 +103,15 @@ ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback irq = STM_ISR_EXTI9_5_POS; else irq = STM_ISR_EXTI15_10_POS; - stm_nvic_set_priority(irq, 10); + + /* Set priority */ + prio = AO_STM_NVIC_MED_PRIORITY; + if (mode & AO_EXTI_PRIORITY_LOW) + prio = AO_STM_NVIC_LOW_PRIORITY; + else if (mode & AO_EXTI_PRIORITY_HIGH) + prio = AO_STM_NVIC_HIGH_PRIORITY; + + stm_nvic_set_priority(irq, prio); stm_nvic_set_enable(irq); } @@ -116,10 +137,10 @@ ao_exti_disable(struct stm_gpio *gpio, uint8_t pin) { void ao_exti_init(void) { - stm_nvic_set_priority(STM_ISR_EXTI1_POS, 10); - stm_nvic_set_priority(STM_ISR_EXTI2_POS, 10); - stm_nvic_set_priority(STM_ISR_EXTI3_POS, 10); - stm_nvic_set_priority(STM_ISR_EXTI4_POS, 10); - stm_nvic_set_priority(STM_ISR_EXTI9_5_POS, 10); - stm_nvic_set_priority(STM_ISR_EXTI15_10_POS, 10); + stm_nvic_set_priority(STM_ISR_EXTI1_POS, AO_STM_NVIC_MED_PRIORITY); + stm_nvic_set_priority(STM_ISR_EXTI2_POS, AO_STM_NVIC_MED_PRIORITY); + stm_nvic_set_priority(STM_ISR_EXTI3_POS, AO_STM_NVIC_MED_PRIORITY); + stm_nvic_set_priority(STM_ISR_EXTI4_POS, AO_STM_NVIC_MED_PRIORITY); + stm_nvic_set_priority(STM_ISR_EXTI9_5_POS, AO_STM_NVIC_MED_PRIORITY); + stm_nvic_set_priority(STM_ISR_EXTI15_10_POS, AO_STM_NVIC_MED_PRIORITY); } diff --git a/src/stm/ao_spi_stm.c b/src/stm/ao_spi_stm.c index d3378648..26227086 100644 --- a/src/stm/ao_spi_stm.c +++ b/src/stm/ao_spi_stm.c @@ -23,7 +23,8 @@ struct ao_spi_stm_info { struct stm_spi *stm_spi; }; -uint8_t ao_spi_mutex[STM_NUM_SPI]; +uint8_t ao_spi_mutex[STM_NUM_SPI]; +uint16_t ao_spi_speed[STM_NUM_SPI]; static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = { { @@ -282,7 +283,7 @@ ao_spi_get(uint8_t spi_index) (1 << STM_SPI_CR1_SSI) | /* ... */ (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */ (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */ - (STM_SPI_CR1_BR_PCLK_16 << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */ + (ao_spi_speed[spi_index] << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */ (1 << STM_SPI_CR1_MSTR) | (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ (0 << STM_SPI_CR1_CPHA)); @@ -310,6 +311,7 @@ ao_spi_channel_init(uint8_t spi_index) (0 << STM_SPI_CR2_SSOE) | (0 << STM_SPI_CR2_TXDMAEN) | (0 << STM_SPI_CR2_RXDMAEN)); + ao_spi_speed[spi_index] = AO_SPI_SPEED_FAST; } void diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index 0c44f352..936dc881 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -87,7 +87,7 @@ void ao_timer_init(void) { stm_nvic_set_enable(STM_ISR_TIM6_POS); - stm_nvic_set_priority(STM_ISR_TIM6_POS, 1); + stm_nvic_set_priority(STM_ISR_TIM6_POS, AO_STM_NVIC_CLOCK_PRIORITY); /* Turn on timer 6 */ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN); diff --git a/src/test/ao_fec_test.c b/src/test/ao_fec_test.c index e8d3d8b1..8ce532c8 100644 --- a/src/test/ao_fec_test.c +++ b/src/test/ao_fec_test.c @@ -74,6 +74,12 @@ gaussian_random(double mean, double dev) #define DECODE_LEN(input_len) ((input_len) + AO_FEC_PREPARE_EXTRA) #define EXPAND_LEN(input_len) (ENCODE_LEN(input_len) * 8) +static uint8_t ao_bit(uint8_t b) { + if (b) + return 0x00; + return 0xff; +} + static int ao_expand(uint8_t *bits, int bits_len, uint8_t *bytes) { @@ -83,7 +89,7 @@ ao_expand(uint8_t *bits, int bits_len, uint8_t *bytes) for (i = 0; i < bits_len; i++) { b = bits[i]; for (bit = 7; bit >= 0; bit--) - *bytes++ = ((b >> bit) & 1) * 0xff; + *bytes++ = ao_bit ((b >> bit) & 1); } return bits_len * 8; @@ -127,7 +133,7 @@ ao_random_data(uint8_t *out, uint8_t out_len) static uint8_t real_packet[] = { - 0x00, 0x40, 0x38, 0xcd, 0x38, 0x3d, 0x34, 0xca, 0x31, 0xc3, 0xc1, 0xc6, 0x35, 0xcc, 0x3a, 0x3c, + 0x40, 0x38, 0xcd, 0x38, 0x3d, 0x34, 0xca, 0x31, 0xc3, 0xc1, 0xc6, 0x35, 0xcc, 0x3a, 0x3c, 0x3c, 0x3d, 0x3c, 0x37, 0xc5, 0xc1, 0xc0, 0xc1, 0xc1, 0xc3, 0xc0, 0xc1, 0xc6, 0x38, 0x3b, 0xc6, 0xc0, 0xc6, 0x32, 0xc9, 0xc9, 0x34, 0xcf, 0x35, 0xcf, 0x3a, 0x3b, 0xc6, 0xc7, 0x35, 0xcf, 0x36, 0xce, 0x37, 0xc8, 0xc8, 0x3a, 0x3c, 0xc9, 0xc8, 0x3a, 0x3c, 0xcc, 0x32, 0xcd, 0x32, 0xce, 0x32, @@ -258,22 +264,24 @@ static uint8_t real_packet[] = { }; -void +int ao_real_packet(void) { uint8_t decode[64]; uint8_t decode_len; - int off; + int ok = 0; - for (off = 0; off < sizeof (real_packet) - 576; off++) { - decode_len = ao_fec_decode(real_packet+off, 576, decode, 34, NULL); + decode_len = ao_fec_decode(real_packet, 576, decode, 34, NULL); - if (ao_fec_check_crc(decode, 32)) { - printf ("match at %d\n", off); + if (decode[32] == 0 && decode[33] == 0) { + printf ("match\n"); - ao_fec_dump_bytes(decode, decode_len, "Decode"); - } + ao_fec_dump_bytes(decode, decode_len, "Decode"); + ok = 1; + } else { + printf ("actual packet crc error\n"); } + return ok; } int @@ -299,9 +307,11 @@ main(int argc, char **argv) int errors = 0; int error; - ao_real_packet(); exit(0); + if (!ao_real_packet()) + errors++; + srandom(0); - for (trial = 0; trial < 10000; trial++) { + for (trial = 0; trial < 100000; trial++) { /* Compute some random data */ original_len = ao_random_data(original, sizeof(original)); @@ -313,7 +323,7 @@ main(int argc, char **argv) transmit_len = ao_expand(encode, encode_len, transmit); /* Add gaussian noise to the signal */ - receive_errors = ao_fuzz(transmit, transmit_len, receive, 0x30); + receive_errors = ao_fuzz(transmit, transmit_len, receive, 0x38); receive_len = transmit_len; /* Decode it */ @@ -327,7 +337,7 @@ main(int argc, char **argv) error++; } - if (!ao_fec_check_crc(decode, original_len)) { + if (decode[original_len] != 0 || decode[original_len+1] != 0) { printf ("crc mis-match\n"); error++; } @@ -343,6 +353,7 @@ main(int argc, char **argv) errors += error; } } + printf ("%d packets coded\n", trial); return errors; } -- cgit v1.2.3 From 84f9a525c64491afa9b7a565e3c10a4cee106e14 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Jun 2012 17:17:44 -0700 Subject: altos: Clean up radio CRC handling Make the FEC code just set the CRC_OK bit like the cc1111 radio does; eliminates a bunch of weird conventions across the FEC API. Signed-off-by: Keith Packard --- src/core/ao.h | 7 +++++++ src/core/ao_fec.h | 2 ++ src/core/ao_fec_rx.c | 26 +++++++++++++++----------- src/drivers/ao_cc1120.c | 7 +------ src/drivers/ao_packet.c | 4 +--- src/test/ao_fec_test.c | 21 ++++++++++----------- 6 files changed, 36 insertions(+), 31 deletions(-) (limited to 'src/test') diff --git a/src/core/ao.h b/src/core/ao.h index 62eb488e..861a0fd4 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -511,6 +511,13 @@ extern __xdata uint8_t ao_radio_dma_done; extern __xdata uint8_t ao_radio_done; extern __xdata uint8_t ao_radio_mutex; +#ifdef PKT_APPEND_STATUS_1_CRC_OK +#define AO_RADIO_STATUS_CRC_OK PKT_APPEND_STATUS_1_CRC_OK +#else +#include +#define AO_RADIO_STATUS_CRC_OK AO_FEC_DECODE_CRC_OK +#endif + void ao_radio_general_isr(void) ao_arch_interrupt(16); diff --git a/src/core/ao_fec.h b/src/core/ao_fec.h index f1192b62..771732bd 100644 --- a/src/core/ao_fec.h +++ b/src/core/ao_fec.h @@ -70,6 +70,8 @@ ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out); #define AO_FEC_DECODE_BLOCK (32) /* callback must return multiples of this many bits */ +#define AO_FEC_DECODE_CRC_OK 0x80 /* stored in out[out_len-1] */ + uint8_t ao_fec_decode(const uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)()); diff --git a/src/core/ao_fec_rx.c b/src/core/ao_fec_rx.c index 0d400bb0..d4c98475 100644 --- a/src/core/ao_fec_rx.c +++ b/src/core/ao_fec_rx.c @@ -211,6 +211,7 @@ ao_fec_decode(const uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, ui int8_t dist = b - (o + 8); /* distance to last ready-for-writing bit */ uint32_t min_cost; /* lowest cost */ uint8_t min_state; /* lowest cost state */ + uint8_t byte; /* Find the best fit at the current point * of the decode. @@ -238,24 +239,27 @@ ao_fec_decode(const uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, ui printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x whiten %0x\n", i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten); #endif - if (out_len) { - uint8_t byte = (bits[p][min_state] >> dist) ^ *whiten++; + byte = (bits[p][min_state] >> dist) ^ *whiten++; + *out++ = byte; + if (out_len > 2) + crc = ao_fec_crc_byte(byte, crc); - if (out_len > 2) { - crc = ao_fec_crc_byte(byte, crc); - *out++ = byte; - } else { - *out++ = byte ^ (crc >> 8); - crc <<= 8; - } - --out_len; + if (!--out_len) { + if ((out[-2] == (uint8_t) (crc >> 8)) && + out[-1] == (uint8_t) crc) + out[-1] = AO_FEC_DECODE_CRC_OK; + else + out[-1] = 0; + out[-2] = 0; + goto done; } o += 8; } } +done: #if AO_PROFILE ao_fec_decode_start = start_tick; ao_fec_decode_end = ao_profile_tick(); #endif - return len/16; + return 1; } diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index c974613e..30663042 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -690,12 +690,7 @@ ao_radio_recv(__xdata void *d, uint8_t size) ao_radio_put(); - /* Construct final packet */ - - if (ret && ((uint8_t *) d)[size] == 0 && ((uint8_t *)d)[size+1] == 0) - ((uint8_t *) d)[size + 1] = 0x80; - else - ((uint8_t *) d)[size + 1] = 0x00; + /* Store the received RSSI value; the crc-OK byte is already done */ ((uint8_t *) d)[size] = (uint8_t) rssi; diff --git a/src/drivers/ao_packet.c b/src/drivers/ao_packet.c index 19fe0558..28a0c415 100644 --- a/src/drivers/ao_packet.c +++ b/src/drivers/ao_packet.c @@ -65,10 +65,8 @@ ao_packet_recv(void) /* Check to see if we got a valid packet */ if (!dma_done) return 0; -#ifdef PKT_APPEND_STATUS_1_CRC_OK - if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) + if (!(ao_rx_packet.status & AO_RADIO_STATUS_CRC_OK)) return 0; -#endif /* Accept packets with matching call signs, or any packet if * our callsign hasn't been configured diff --git a/src/test/ao_fec_test.c b/src/test/ao_fec_test.c index 8ce532c8..671fcafc 100644 --- a/src/test/ao_fec_test.c +++ b/src/test/ao_fec_test.c @@ -268,18 +268,17 @@ int ao_real_packet(void) { uint8_t decode[64]; - uint8_t decode_len; - int ok = 0; + int ok; - decode_len = ao_fec_decode(real_packet, 576, decode, 34, NULL); + ok = ao_fec_decode(real_packet, 576, decode, 34, NULL); - if (decode[32] == 0 && decode[33] == 0) { + if (ok && decode[33] == AO_FEC_DECODE_CRC_OK) { printf ("match\n"); - ao_fec_dump_bytes(decode, decode_len, "Decode"); - ok = 1; + ao_fec_dump_bytes(decode, 34, "Decode"); } else { printf ("actual packet crc error\n"); + ok = 0; } return ok; } @@ -302,7 +301,7 @@ main(int argc, char **argv) int receive_len, receive_errors; uint8_t decode[DECODE_LEN(sizeof(original))]; - int decode_len; + int decode_ok; int errors = 0; int error; @@ -327,17 +326,17 @@ main(int argc, char **argv) receive_len = transmit_len; /* Decode it */ - decode_len = ao_fec_decode(receive, receive_len, decode, original_len + 2, NULL); + decode_ok = ao_fec_decode(receive, receive_len, decode, original_len + 2, NULL); /* Check to see if we received the right data */ error = 0; - if (decode_len < original_len + 2) { - printf ("len mis-match\n"); + if (!decode_ok) { + printf ("decode failed\n"); error++; } - if (decode[original_len] != 0 || decode[original_len+1] != 0) { + if (decode[original_len +1] != AO_FEC_DECODE_CRC_OK) { printf ("crc mis-match\n"); error++; } -- cgit v1.2.3 From 939ad8bfd640ed55116703a58f87af06e75ef87e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 3 Jul 2012 21:01:01 -0700 Subject: altos: Crank up the gaussian noise in the FEC test This lets us check to make sure our receive performance isn't degrading at all, instead of just making sure we can receive perfect packets well. Signed-off-by: Keith Packard --- src/test/ao_fec_test.c | 54 +++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 23 deletions(-) (limited to 'src/test') diff --git a/src/test/ao_fec_test.c b/src/test/ao_fec_test.c index 671fcafc..b94b16dc 100644 --- a/src/test/ao_fec_test.c +++ b/src/test/ao_fec_test.c @@ -283,6 +283,11 @@ ao_real_packet(void) return ok; } +#define EXPECT_DECODE_FAIL 0 +#define EXPECT_CRC_MISMATCH 6386 +#define EXPECT_DATA_MISMATCH 0 +#define NOISE_AMOUNT 0x50 + int main(int argc, char **argv) { @@ -298,13 +303,15 @@ main(int argc, char **argv) int transmit_len; uint8_t receive[EXPAND_LEN(sizeof(original))]; - int receive_len, receive_errors; + int receive_len; uint8_t decode[DECODE_LEN(sizeof(original))]; int decode_ok; int errors = 0; - int error; + int decode_fail = 0; + int crc_mismatch = 0; + int data_mismatch = 0; if (!ao_real_packet()) errors++; @@ -322,37 +329,38 @@ main(int argc, char **argv) transmit_len = ao_expand(encode, encode_len, transmit); /* Add gaussian noise to the signal */ - receive_errors = ao_fuzz(transmit, transmit_len, receive, 0x38); + (void) ao_fuzz(transmit, transmit_len, receive, NOISE_AMOUNT); receive_len = transmit_len; /* Decode it */ decode_ok = ao_fec_decode(receive, receive_len, decode, original_len + 2, NULL); /* Check to see if we received the right data */ - error = 0; - if (!decode_ok) { - printf ("decode failed\n"); - error++; - } + if (!decode_ok) + decode_fail++; + else if (decode[original_len +1] != AO_FEC_DECODE_CRC_OK) + crc_mismatch++; + else if (memcmp(original, decode, original_len) != 0) + data_mismatch++; + } - if (decode[original_len +1] != AO_FEC_DECODE_CRC_OK) { - printf ("crc mis-match\n"); - error++; - } - if (memcmp(original, decode, original_len) != 0) { - printf ("data mis-match\n"); - error++; - } - if (error) { - printf ("Errors: %d\n", receive_errors); - ao_fec_dump_bytes(original, original_len, "Input"); - ao_fec_dump_bytes(decode, original_len, "Decode"); - errors += error; - } - } printf ("%d packets coded\n", trial); + printf ("decode_fail %d crc_mismatch %d data_mismatch %d\n", + decode_fail, crc_mismatch, data_mismatch); + if (decode_fail != EXPECT_DECODE_FAIL) { + printf ("expected %d decode failures\n", EXPECT_DECODE_FAIL); + errors++; + } + if (crc_mismatch != EXPECT_CRC_MISMATCH) { + printf ("expected %d crc mismatch\n", EXPECT_CRC_MISMATCH); + errors++; + } + if (data_mismatch != EXPECT_DATA_MISMATCH) { + printf ("expected %d data mismatch\n", EXPECT_DATA_MISMATCH); + errors++; + } return errors; } -- cgit v1.2.3 From 1ae3f467a1d7be2fc3b1a45ba12568a3a25a0099 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jul 2012 15:11:36 -0700 Subject: altos: Rename *_mm.c back to *.c Was just a temporary hack to keep cc1111 products building during MM development. Signed-off-by: Keith Packard --- src/core/ao_flight.c | 418 ++++++++++++++++++++++++++++++++++++++++ src/core/ao_flight_mm.c | 418 ---------------------------------------- src/core/ao_sample.c | 138 +++++++++++++ src/core/ao_sample_mm.c | 138 ------------- src/megametrum-v0.1/Makefile | 4 +- src/product/Makefile.telemetrum | 4 +- src/product/Makefile.telemini | 4 +- src/product/Makefile.telenano | 2 +- src/test/Makefile | 9 +- src/test/ao_flight_test.c | 35 ++-- 10 files changed, 591 insertions(+), 579 deletions(-) create mode 100644 src/core/ao_flight.c delete mode 100644 src/core/ao_flight_mm.c create mode 100644 src/core/ao_sample.c delete mode 100644 src/core/ao_sample_mm.c (limited to 'src/test') diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c new file mode 100644 index 00000000..a0affc48 --- /dev/null +++ b/src/core/ao_flight.c @@ -0,0 +1,418 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef AO_FLIGHT_TEST +#include "ao.h" +#include +#endif + +#ifndef HAS_ACCEL +#error Please define HAS_ACCEL +#endif + +#ifndef HAS_GPS +#error Please define HAS_GPS +#endif + +#ifndef HAS_USB +#error Please define HAS_USB +#endif + +#ifndef HAS_TELEMETRY +#define HAS_TELEMETRY HAS_RADIO +#endif + +/* Main flight thread. */ + +__pdata enum ao_flight_state ao_flight_state; /* current flight state */ +__pdata uint16_t ao_boost_tick; /* time of launch detect */ + +/* + * track min/max data over a long interval to detect + * resting + */ +static __data uint16_t ao_interval_end; +static __data int16_t ao_interval_min_height; +static __data int16_t ao_interval_max_height; +static __data int16_t ao_coast_avg_accel; + +__pdata uint8_t ao_flight_force_idle; + +/* We also have a clock, which can be used to sanity check things in + * case of other failures + */ + +#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) + +/* Landing is detected by getting constant readings from both pressure and accelerometer + * for a fairly long time (AO_INTERVAL_TICKS) + */ +#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10) + +#define abs(a) ((a) < 0 ? -(a) : (a)) + +void +ao_flight(void) +{ + ao_sample_init(); + ao_flight_state = ao_flight_startup; + for (;;) { + + /* + * Process ADC samples, just looping + * until the sensors are calibrated. + */ + if (!ao_sample()) + continue; + + switch (ao_flight_state) { + case ao_flight_startup: + + /* Check to see what mode we should go to. + * - Invalid mode if accel cal appears to be out + * - pad mode if we're upright, + * - idle mode otherwise + */ +#if HAS_ACCEL + if (ao_config.accel_plus_g == 0 || + ao_config.accel_minus_g == 0 || + ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || + ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) + { + /* Detected an accel value outside -1.5g to 1.5g + * (or uncalibrated values), so we go into invalid mode + */ + ao_flight_state = ao_flight_invalid; + +#if HAS_RADIO && PACKET_HAS_SLAVE + /* Turn on packet system in invalid mode on TeleMetrum */ + ao_packet_slave_start(); +#endif + } else +#endif + if (!ao_flight_force_idle +#if HAS_ACCEL + && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP +#endif + ) + { + /* Set pad mode - we can fly! */ + ao_flight_state = ao_flight_pad; +#if HAS_USB && HAS_RADIO + /* Disable the USB controller in flight mode + * to save power + */ + ao_usb_disable(); +#endif + +#if !HAS_ACCEL + /* Disable packet mode in pad state on TeleMini */ + ao_packet_slave_stop(); +#endif + +#if HAS_TELEMETRY + /* Turn on telemetry system */ + ao_rdf_set(1); + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); +#endif + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + } else { + /* Set idle mode */ + ao_flight_state = ao_flight_idle; + +#if HAS_ACCEL && HAS_RADIO && PACKET_HAS_SLAVE + /* Turn on packet system in idle mode on TeleMetrum */ + ao_packet_slave_start(); +#endif + + /* signal successful initialization by turning off the LED */ + ao_led_off(AO_LED_RED); + } + /* wakeup threads due to state change */ + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + + break; + case ao_flight_pad: + + /* pad to boost: + * + * barometer: > 20m vertical motion + * OR + * accelerometer: > 2g AND velocity > 5m/s + * + * The accelerometer should always detect motion before + * the barometer, but we use both to make sure this + * transition is detected. If the device + * doesn't have an accelerometer, then ignore the + * speed and acceleration as they are quite noisy + * on the pad. + */ + if (ao_height > AO_M_TO_HEIGHT(20) +#if HAS_ACCEL + || (ao_accel > AO_MSS_TO_ACCEL(20) && + ao_speed > AO_MS_TO_SPEED(5)) +#endif + ) + { + ao_flight_state = ao_flight_boost; + ao_boost_tick = ao_sample_tick; + + /* start logging data */ + ao_log_start(); + +#if HAS_TELEMETRY + /* Increase telemetry rate */ + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT); + + /* disable RDF beacon */ + ao_rdf_set(0); +#endif + +#if HAS_GPS + /* Record current GPS position by waking up GPS log tasks */ + ao_wakeup(&ao_gps_data); + ao_wakeup(&ao_gps_tracking_data); +#endif + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + case ao_flight_boost: + + /* boost to fast: + * + * accelerometer: start to fall at > 1/4 G + * OR + * time: boost for more than 15 seconds + * + * Detects motor burn out by the switch from acceleration to + * deceleration, or by waiting until the maximum burn duration + * (15 seconds) has past. + */ + if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || + (int16_t) (ao_sample_tick - ao_boost_tick) > BOOST_TICKS_MAX) + { +#if HAS_ACCEL + ao_flight_state = ao_flight_fast; + ao_coast_avg_accel = ao_accel; +#else + ao_flight_state = ao_flight_coast; +#endif + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; +#if HAS_ACCEL + case ao_flight_fast: + /* + * This is essentially the same as coast, + * but the barometer is being ignored as + * it may be unreliable. + */ + if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) + { + ao_flight_state = ao_flight_coast; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } else + goto check_re_boost; + break; +#endif + case ao_flight_coast: + + /* + * By customer request - allow the user + * to lock out apogee detection for a specified + * number of seconds. + */ + if (ao_config.apogee_lockout) { + if ((ao_sample_tick - ao_boost_tick) < + AO_SEC_TO_TICKS(ao_config.apogee_lockout)) + break; + } + + /* apogee detect: coast to drogue deploy: + * + * speed: < 0 + * + * Also make sure the model altitude is tracking + * the measured altitude reasonably closely; otherwise + * we're probably transsonic. + */ + if (ao_speed < 0 +#if !HAS_ACCEL + && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) +#endif + ) + { +#if HAS_IGNITE + /* ignite the drogue charge */ + ao_ignite(ao_igniter_drogue); +#endif + +#if HAS_TELEMETRY + /* slow down the telemetry system */ + ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); + + /* Turn the RDF beacon back on */ + ao_rdf_set(1); +#endif + + /* and enter drogue state */ + ao_flight_state = ao_flight_drogue; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } +#if HAS_ACCEL + else { + check_re_boost: + ao_coast_avg_accel = ao_coast_avg_accel - (ao_coast_avg_accel >> 6) + (ao_accel >> 6); + if (ao_coast_avg_accel > AO_MSS_TO_ACCEL(20)) { + ao_boost_tick = ao_sample_tick; + ao_flight_state = ao_flight_boost; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + } +#endif + + break; + case ao_flight_drogue: + + /* drogue to main deploy: + * + * barometer: reach main deploy altitude + * + * Would like to use the accelerometer for this test, but + * the orientation of the flight computer is unknown after + * drogue deploy, so we ignore it. Could also detect + * high descent rate using the pressure sensor to + * recognize drogue deploy failure and eject the main + * at that point. Perhaps also use the drogue sense lines + * to notice continutity? + */ + if (ao_height <= ao_config.main_deploy) + { +#if HAS_IGNITE + ao_ignite(ao_igniter_main); +#endif + + /* + * Start recording min/max height + * to figure out when the rocket has landed + */ + + /* initialize interval values */ + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + + ao_interval_min_height = ao_interval_max_height = ao_avg_height; + + ao_flight_state = ao_flight_main; + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + break; + + /* fall through... */ + case ao_flight_main: + + /* main to land: + * + * barometer: altitude stable + */ + + if (ao_avg_height < ao_interval_min_height) + ao_interval_min_height = ao_avg_height; + if (ao_avg_height > ao_interval_max_height) + ao_interval_max_height = ao_avg_height; + + if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { + if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4)) + { + ao_flight_state = ao_flight_landed; + + /* turn off the ADC capture */ + ao_timer_set_adc_interval(0); + + ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); + } + ao_interval_min_height = ao_interval_max_height = ao_avg_height; + ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; + } + break; + case ao_flight_landed: + break; + } + } +} + +#if !HAS_RADIO +static inline int int_part(int16_t i) { return i >> 4; } +static inline int frac_part(int16_t i) { return ((i & 0xf) * 100 + 8) / 16; } + +static void +ao_flight_dump(void) +{ +#if HAS_ACCEL + int16_t accel; + + accel = ((ao_ground_accel - ao_sample_accel) * ao_accel_scale) >> 16; +#endif + + printf ("sample:\n"); + printf (" tick %d\n", ao_sample_tick); + printf (" raw pres %d\n", ao_sample_pres); +#if HAS_ACCEL + printf (" raw accel %d\n", ao_sample_accel); +#endif + printf (" ground pres %d\n", ao_ground_pres); +#if HAS_ACCEL + printf (" raw accel %d\n", ao_sample_accel); + printf (" groundaccel %d\n", ao_ground_accel); + printf (" accel_2g %d\n", ao_accel_2g); +#endif + + printf (" alt %d\n", ao_sample_alt); + printf (" height %d\n", ao_sample_height); +#if HAS_ACCEL + printf (" accel %d.%02d\n", int_part(accel), frac_part(accel)); +#endif + + + printf ("kalman:\n"); + printf (" height %d\n", ao_height); + printf (" speed %d.%02d\n", int_part(ao_speed), frac_part(ao_speed)); + printf (" accel %d.%02d\n", int_part(ao_accel), frac_part(ao_accel)); + printf (" max_height %d\n", ao_max_height); + printf (" avg_height %d\n", ao_avg_height); + printf (" error_h %d\n", ao_error_h); + printf (" error_avg %d\n", ao_error_h_sq_avg); +} + +__code struct ao_cmds ao_flight_cmds[] = { + { ao_flight_dump, "F\0Dump flight status" }, + { 0, NULL }, +}; +#endif + +static __xdata struct ao_task flight_task; + +void +ao_flight_init(void) +{ + ao_flight_state = ao_flight_startup; +#if !HAS_RADIO + ao_cmd_register(&ao_flight_cmds[0]); +#endif + ao_add_task(&flight_task, ao_flight, "flight"); +} diff --git a/src/core/ao_flight_mm.c b/src/core/ao_flight_mm.c deleted file mode 100644 index a0affc48..00000000 --- a/src/core/ao_flight_mm.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * 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. - */ - -#ifndef AO_FLIGHT_TEST -#include "ao.h" -#include -#endif - -#ifndef HAS_ACCEL -#error Please define HAS_ACCEL -#endif - -#ifndef HAS_GPS -#error Please define HAS_GPS -#endif - -#ifndef HAS_USB -#error Please define HAS_USB -#endif - -#ifndef HAS_TELEMETRY -#define HAS_TELEMETRY HAS_RADIO -#endif - -/* Main flight thread. */ - -__pdata enum ao_flight_state ao_flight_state; /* current flight state */ -__pdata uint16_t ao_boost_tick; /* time of launch detect */ - -/* - * track min/max data over a long interval to detect - * resting - */ -static __data uint16_t ao_interval_end; -static __data int16_t ao_interval_min_height; -static __data int16_t ao_interval_max_height; -static __data int16_t ao_coast_avg_accel; - -__pdata uint8_t ao_flight_force_idle; - -/* We also have a clock, which can be used to sanity check things in - * case of other failures - */ - -#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15) - -/* Landing is detected by getting constant readings from both pressure and accelerometer - * for a fairly long time (AO_INTERVAL_TICKS) - */ -#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10) - -#define abs(a) ((a) < 0 ? -(a) : (a)) - -void -ao_flight(void) -{ - ao_sample_init(); - ao_flight_state = ao_flight_startup; - for (;;) { - - /* - * Process ADC samples, just looping - * until the sensors are calibrated. - */ - if (!ao_sample()) - continue; - - switch (ao_flight_state) { - case ao_flight_startup: - - /* Check to see what mode we should go to. - * - Invalid mode if accel cal appears to be out - * - pad mode if we're upright, - * - idle mode otherwise - */ -#if HAS_ACCEL - if (ao_config.accel_plus_g == 0 || - ao_config.accel_minus_g == 0 || - ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP || - ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP) - { - /* Detected an accel value outside -1.5g to 1.5g - * (or uncalibrated values), so we go into invalid mode - */ - ao_flight_state = ao_flight_invalid; - -#if HAS_RADIO && PACKET_HAS_SLAVE - /* Turn on packet system in invalid mode on TeleMetrum */ - ao_packet_slave_start(); -#endif - } else -#endif - if (!ao_flight_force_idle -#if HAS_ACCEL - && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP -#endif - ) - { - /* Set pad mode - we can fly! */ - ao_flight_state = ao_flight_pad; -#if HAS_USB && HAS_RADIO - /* Disable the USB controller in flight mode - * to save power - */ - ao_usb_disable(); -#endif - -#if !HAS_ACCEL - /* Disable packet mode in pad state on TeleMini */ - ao_packet_slave_stop(); -#endif - -#if HAS_TELEMETRY - /* Turn on telemetry system */ - ao_rdf_set(1); - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD); -#endif - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - } else { - /* Set idle mode */ - ao_flight_state = ao_flight_idle; - -#if HAS_ACCEL && HAS_RADIO && PACKET_HAS_SLAVE - /* Turn on packet system in idle mode on TeleMetrum */ - ao_packet_slave_start(); -#endif - - /* signal successful initialization by turning off the LED */ - ao_led_off(AO_LED_RED); - } - /* wakeup threads due to state change */ - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - - break; - case ao_flight_pad: - - /* pad to boost: - * - * barometer: > 20m vertical motion - * OR - * accelerometer: > 2g AND velocity > 5m/s - * - * The accelerometer should always detect motion before - * the barometer, but we use both to make sure this - * transition is detected. If the device - * doesn't have an accelerometer, then ignore the - * speed and acceleration as they are quite noisy - * on the pad. - */ - if (ao_height > AO_M_TO_HEIGHT(20) -#if HAS_ACCEL - || (ao_accel > AO_MSS_TO_ACCEL(20) && - ao_speed > AO_MS_TO_SPEED(5)) -#endif - ) - { - ao_flight_state = ao_flight_boost; - ao_boost_tick = ao_sample_tick; - - /* start logging data */ - ao_log_start(); - -#if HAS_TELEMETRY - /* Increase telemetry rate */ - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT); - - /* disable RDF beacon */ - ao_rdf_set(0); -#endif - -#if HAS_GPS - /* Record current GPS position by waking up GPS log tasks */ - ao_wakeup(&ao_gps_data); - ao_wakeup(&ao_gps_tracking_data); -#endif - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - case ao_flight_boost: - - /* boost to fast: - * - * accelerometer: start to fall at > 1/4 G - * OR - * time: boost for more than 15 seconds - * - * Detects motor burn out by the switch from acceleration to - * deceleration, or by waiting until the maximum burn duration - * (15 seconds) has past. - */ - if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) || - (int16_t) (ao_sample_tick - ao_boost_tick) > BOOST_TICKS_MAX) - { -#if HAS_ACCEL - ao_flight_state = ao_flight_fast; - ao_coast_avg_accel = ao_accel; -#else - ao_flight_state = ao_flight_coast; -#endif - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; -#if HAS_ACCEL - case ao_flight_fast: - /* - * This is essentially the same as coast, - * but the barometer is being ignored as - * it may be unreliable. - */ - if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) - { - ao_flight_state = ao_flight_coast; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } else - goto check_re_boost; - break; -#endif - case ao_flight_coast: - - /* - * By customer request - allow the user - * to lock out apogee detection for a specified - * number of seconds. - */ - if (ao_config.apogee_lockout) { - if ((ao_sample_tick - ao_boost_tick) < - AO_SEC_TO_TICKS(ao_config.apogee_lockout)) - break; - } - - /* apogee detect: coast to drogue deploy: - * - * speed: < 0 - * - * Also make sure the model altitude is tracking - * the measured altitude reasonably closely; otherwise - * we're probably transsonic. - */ - if (ao_speed < 0 -#if !HAS_ACCEL - && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100) -#endif - ) - { -#if HAS_IGNITE - /* ignite the drogue charge */ - ao_ignite(ao_igniter_drogue); -#endif - -#if HAS_TELEMETRY - /* slow down the telemetry system */ - ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER); - - /* Turn the RDF beacon back on */ - ao_rdf_set(1); -#endif - - /* and enter drogue state */ - ao_flight_state = ao_flight_drogue; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } -#if HAS_ACCEL - else { - check_re_boost: - ao_coast_avg_accel = ao_coast_avg_accel - (ao_coast_avg_accel >> 6) + (ao_accel >> 6); - if (ao_coast_avg_accel > AO_MSS_TO_ACCEL(20)) { - ao_boost_tick = ao_sample_tick; - ao_flight_state = ao_flight_boost; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - } -#endif - - break; - case ao_flight_drogue: - - /* drogue to main deploy: - * - * barometer: reach main deploy altitude - * - * Would like to use the accelerometer for this test, but - * the orientation of the flight computer is unknown after - * drogue deploy, so we ignore it. Could also detect - * high descent rate using the pressure sensor to - * recognize drogue deploy failure and eject the main - * at that point. Perhaps also use the drogue sense lines - * to notice continutity? - */ - if (ao_height <= ao_config.main_deploy) - { -#if HAS_IGNITE - ao_ignite(ao_igniter_main); -#endif - - /* - * Start recording min/max height - * to figure out when the rocket has landed - */ - - /* initialize interval values */ - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - - ao_interval_min_height = ao_interval_max_height = ao_avg_height; - - ao_flight_state = ao_flight_main; - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - break; - - /* fall through... */ - case ao_flight_main: - - /* main to land: - * - * barometer: altitude stable - */ - - if (ao_avg_height < ao_interval_min_height) - ao_interval_min_height = ao_avg_height; - if (ao_avg_height > ao_interval_max_height) - ao_interval_max_height = ao_avg_height; - - if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) { - if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4)) - { - ao_flight_state = ao_flight_landed; - - /* turn off the ADC capture */ - ao_timer_set_adc_interval(0); - - ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); - } - ao_interval_min_height = ao_interval_max_height = ao_avg_height; - ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS; - } - break; - case ao_flight_landed: - break; - } - } -} - -#if !HAS_RADIO -static inline int int_part(int16_t i) { return i >> 4; } -static inline int frac_part(int16_t i) { return ((i & 0xf) * 100 + 8) / 16; } - -static void -ao_flight_dump(void) -{ -#if HAS_ACCEL - int16_t accel; - - accel = ((ao_ground_accel - ao_sample_accel) * ao_accel_scale) >> 16; -#endif - - printf ("sample:\n"); - printf (" tick %d\n", ao_sample_tick); - printf (" raw pres %d\n", ao_sample_pres); -#if HAS_ACCEL - printf (" raw accel %d\n", ao_sample_accel); -#endif - printf (" ground pres %d\n", ao_ground_pres); -#if HAS_ACCEL - printf (" raw accel %d\n", ao_sample_accel); - printf (" groundaccel %d\n", ao_ground_accel); - printf (" accel_2g %d\n", ao_accel_2g); -#endif - - printf (" alt %d\n", ao_sample_alt); - printf (" height %d\n", ao_sample_height); -#if HAS_ACCEL - printf (" accel %d.%02d\n", int_part(accel), frac_part(accel)); -#endif - - - printf ("kalman:\n"); - printf (" height %d\n", ao_height); - printf (" speed %d.%02d\n", int_part(ao_speed), frac_part(ao_speed)); - printf (" accel %d.%02d\n", int_part(ao_accel), frac_part(ao_accel)); - printf (" max_height %d\n", ao_max_height); - printf (" avg_height %d\n", ao_avg_height); - printf (" error_h %d\n", ao_error_h); - printf (" error_avg %d\n", ao_error_h_sq_avg); -} - -__code struct ao_cmds ao_flight_cmds[] = { - { ao_flight_dump, "F\0Dump flight status" }, - { 0, NULL }, -}; -#endif - -static __xdata struct ao_task flight_task; - -void -ao_flight_init(void) -{ - ao_flight_state = ao_flight_startup; -#if !HAS_RADIO - ao_cmd_register(&ao_flight_cmds[0]); -#endif - ao_add_task(&flight_task, ao_flight, "flight"); -} diff --git a/src/core/ao_sample.c b/src/core/ao_sample.c new file mode 100644 index 00000000..ac11eef0 --- /dev/null +++ b/src/core/ao_sample.c @@ -0,0 +1,138 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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. + */ + +#ifndef AO_FLIGHT_TEST +#include "ao.h" +#include +#endif + +/* + * Current sensor values + */ + +#ifndef PRES_TYPE +#define PRES_TYPE int32_t +#define ALT_TYPE int32_t +#define ACCEL_TYPE int16_t +#endif + +__pdata uint16_t ao_sample_tick; /* time of last data */ +__pdata pres_t ao_sample_pres; +__pdata alt_t ao_sample_alt; +__pdata alt_t ao_sample_height; +#if HAS_ACCEL +__pdata accel_t ao_sample_accel; +#endif + +__data uint8_t ao_sample_data; + +/* + * Sensor calibration values + */ + +__pdata pres_t ao_ground_pres; /* startup pressure */ +__pdata alt_t ao_ground_height; /* MSL of ao_ground_pres */ + +#if HAS_ACCEL +__pdata accel_t ao_ground_accel; /* startup acceleration */ +__pdata accel_t ao_accel_2g; /* factory accel calibration */ +__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ +#endif + +static __pdata uint8_t ao_preflight; /* in preflight mode */ + +static __pdata uint16_t nsamples; +__pdata int32_t ao_sample_pres_sum; +#if HAS_ACCEL +__pdata int32_t ao_sample_accel_sum; +#endif + +static void +ao_sample_preflight(void) +{ + /* startup state: + * + * Collect 512 samples of acceleration and pressure + * data and average them to find the resting values + */ + if (nsamples < 512) { +#if HAS_ACCEL + ao_sample_accel_sum += ao_sample_accel; +#endif + ao_sample_pres_sum += ao_sample_pres; + ++nsamples; + } else { + ao_config_get(); +#if HAS_ACCEL + ao_ground_accel = ao_sample_accel_sum >> 9; + ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; + ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; +#endif + ao_ground_pres = ao_sample_pres_sum >> 9; + ao_ground_height = pres_to_altitude(ao_ground_pres); + ao_preflight = FALSE; + } +} + + +uint8_t +ao_sample(void) +{ + ao_config_get(); + ao_wakeup(DATA_TO_XDATA(&ao_sample_data)); + ao_sleep((void *) DATA_TO_XDATA(&ao_data_head)); + while (ao_sample_data != ao_data_head) { + __xdata struct ao_data *ao_data; + + /* Capture a sample */ + ao_data = (struct ao_data *) &ao_data_ring[ao_sample_data]; + ao_sample_tick = ao_data->tick; + + ao_data_pres_cook(ao_data); + ao_sample_pres = ao_data_pres(ao_data); + ao_sample_alt = pres_to_altitude(ao_sample_pres); + ao_sample_height = ao_sample_alt - ao_ground_height; + +#if HAS_ACCEL + ao_sample_accel = ao_data_accel_cook(ao_data); + if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) + ao_sample_accel = ao_data_accel_invert(ao_sample_accel); + ao_data_set_accel(ao_data, ao_sample_accel); +#endif + + if (ao_preflight) + ao_sample_preflight(); + else + ao_kalman(); + ao_sample_data = ao_data_ring_next(ao_sample_data); + } + return !ao_preflight; +} + +void +ao_sample_init(void) +{ + nsamples = 0; + ao_sample_pres_sum = 0; + ao_sample_pres = 0; +#if HAS_ACCEL + ao_sample_accel_sum = 0; + ao_sample_accel = 0; +#endif + ao_sample_data = ao_data_head; + ao_preflight = TRUE; +} diff --git a/src/core/ao_sample_mm.c b/src/core/ao_sample_mm.c deleted file mode 100644 index ac11eef0..00000000 --- a/src/core/ao_sample_mm.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright © 2011 Keith Packard - * - * 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. - */ - -#ifndef AO_FLIGHT_TEST -#include "ao.h" -#include -#endif - -/* - * Current sensor values - */ - -#ifndef PRES_TYPE -#define PRES_TYPE int32_t -#define ALT_TYPE int32_t -#define ACCEL_TYPE int16_t -#endif - -__pdata uint16_t ao_sample_tick; /* time of last data */ -__pdata pres_t ao_sample_pres; -__pdata alt_t ao_sample_alt; -__pdata alt_t ao_sample_height; -#if HAS_ACCEL -__pdata accel_t ao_sample_accel; -#endif - -__data uint8_t ao_sample_data; - -/* - * Sensor calibration values - */ - -__pdata pres_t ao_ground_pres; /* startup pressure */ -__pdata alt_t ao_ground_height; /* MSL of ao_ground_pres */ - -#if HAS_ACCEL -__pdata accel_t ao_ground_accel; /* startup acceleration */ -__pdata accel_t ao_accel_2g; /* factory accel calibration */ -__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ -#endif - -static __pdata uint8_t ao_preflight; /* in preflight mode */ - -static __pdata uint16_t nsamples; -__pdata int32_t ao_sample_pres_sum; -#if HAS_ACCEL -__pdata int32_t ao_sample_accel_sum; -#endif - -static void -ao_sample_preflight(void) -{ - /* startup state: - * - * Collect 512 samples of acceleration and pressure - * data and average them to find the resting values - */ - if (nsamples < 512) { -#if HAS_ACCEL - ao_sample_accel_sum += ao_sample_accel; -#endif - ao_sample_pres_sum += ao_sample_pres; - ++nsamples; - } else { - ao_config_get(); -#if HAS_ACCEL - ao_ground_accel = ao_sample_accel_sum >> 9; - ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g; - ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g; -#endif - ao_ground_pres = ao_sample_pres_sum >> 9; - ao_ground_height = pres_to_altitude(ao_ground_pres); - ao_preflight = FALSE; - } -} - - -uint8_t -ao_sample(void) -{ - ao_config_get(); - ao_wakeup(DATA_TO_XDATA(&ao_sample_data)); - ao_sleep((void *) DATA_TO_XDATA(&ao_data_head)); - while (ao_sample_data != ao_data_head) { - __xdata struct ao_data *ao_data; - - /* Capture a sample */ - ao_data = (struct ao_data *) &ao_data_ring[ao_sample_data]; - ao_sample_tick = ao_data->tick; - - ao_data_pres_cook(ao_data); - ao_sample_pres = ao_data_pres(ao_data); - ao_sample_alt = pres_to_altitude(ao_sample_pres); - ao_sample_height = ao_sample_alt - ao_ground_height; - -#if HAS_ACCEL - ao_sample_accel = ao_data_accel_cook(ao_data); - if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) - ao_sample_accel = ao_data_accel_invert(ao_sample_accel); - ao_data_set_accel(ao_data, ao_sample_accel); -#endif - - if (ao_preflight) - ao_sample_preflight(); - else - ao_kalman(); - ao_sample_data = ao_data_ring_next(ao_sample_data); - } - return !ao_preflight; -} - -void -ao_sample_init(void) -{ - nsamples = 0; - ao_sample_pres_sum = 0; - ao_sample_pres = 0; -#if HAS_ACCEL - ao_sample_accel_sum = 0; - ao_sample_accel = 0; -#endif - ao_sample_data = ao_data_head; - ao_preflight = TRUE; -} diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index 6fc9324e..13e46c97 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -67,9 +67,9 @@ ALTOS_SRC = \ ao_convert_pa.c \ ao_log.c \ ao_log_mega.c \ - ao_sample_mm.c \ + ao_sample.c \ ao_kalman.c \ - ao_flight_mm.c \ + ao_flight.c \ ao_telemetry.c \ ao_packet_slave.c \ ao_packet.c \ diff --git a/src/product/Makefile.telemetrum b/src/product/Makefile.telemetrum index fba2c19a..57586c95 100644 --- a/src/product/Makefile.telemetrum +++ b/src/product/Makefile.telemetrum @@ -36,8 +36,8 @@ CORE_SRC = \ ao_stdio.c \ ao_storage.c \ ao_task.c \ - ao_flight_mm.c \ - ao_sample_mm.c \ + ao_flight.c \ + ao_sample.c \ ao_kalman.c \ ao_log.c \ ao_log_big.c \ diff --git a/src/product/Makefile.telemini b/src/product/Makefile.telemini index f0ab2b14..23aed1c7 100644 --- a/src/product/Makefile.telemini +++ b/src/product/Makefile.telemini @@ -24,14 +24,14 @@ CORE_SRC = \ ao_cmd.c \ ao_config.c \ ao_convert.c \ - ao_flight_mm.c \ + ao_flight.c \ ao_kalman.c \ ao_log.c \ ao_log_tiny.c \ ao_mutex.c \ ao_panic.c \ ao_report.c \ - ao_sample_mm.c \ + ao_sample.c \ ao_stdio.c \ ao_storage.c \ ao_task.c \ diff --git a/src/product/Makefile.telenano b/src/product/Makefile.telenano index a55bcf95..ca719bbf 100644 --- a/src/product/Makefile.telenano +++ b/src/product/Makefile.telenano @@ -31,7 +31,7 @@ CORE_SRC = \ ao_mutex.c \ ao_panic.c \ ao_report.c \ - ao_sample_mm.c \ + ao_sample.c \ ao_stdio.c \ ao_storage.c \ ao_task.c \ diff --git a/src/test/Makefile b/src/test/Makefile index 4631fb78..963f4131 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -4,7 +4,7 @@ PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noi KALMAN=make-kalman -CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g -Wall +CFLAGS=-I.. -I. -I../core -I../drivers -O3 -g -Wall all: $(PROGS) @@ -13,10 +13,10 @@ clean: install: -ao_flight_test: ao_flight_test.c ao_host.h ao_flight_mm.c ao_sample_mm.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 ao_kalman.h cc $(CFLAGS) -o $@ $< -ao_flight_test_noisy_accel: ao_flight_test.c ao_host.h ao_flight_mm.c ao_sample_mm.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 altitude.h ao_kalman.h 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 @@ -42,3 +42,6 @@ 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 + +check: ao_fec_test ao_flight_test ao_flight_test_baro run-tests + ./ao_fec_test && ./run-tests \ No newline at end of file diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index baf2ad1d..9bb03d68 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -141,7 +141,7 @@ struct ao_task { int dummy; }; -#define ao_add_task(t,f,n) +#define ao_add_task(t,f,n) ((void) (t)) #define ao_log_start() #define ao_log_stop() @@ -156,6 +156,7 @@ int ao_flight_debug; FILE *emulator_in; char *emulator_app; char *emulator_name; +char *emulator_info; double emulator_error_max = 4; double emulator_height_error_max = 20; /* noise in the baro sensor */ @@ -199,6 +200,7 @@ struct ao_config ao_config; #define DATA_TO_XDATA(x) (x) #define HAS_FLIGHT 1 +#define HAS_IGNITE 1 #define HAS_ADC 1 #define HAS_USB 1 #define HAS_GPS 1 @@ -223,8 +225,8 @@ int ao_sample_prev_tick; uint16_t prev_tick; #include "ao_kalman.c" -#include "ao_sample_mm.c" -#include "ao_flight_mm.c" +#include "ao_sample.c" +#include "ao_flight.c" #define to_double(f) ((f) / 65536.0) @@ -259,10 +261,11 @@ ao_test_exit(void) main_error = fabs(ao_test_main_height_time - main_time); landed_error = fabs(ao_test_landed_height - landed_height); landed_time_error = ao_test_landed_time - landed_time; - if (drogue_error > emulator_error_max || main_error > emulator_error_max || - landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) { + if (drogue_error > emulator_error_max || main_error > emulator_error_max) { printf ("%s %s\n", emulator_app, emulator_name); + if (emulator_info) + printf ("\t%s\n", emulator_info); printf ("\tApogee error %g\n", drogue_error); printf ("\tMain error %g\n", main_error); printf ("\tLanded height error %g\n", landed_error); @@ -477,10 +480,9 @@ void ao_sleep(void *wchan) { if (wchan == &ao_data_head) { - char type; - uint16_t tick; - uint16_t a, b; - int ret; + char type = 0; + uint16_t tick = 0; + uint16_t a = 0, b = 0; uint8_t bytes[1024]; union ao_telemetry_all telem; char line[1024]; @@ -676,13 +678,15 @@ 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) +void run_flight_fixed(char *name, FILE *f, int summary, char *info) { emulator_name = name; emulator_in = f; + emulator_info = info; ao_summary = summary; ao_flight_init(); ao_flight(); @@ -694,13 +698,14 @@ main (int argc, char **argv) int summary = 0; int c; int i; + char *info = NULL; #if HAS_ACCEL emulator_app="full"; #else emulator_app="baro"; #endif - while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "sdi:", options, NULL)) != -1) { switch (c) { case 's': summary = 1; @@ -708,11 +713,14 @@ main (int argc, char **argv) case 'd': ao_flight_debug = 1; break; + case 'i': + info = optarg; + break; } } if (optind == argc) - run_flight_fixed("", stdin, summary); + run_flight_fixed("", stdin, summary, info); else for (i = optind; i < argc; i++) { FILE *f = fopen(argv[i], "r"); @@ -720,7 +728,8 @@ main (int argc, char **argv) perror(argv[i]); continue; } - run_flight_fixed(argv[i], f, summary); + run_flight_fixed(argv[i], f, summary, info); fclose(f); } + exit(0); } -- cgit v1.2.3 From b89d37d357273b97050c00d7fe12022e32799fa8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jul 2012 15:13:55 -0700 Subject: altos: add some (unused) test code for different soft-decision sizes This lets us experiment with hard-decision and other possible soft_decision bit depths. Signed-off-by: Keith Packard --- src/test/ao_fec_test.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/test') diff --git a/src/test/ao_fec_test.c b/src/test/ao_fec_test.c index b94b16dc..216a4b79 100644 --- a/src/test/ao_fec_test.c +++ b/src/test/ao_fec_test.c @@ -100,6 +100,7 @@ ao_fuzz (uint8_t *in, int in_len, uint8_t *out, double dev) { int i; int errors = 0; + int s; for (i = 0; i < in_len; i++) { double error = gaussian_random(0, dev); @@ -115,6 +116,24 @@ ao_fuzz (uint8_t *in, int in_len, uint8_t *out, double dev) else byte -= error; } + + /* abcd efgh 8 + * abcd efga 7 + * abcd efab 6 + * abcd eabc 5 + * abcd abcd 4 + * abca bcab 3 + * abab abab 2 + * aaaa aaaa 1 + */ + +#define SAVE 8 +#define SAVE_MASK (((1 << SAVE) - 1) << (8 - SAVE)) + + byte &= SAVE_MASK; + for (s = SAVE; s < 8; s += SAVE) + byte |= byte >> s; + out[i] = byte; } return errors; -- cgit v1.2.3 From a60c5a728530e4659a6750d8d5b87000735d4531 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jul 2012 15:15:00 -0700 Subject: altos: Improve ao_flight_test a bit Add -i flag to include flight description Have run-tests know how many failures to expect Add run_baro to plot a single flight using the baro-only mode Signed-off-by: Keith Packard --- src/test/run-baro | 31 +++++++++++++++++++++++++++++++ src/test/run-tests | 17 +++++++++++------ src/test/test-flights | 14 +++++++------- 3 files changed, 49 insertions(+), 13 deletions(-) create mode 100755 src/test/run-baro (limited to 'src/test') diff --git a/src/test/run-baro b/src/test/run-baro new file mode 100755 index 00000000..21bab9fb --- /dev/null +++ b/src/test/run-baro @@ -0,0 +1,31 @@ +#!/bin/sh + +for i in "$@"; do +./ao_flight_test_baro "$i" > run-out.baro + +#./ao_flight_test_accel "$i" > 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.baro" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ +"run-out.baro" using 1:5 with lines lw 2 lt 2 axes x1y2 title "raw accel",\ +"run-out.baro" using 1:9 with lines lt 3 axes x1y1 title "baro height",\ +"run-out.baro" using 1:11 with lines lt 4 axes x1y2 title "baro speed",\ +"run-out.baro" using 1:13 with lines lt 5 axes x1y2 title "baro accel",\ +"run-out.baro" using 1:17 with lines lt 6 axes x1y1 title "baro drogue",\ +"run-out.baro" using 1:19 with lines lt 7 axes x1y1 title "baro main" +pause mouse close +EOF +done \ No newline at end of file diff --git a/src/test/run-tests b/src/test/run-tests index a8a8dc3f..4edecf1a 100755 --- a/src/test/run-tests +++ b/src/test/run-tests @@ -2,21 +2,26 @@ DIR=~/misc/rockets/flights +expect_baro=2 +expect_full=5 + bad_baro=0 bad_full=0 while read flight description; do - if ./ao_flight_test_baro -s $DIR/$flight; then + if ./ao_flight_test_baro -s -i "$description" $DIR/$flight; then : else : $((bad_baro++)) fi - if ./ao_flight_test -s $DIR/$flight; then + if ./ao_flight_test -s -i "$description" $DIR/$flight; then : else : $((bad_full++)) fi done < test-flights -echo baro errors $bad_baro -echo full errors $bad_full -: $((bad = bad_baro + bad_full)) -exit $bad \ No newline at end of file +echo baro errors $bad_baro expected $expect_baro +echo full errors $bad_full expected $expect_full +: $((miss_baro = bad_baro > expect_baro ? bad_baro - expect_baro : expect_baro - bad_baro)) +: $((miss_full = bad_full > expect_full ? bad_full - expect_full : expect_full - bad_full)) +: $((miss = miss_baro + miss_full)) +exit $miss \ No newline at end of file diff --git a/src/test/test-flights b/src/test/test-flights index f6b3b992..12f62ea9 100644 --- a/src/test/test-flights +++ b/src/test/test-flights @@ -29,7 +29,7 @@ 2010-02-28-serial-052-flight-004.eeprom LDDD Tillamook airport, 2010-02-28, I161 2010-03-06-serial-010-flight-004.eeprom Robert's Lil Nuke at Hudson Ranch on a CTI 108G57CL Pro29 2010-03-06-serial-013-flight-003.eeprom Trick-O-Treat at Hudson Ranch on a J595BS -2010-03-06-serial-051-flight-003.eeprom G-Spot at Hudson Ranch on an H180W +2010-03-06-serial-051-flight-003.eeprom G-Spot at Hudson Ranch on an H180W (apogee early, fools ao_flight_test_baro) 2010-03-06-serial-053-flight-004.eeprom Horizon Rebuilt at Hudson Ranch on a J530IM with MAWD as backup 2010-05-08-serial-229-flight-002.eeprom First customer flight on a sparky. 2010-05-28-serial-215-flight-002.eeprom Mike's L1 cert flight. Congrats! @@ -38,28 +38,28 @@ 2010-05-30-serial-010-flight-005.eeprom Robert's Lil Nuke on a 84G88 Smoky Sam at Mile High Mayhem 2010 Version 0.1 TeleMetrum with 5010 GPS board. 2010-05-30-serial-051-flight-004.eeprom Bdale's G-Spot on a CTI 298H159 Green3 at Mile High Mayhem 2010 2010-05-30-serial-224-flight-003.eeprom Bill Mott's L3 cert flight -2010-05-30-serial-226-flight-001.eeprom Robert's RG-2 on a 159G54RL at Mile High Mayhem. Very noise accel data, early apogee +2010-05-30-serial-226-flight-001.eeprom Robert's RG-2 on a 159G54RL at Mile High Mayhem. Very noise accel data, early apogee (fools full) 2010-05-31-serial-010-flight-006.eeprom Robert's Lil Nuke with a v0.1 TeleMetrum and 5010 GPS board flying on a 159G118 Blue Streak on the last day of Mile High Mayhem 2010 2010-05-31-serial-216-flight-001.eeprom Sharp Stick in the Sky on an "I something" EX motor from James Russell -2010-05-31-serial-219-flight-001.eeprom Candy Cane on CTI K300 at MHM. +2010-05-31-serial-219-flight-001.eeprom Candy Cane on CTI K300 at MHM. (accel noise fools full) 2010-05-31-serial-227-flight-003.eeprom Mike's Rocket on J285 for successful L2 cert at MHM 2010-06-05-serial-220-flight-001.eeprom Mini-mmuchness on 159G54RL, Sunday at MHM 2010 2010-06-26-serial-209-flight-003.eeprom Tripoli Colorado Spring Fling with COSROCS at the Buffalo Ranch -2010-06-26-serial-215-flight-004.eeprom Tripoli Colorado Spring Fling with COSROCS at the Buffalo Ranch +2010-06-26-serial-215-flight-004.eeprom Tripoli Colorado Spring Fling with COSROCS at the Buffalo Ranch (accel noise fools full) 2010-06-26-serial-220-flight-002.eeprom Mini Mmuchness on CTI H120CL to 1975m, OROC June 2010 2010-06-26-serial-226-flight-002.eeprom Tripoli Colorado Spring Fling with COSROCS at the Buffalo Ranch 2010-06-27-serial-221-flight-002.eeprom PSAS LV2c on N2000 at OROC june launch 2010-07-17-serial-230-flight-001.eeprom Mike Ward's Level 1 cert flight on H225 2010-07-18-serial-219-flight-002.eeprom MMuchness on M1230 for successful L3 cert flight 2010-08-07-serial-216-flight-003.eeprom Sharp stick on I300T at Metra's august launch. Main out at apogee. -2010-08-07-serial-220-flight-003.eeprom Mini-mmuchness flight at Metra after debconf. Unstable on G80. ABNORMAL FLIGHT. -2010-08-12-serial-236-flight-001.eeprom Edgar's L1 flight, Madcow Momba on Aerotech H128 +2010-08-07-serial-220-flight-003.eeprom Mini-mmuchness flight at Metra after debconf. Unstable on G80. ABNORMAL FLIGHT. (fools full) +2010-08-12-serial-236-flight-001.eeprom Edgar's L1 flight, Madcow Momba on Aerotech H128 (early apogee charge fools baro) 2010-08-21-serial-010-flight-007.eeprom Robert's Lil Nuke, flying on a CTI Pro29 2-grain 110G250 Vmax. Just awesome! PFND. 2010-08-21-serial-224-flight-004.eeprom Anthony Towns' LDDD clone, successful L1 cert on a CTI Pro38 2-grain 266H125 classic. Airframe was set up for apogee-only with motor based ejection. The BP charge was larger than necessary, caused nose cone to snap back against aft airframe. Minor damage to leading edge of aft airframe, big chunk of the nose cone skin cracked away. Same problem Bdale saw on Sharp Stick's nosecone, also from Performance Rocketry, where there was apparently an air bubble below the gel coat. Determination was that damage was cosmetic and would not affect cert... confirmed by successful L2 later in the day! 2010-08-21-serial-224-flight-005.eeprom Anthony Towns' LDDD clone, successful L2 cert on a CTI Pro38 5-grain 58J357 blue streak. Perfect drogueless dual deploy! 0.8-0.9 grams aft charge and about 1.0 grams forward. Flew without ground testing charges due to time pressure before waiver closed for the day. About as close to the waiver as you'd ever want to be on a cert flight, again demonstrating that OpenRocket under-estimates apogee ... approximately 6800 ft predicted... 2010-08-21-serial-233-flight-002.eeprom Tim van Milligan's 5.5" L2 airframe, flying on a CTI Pro38 6-grain 774J410 red, TM indicated a problem with the apogee igniter continuity, noticed during countdown, turned out to be a loose wire! Perfect dual deploy flight once that was fixed. 2010-09-03-serial-051-flight-005.eeprom G-spot on an old Aerotech H125-20W single use 29mm motor. It appears the ejection at apogee actually happened much later, perhaps as much as 10 seconds late! -2010-09-03-serial-215-flight-005.eeprom Horizon Rebuild on a K490 Green3 reload. PFND. About 1.4 grams each end. +2010-09-03-serial-215-flight-005.eeprom Horizon Rebuild on a K490 Green3 reload. PFND. About 1.4 grams each end. (accel noise fools full) 2010-09-24-serial-236-flight-006.eeprom LDDD on I236 in Sheridan on 2010-09-24 to 1216m 2010-09-25-serial-223-flight-001.eeprom Bdale's 10" Goblin, flying on a CTI Pro75 M1300 Imax dual thrust during Chili Blaster 2 at Hudson Ranch. First flight after rebuild to do dual deploy from one bay with ARRD and 15' surplus "+ sign" parachute. 2010-10-17-serial-215-flight-006.eeprom Horizon Rebuild on CTI J595BS at Tripoli Colorado launch site near Hartsel, CO -- cgit v1.2.3 From aafa8859ecb27383f697b98f6991643b44f4721a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jul 2012 20:32:31 -0700 Subject: altos: Save some memory. A few minor space savings in ao_cmd.c and ao_config.c. Don't build unused conversion functions ao_altitude_to_pres and ao_temp_to_dC Signed-off-by: Keith Packard --- src/core/ao_cmd.c | 24 +++++++++++++----------- src/core/ao_config.c | 26 ++++++++++++++------------ src/core/ao_convert.c | 4 ++++ src/core/ao_convert_test.c | 5 +++-- src/test/ao_flight_test.c | 1 + 5 files changed, 35 insertions(+), 25 deletions(-) (limited to 'src/test') diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c index fbf0c347..05dbfb51 100644 --- a/src/core/ao_cmd.c +++ b/src/core/ao_cmd.c @@ -36,10 +36,16 @@ put_string(__code char *s) putchar(c); } +static void +backspace(void) +{ + put_string ("\010 \010"); +} + static void readline(void) { - __pdata char c; + char c; if (ao_echo()) put_string("> "); cmd_len = 0; @@ -50,7 +56,7 @@ readline(void) if (c == '\010' || c == '\177') { if (cmd_len != 0) { if (ao_echo()) - put_string("\010 \010"); + backspace(); --cmd_len; } continue; @@ -60,7 +66,7 @@ readline(void) if (c == '\025') { while (cmd_len != 0) { if (ao_echo()) - put_string("\010 \010"); + backspace(); --cmd_len; } continue; @@ -76,11 +82,8 @@ readline(void) break; } - if (cmd_len >= CMD_LEN - 2) { - if (ao_echo()) - putchar('\007'); + if (cmd_len >= CMD_LEN - 2) continue; - } cmd_line[cmd_len++] = c; if (ao_echo()) putchar(c); @@ -271,13 +274,12 @@ help(void) __pdata uint8_t cmds; __pdata uint8_t cmd; __code struct ao_cmds * __pdata cs; + const char *h; for (cmds = 0; cmds < ao_ncmds; cmds++) { cs = ao_cmds[cmds]; - for (cmd = 0; cs[cmd].func; cmd++) - printf("%-45s %s\n", - cs[cmd].help, - cs[cmd].help+1+strlen(cs[cmd].help)); + for (cmd = 0; (h = cs[cmd].help); cmd++) + printf("%-45s %s\n", h, h + 1 + strlen(h)); } } diff --git a/src/core/ao_config.c b/src/core/ao_config.c index cc580d66..e0dabcd9 100644 --- a/src/core/ao_config.c +++ b/src/core/ao_config.c @@ -78,6 +78,8 @@ ao_config_set_radio(void) static void _ao_config_get(void) { + uint8_t minor; + if (ao_config_loaded) return; #if HAS_EEPROM @@ -97,37 +99,37 @@ _ao_config_get(void) ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign)); ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN), sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1); - ao_config_dirty = 1; } - if (ao_config.minor != AO_CONFIG_MINOR) { + minor = ao_config.minor; + if (minor != AO_CONFIG_MINOR) { /* Fixups for minor version 1 */ - if (ao_config.minor < 1) + if (minor < 1) ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY; /* Fixups for minor version 2 */ - if (ao_config.minor < 2) { + if (minor < 2) { ao_config.accel_plus_g = 0; ao_config.accel_minus_g = 0; } /* Fixups for minor version 3 */ #if HAS_RADIO - if (ao_config.minor < 3) + if (minor < 3) ao_config.radio_cal = ao_radio_cal; #endif /* Fixups for minor version 4 */ - if (ao_config.minor < 4) + if (minor < 4) ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; /* Fixupes for minor version 5 */ - if (ao_config.minor < 5) + if (minor < 5) ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; - if (ao_config.minor < 6) + if (minor < 6) ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; - if (ao_config.minor < 8) + if (minor < 8) ao_config.radio_enable = TRUE; - if (ao_config.minor < 9) + if (minor < 9) ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN); - if (ao_config.minor < 10) + if (minor < 10) ao_config.frequency = 434550; - if (ao_config.minor < 11) + if (minor < 11) ao_config.apogee_lockout = 0; ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; diff --git a/src/core/ao_convert.c b/src/core/ao_convert.c index 0969f107..aa9b5f48 100644 --- a/src/core/ao_convert.c +++ b/src/core/ao_convert.c @@ -41,6 +41,7 @@ ao_pres_to_altitude(int16_t pres) __reentrant (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS; } +#if AO_NEED_ALTITUDE_TO_PRES int16_t ao_altitude_to_pres(int16_t alt) __reentrant { @@ -66,7 +67,9 @@ ao_altitude_to_pres(int16_t alt) __reentrant pres = 0; return (int16_t) pres; } +#endif +#if 0 int16_t ao_temp_to_dC(int16_t temp) __reentrant { @@ -83,3 +86,4 @@ ao_temp_to_dC(int16_t temp) __reentrant ret = ((temp - 19791) * 1012L) >> 16; return ret; } +#endif diff --git a/src/core/ao_convert_test.c b/src/core/ao_convert_test.c index e2c28b73..87e76841 100644 --- a/src/core/ao_convert_test.c +++ b/src/core/ao_convert_test.c @@ -17,14 +17,15 @@ #include #define AO_CONVERT_TEST +#define AO_NEED_ALTITUDE_TO_PRES 1 #include "ao_host.h" #include "ao_convert.c" #define STEP 1 -static inline i_abs(int i) { return i < 0 ? -i : i; } +static inline int i_abs(int i) { return i < 0 ? -i : i; } -main () +int main (int argc, char **argv) { int i; int16_t p_to_a, p_to_a_to_p; diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 9bb03d68..a4ef8dc0 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -180,6 +180,7 @@ struct ao_cmds { #define ao_xmemset(d,v,c) memset(d,v,c) #define ao_xmemcmp(d,s,c) memcmp(d,s,c) +#define AO_NEED_ALTITUDE_TO_PRES 1 #include "ao_convert.c" struct ao_config { -- cgit v1.2.3 From 18431c88c8a6cb267922b97192e8b7ddb88d0e7e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 13:49:26 -0700 Subject: altos: Have 'make clean' remove all programs, even old ones This makes sure that changing version numbers doesn't leave old compiled output lying around. Signed-off-by: Keith Packard --- src/cc1111/Makefile.cc1111 | 8 ++++++++ src/megametrum-v0.1/Makefile | 5 +++-- src/product/Makefile.telebt | 13 +++++-------- src/product/Makefile.teledongle | 9 +++------ src/product/Makefile.telelaunch | 9 +++------ src/product/Makefile.telemetrum | 9 +++------ src/product/Makefile.telemini | 9 +++------ src/product/Makefile.telenano | 9 +++------ src/stm-demo/Makefile | 2 +- src/teleballoon-v1.1/Makefile | 13 +++++-------- src/telescience-v0.1/Makefile | 2 +- src/teleshield-v0.1/Makefile | 9 +++------ src/teleterra-v0.2/Makefile | 9 +++------ src/test/Makefile | 2 +- src/tidongle/Makefile | 9 +++------ 15 files changed, 48 insertions(+), 69 deletions(-) (limited to 'src/test') diff --git a/src/cc1111/Makefile.cc1111 b/src/cc1111/Makefile.cc1111 index 8de4a9b2..f7ecce33 100644 --- a/src/cc1111/Makefile.cc1111 +++ b/src/cc1111/Makefile.cc1111 @@ -25,3 +25,11 @@ PAOM=$(PROG:.ihx=) %.rel : %.c $(INC) $(call quiet,CC,$(PRODUCT_DEF)) $(CFLAGS) -c -o$@ $< + +all: + +clean-cc1111: + rm -f *.adb *.asm *.lnk *.lst *.rel *.rst *.sym + rm -f $(PROGNAME)-* + rm -f ao_product.h + rm -f ../$(PROGNAME)-* diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index 13e46c97..59cfb64d 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -82,7 +82,8 @@ IDPRODUCT=0x0023 CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g -PROG=megametrum-v0.1-$(VERSION).elf +PROGNAME=megametrum-v0.1 +PROG=$(PROGNAME)-$(VERSION).elf SRC=$(ALTOS_SRC) ao_megametrum.c OBJ=$(SRC:.c=.o) @@ -103,7 +104,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean clean: - rm -f $(OBJ) + rm -f *.o $(PROGNAME)-*.elf rm -f ao_product.h install: diff --git a/src/product/Makefile.telebt b/src/product/Makefile.telebt index 90525d63..fd52cec4 100644 --- a/src/product/Makefile.telebt +++ b/src/product/Makefile.telebt @@ -60,7 +60,8 @@ SRC = \ $(PRODUCT_SRC) \ $(TELEBT_SRC) -PROG = telebt-v$(TELEBT_VER)-$(VERSION).ihx +PROGNAME = telebt-v$(TELEBT_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleBT-v$(TELEBT_VER) PRODUCT_DEF=-DTELEBT_V_$(TELEBT_DEF) IDPRODUCT=0x000e @@ -78,9 +79,9 @@ endif # Otherwise, print the full command line. quiet ?= $($1) -all: ../$(PROG) +all: $(PROG) -../$(PROG): $(REL) Makefile +$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@ @@ -89,11 +90,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/product/Makefile.teledongle b/src/product/Makefile.teledongle index fbf14a04..5105b567 100644 --- a/src/product/Makefile.teledongle +++ b/src/product/Makefile.teledongle @@ -60,7 +60,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = teledongle-v$(TD_VER)-$(VERSION).ihx +PROGNAME = teledongle-v$(TD_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleDongle-v$(TD_VER) PRODUCT_DEF=-DTELEDONGLE_V_$(TD_DEF) IDPRODUCT=0x000c @@ -89,11 +90,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/product/Makefile.telelaunch b/src/product/Makefile.telelaunch index 3753f3c9..1e55989c 100644 --- a/src/product/Makefile.telelaunch +++ b/src/product/Makefile.telelaunch @@ -62,7 +62,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = telelaunch-v$(TELELAUNCH_VER)-$(VERSION).ihx +PROGNAME = telelaunch-v$(TELELAUNCH_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleLaunch-v$(TELELAUNCH_VER) PRODUCT_DEF=-DTELELAUNCH_V_$(TELELAUNCH_DEF) IDPRODUCT=0x000f @@ -92,11 +93,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/product/Makefile.telemetrum b/src/product/Makefile.telemetrum index 57586c95..5e3eed7f 100644 --- a/src/product/Makefile.telemetrum +++ b/src/product/Makefile.telemetrum @@ -75,7 +75,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = telemetrum-v$(TM_VER)-$(VERSION)$(TM_EXTRA).ihx +PROGNAME = telemetrum-v$(TM_VER)$(TM_EXTRA) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleMetrum-v$(TM_VER) PRODUCT_DEF=-DTELEMETRUM_V_$(TM_DEF) IDPRODUCT=0x000b @@ -104,11 +105,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/product/Makefile.telemini b/src/product/Makefile.telemini index 23aed1c7..ef8906ba 100644 --- a/src/product/Makefile.telemini +++ b/src/product/Makefile.telemini @@ -63,7 +63,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = telemini-v$(TELEMINI_VER)-$(VERSION).ihx +PROGNAME = telemini-v$(TELEMINI_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleMini-v$(TELEMINI_VER) PRODUCT_DEF=-DTELEMINI_V_$(TELEMINI_DEF) IDPRODUCT=0x000a @@ -93,11 +94,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/product/Makefile.telenano b/src/product/Makefile.telenano index ca719bbf..67410ae0 100644 --- a/src/product/Makefile.telenano +++ b/src/product/Makefile.telenano @@ -62,7 +62,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = telenano-v$(TELENANO_VER)-$(VERSION).ihx +PROGNAME = telenano-v$(TELENANO_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleNano-v$(TELENANO_VER) PRODUCT_DEF=-DTELENANO_V_$(TELENANO_DEF) IDPRODUCT=0x000a @@ -92,11 +93,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/stm-demo/Makefile b/src/stm-demo/Makefile index dd7e6e02..055a73af 100644 --- a/src/stm-demo/Makefile +++ b/src/stm-demo/Makefile @@ -61,7 +61,7 @@ $(OBJ): $(INC) distclean: clean clean: - rm -f $(OBJ) + rm -f *.o $(PROG) rm -f ao_product.h install: diff --git a/src/teleballoon-v1.1/Makefile b/src/teleballoon-v1.1/Makefile index fb88787b..2eea996e 100644 --- a/src/teleballoon-v1.1/Makefile +++ b/src/teleballoon-v1.1/Makefile @@ -81,7 +81,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = teleballoon-v$(TELEBALLOON_VER)-$(VERSION).ihx +PROGNAME = teleballoon-v$(TELEBALLOON_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleBalloon-v$(TELEBALLOON_VER) PRODUCT_DEF=-DTELEBALLOON_V_$(TELEBALLOON_DEF) IDPRODUCT=0x000b @@ -99,9 +100,9 @@ endif # Otherwise, print the full command line. quiet ?= $($1) -all: ../$(PROG) +all: $(PROG) -../$(PROG): $(REL) Makefile +$(PROG): $(REL) Makefile $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) .. $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@ @@ -110,11 +111,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/telescience-v0.1/Makefile b/src/telescience-v0.1/Makefile index 10e4a2a3..d24128ef 100644 --- a/src/telescience-v0.1/Makefile +++ b/src/telescience-v0.1/Makefile @@ -105,7 +105,7 @@ ao_product.o: ao_product.c ao_product.h distclean: clean clean: - rm -f $(OBJ) + rm -f *.o $(PROG) $(PROG).hex rm -f ao_product.h install: diff --git a/src/teleshield-v0.1/Makefile b/src/teleshield-v0.1/Makefile index c1f45f37..ab2a025f 100644 --- a/src/teleshield-v0.1/Makefile +++ b/src/teleshield-v0.1/Makefile @@ -72,7 +72,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = teleshield-v$(TELESHIELD_VER)-$(VERSION).ihx +PROGNAME = teleshield-v$(TELESHIELD_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleShield-v$(TELESHIELD_VER) PRODUCT_DEF=-DTELESHIELD_V_$(TELESHIELD_DEF) IDPRODUCT=0x0013 @@ -102,11 +103,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/teleterra-v0.2/Makefile b/src/teleterra-v0.2/Makefile index 4967d187..65db57ce 100644 --- a/src/teleterra-v0.2/Makefile +++ b/src/teleterra-v0.2/Makefile @@ -66,7 +66,8 @@ SRC = \ TELETERRA_VER=0.2 TELETERRA_DEF=0_2 -PROG = teleterra-v$(TELETERRA_VER)-$(VERSION).ihx +PROGNAME = teleterra-v$(TELETERRA_VER) +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TeleTerra-v$(TELETERRA_VER) PRODUCT_DEF=-DTELETERRA_V_$(TELETERRA_DEF) IDPRODUCT=0x000d @@ -95,11 +96,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: diff --git a/src/test/Makefile b/src/test/Makefile index 963f4131..db3cc04b 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -9,7 +9,7 @@ CFLAGS=-I.. -I. -I../core -I../drivers -O3 -g -Wall all: $(PROGS) clean: - rm -f $(PROGS) + rm -f $(PROGS) run-out.baro run-out.full install: diff --git a/src/tidongle/Makefile b/src/tidongle/Makefile index 0bb2ce32..1514c4df 100644 --- a/src/tidongle/Makefile +++ b/src/tidongle/Makefile @@ -53,7 +53,8 @@ SRC = \ $(DRIVER_SRC) \ $(PRODUCT_SRC) -PROG = tidongle-$(VERSION).ihx +PROGNAME = tidongle +PROG = $(PROGNAME)-$(VERSION).ihx PRODUCT=TIDongle PRODUCT_DEF=-DTIDONGLE IDPRODUCT=0x000a @@ -82,11 +83,7 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: - rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) - rm -f $(PROG) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) - rm -f ao_product.h - rm -f ../$(PROG) ../$(PMAP) +clean: clean-cc1111 install: -- cgit v1.2.3 From cf44ea354c2d1780cee343132c6058e11e9eefa3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 13:52:32 -0700 Subject: altos: Fix gcc compiler warnings in GPS code unused variables and mis-matches in printf format codes. Signed-off-by: Keith Packard --- src/core/ao_gps_print.c | 4 ++-- src/drivers/ao_gps_skytraq.c | 2 +- src/test/ao_gps_test.c | 7 ++++++- src/test/ao_gps_test_skytraq.c | 12 +++++++++--- 4 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src/test') diff --git a/src/core/ao_gps_print.c b/src/core/ao_gps_print.c index fcdedd30..47c945d7 100644 --- a/src/core/ao_gps_print.c +++ b/src/core/ao_gps_print.c @@ -40,8 +40,8 @@ ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant printf(AO_TELEM_GPS_LATITUDE " %ld " AO_TELEM_GPS_LONGITUDE " %ld " AO_TELEM_GPS_ALTITUDE " %d ", - gps_data->latitude, - gps_data->longitude, + (long) gps_data->latitude, + (long) gps_data->longitude, gps_data->altitude); if (gps_data->flags & AO_GPS_DATE_VALID) diff --git a/src/drivers/ao_gps_skytraq.c b/src/drivers/ao_gps_skytraq.c index 84616a05..d80da97c 100644 --- a/src/drivers/ao_gps_skytraq.c +++ b/src/drivers/ao_gps_skytraq.c @@ -480,7 +480,7 @@ gps_dump(void) __reentrant ao_mutex_get(&ao_gps_mutex); printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day); printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second); - printf ("Lat/Lon: %ld %ld\n", ao_gps_data.latitude, ao_gps_data.longitude); + printf ("Lat/Lon: %ld %ld\n", (long) ao_gps_data.latitude, (long) ao_gps_data.longitude); printf ("Alt: %d\n", ao_gps_data.altitude); printf ("Flags: 0x%x\n", ao_gps_data.flags); printf ("Sats: %d", ao_gps_tracking_data.channels); diff --git a/src/test/ao_gps_test.c b/src/test/ao_gps_test.c index 4d4012df..d75a12ec 100644 --- a/src/test/ao_gps_test.c +++ b/src/test/ao_gps_test.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #define AO_GPS_NUM_SAT_MASK (0xf << 0) #define AO_GPS_NUM_SAT_SHIFT (0) @@ -220,6 +221,8 @@ check_sirf_message(char *from, uint8_t *msg, int len) get_u16(h_v_error); + (void) mag_var; + (void) id; printf ("Geodetic Navigation Data (41):\n"); printf ("\tNav valid %04x\n", nav_valid); printf ("\tNav type %04x\n", nav_type); @@ -257,6 +260,7 @@ check_sirf_message(char *from, uint8_t *msg, int len) get_u32(gps_tow); get_u8(channels); + (void) id; printf ("Measured Tracker Data (4):\n"); printf ("GPS week: %d\n", gps_week); printf ("GPS time of week: %d\n", gps_tow); @@ -368,10 +372,11 @@ ao_serial1_putchar(char c) i = write(ao_gps_fd, &c, 1); if (i == 1) { if ((uint8_t) c == 0xb3 || c == '\r') { - static const struct timespec delay = { +/* static const struct timespec delay = { .tv_sec = 0, .tv_nsec = 100 * 1000 * 1000 }; +*/ tcdrain(ao_gps_fd); // nanosleep(&delay, NULL); } diff --git a/src/test/ao_gps_test_skytraq.c b/src/test/ao_gps_test_skytraq.c index 88bed305..846daa94 100644 --- a/src/test/ao_gps_test_skytraq.c +++ b/src/test/ao_gps_test_skytraq.c @@ -22,6 +22,7 @@ #include #include #include +#include #define AO_GPS_NUM_SAT_MASK (0xf << 0) #define AO_GPS_NUM_SAT_SHIFT (0) @@ -87,6 +88,7 @@ ao_mutex_put(uint8_t *mutex) static int ao_gps_fd; +#if 0 static void ao_dbg_char(char c) { @@ -102,6 +104,7 @@ ao_dbg_char(char c) } write(1, line, strlen(line)); } +#endif #define QUEUE_LEN 4096 @@ -222,6 +225,8 @@ check_skytraq_message(char *from, uint8_t *msg, int len) get_u16(h_v_error); + (void) mag_var; + (void) id; printf ("Geodetic Navigation Data (41):\n"); printf ("\tNav valid %04x\n", nav_valid); printf ("\tNav type %04x\n", nav_type); @@ -259,6 +264,7 @@ check_skytraq_message(char *from, uint8_t *msg, int len) get_u32(gps_tow); get_u8(channels); + (void) id; printf ("Measured Tracker Data (4):\n"); printf ("GPS week: %d\n", gps_week); printf ("GPS time of week: %d\n", gps_tow); @@ -371,10 +377,11 @@ ao_serial1_putchar(char c) i = write(ao_gps_fd, &c, 1); if (i == 1) { if ((uint8_t) c == 0xb3 || c == '\r') { - static const struct timespec delay = { +/* static const struct timespec delay = { .tv_sec = 0, .tv_nsec = 100 * 1000 * 1000 }; +*/ tcdrain(ao_gps_fd); // nanosleep(&delay, NULL); } @@ -422,8 +429,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); else @@ -487,4 +492,5 @@ main (int argc, char **argv) exit (1); } ao_gps(); + return 0; } -- cgit v1.2.3 From 354c1fed7f06c2c45c661e7265c2ac4bc47e2750 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 30 Aug 2012 16:22:51 -0500 Subject: altos: Add a bunch of .gitignore entries Clean up the git status output Signed-off-by: Keith Packard --- ao-tools/ao-stmload/.gitignore | 1 + src/spiradio-v0.1/.gitignore | 2 ++ src/stm-bringup/bringup.ld | 69 ++++++++++++++++++++++++++++++++++++++++++ src/telefire-v0.1/.gitignore | 2 ++ src/test/.gitignore | 3 ++ 5 files changed, 77 insertions(+) create mode 100644 ao-tools/ao-stmload/.gitignore create mode 100644 src/spiradio-v0.1/.gitignore create mode 100644 src/stm-bringup/bringup.ld create mode 100644 src/telefire-v0.1/.gitignore (limited to 'src/test') diff --git a/ao-tools/ao-stmload/.gitignore b/ao-tools/ao-stmload/.gitignore new file mode 100644 index 00000000..dedb0094 --- /dev/null +++ b/ao-tools/ao-stmload/.gitignore @@ -0,0 +1 @@ +ao-stmload diff --git a/src/spiradio-v0.1/.gitignore b/src/spiradio-v0.1/.gitignore new file mode 100644 index 00000000..8e39138e --- /dev/null +++ b/src/spiradio-v0.1/.gitignore @@ -0,0 +1,2 @@ +spiradio-* +ao_product.h diff --git a/src/stm-bringup/bringup.ld b/src/stm-bringup/bringup.ld new file mode 100644 index 00000000..10d50cd6 --- /dev/null +++ b/src/stm-bringup/bringup.ld @@ -0,0 +1,69 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (!w) : ORIGIN = 0x20000000, LENGTH = 16K +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .text ORIGIN(rom) : { + __text_start__ = .; + *(.interrupt) /* Interrupt vectors */ + + *(.text*) /* Executable code */ + *(.rodata*) /* Constants */ + } > rom + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __text_end__ = .; + } > rom + + . = ORIGIN(ram); + __data_start__ = .; + + /* Data -- relocated to RAM, but written to ROM + */ + .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) { + *(.data) /* initialized data */ + __data_end__ = .; + __bss_start__ = .; + } >ram + + .bss : { + *(.bss) + *(COMMON) + __bss_end__ = .; + } >ram + + PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram)); + PROVIDE(end = .); + +} + +ENTRY(start); + + diff --git a/src/telefire-v0.1/.gitignore b/src/telefire-v0.1/.gitignore new file mode 100644 index 00000000..4d4f4200 --- /dev/null +++ b/src/telefire-v0.1/.gitignore @@ -0,0 +1,2 @@ +telefire-* +ao_product.h diff --git a/src/test/.gitignore b/src/test/.gitignore index 33c7ef35..5d528ab9 100644 --- a/src/test/.gitignore +++ b/src/test/.gitignore @@ -4,3 +4,6 @@ ao_flight_test_accel ao_gps_test ao_gps_test_skytraq ao_convert_test +ao_convert_pa_test +ao_fec_test +ao_flight_test_noisy_accel -- cgit v1.2.3 From 27ab744c6eec9243b7aa14161eec2fbf7003531e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Sep 2012 13:46:23 -0700 Subject: altos: Clean up flight data definitions These just shuffle the various definitions of data macros around to make the include files more sensible looking. Signed-off-by: Keith Packard --- src/core/ao_data.h | 64 +++++++++++++++++++++++++++++++++++------------ src/core/ao_sample.c | 2 ++ src/core/ao_sample.h | 17 +++++++------ src/test/ao_flight_test.c | 22 ++++++++-------- 4 files changed, 72 insertions(+), 33 deletions(-) (limited to 'src/test') diff --git a/src/core/ao_data.h b/src/core/ao_data.h index 5412febe..2b9ef5ac 100644 --- a/src/core/ao_data.h +++ b/src/core/ao_data.h @@ -95,15 +95,19 @@ extern volatile __data uint8_t ao_data_count; } while (0); /* - * Wait for data to be completed by looking at the - * indicated bit + * Wait until it is time to write a sensor sample; this is + * signaled by the timer tick */ #define AO_DATA_WAIT() do { \ ao_sleep((void *) &ao_data_count); \ } while (0) +#if !HAS_BARO && HAS_MS5607 -#if HAS_MS5607 +/* Either an MS5607 or an MS5611 hooked to a SPI port + */ + +#define HAS_BARO 1 typedef int32_t pres_t; typedef int32_t alt_t; @@ -115,7 +119,11 @@ typedef int32_t alt_t; #define pres_to_altitude(p) ao_pa_to_altitude(p) -#else /* HAS_MS5607 */ +#endif + +#if !HAS_BARO && HAS_ADC + +#define HAS_BARO 1 typedef int16_t pres_t; typedef int16_t alt_t; @@ -125,7 +133,7 @@ typedef int16_t alt_t; #define pres_to_altitude(p) ao_pres_to_altitude(p) #define ao_data_pres_cook(p) -#endif /* else HAS_MS5607 */ +#endif /* * Need a few macros to pull data from the sensors: @@ -136,17 +144,12 @@ typedef int16_t alt_t; * ao_data_accel_invert - flip rocket ends for positive acceleration */ -#if HAS_MPU6000 && !HAS_HIGHG_ACCEL - -typedef int16_t accel_t; - -/* MPU6000 is hooked up so that positive y is positive acceleration */ -#define ao_data_accel(packet) ((packet)->mpu6000.accel_y) -#define ao_data_accel_cook(packet) (-(packet)->mpu6000.accel_y) -#define ao_data_set_accel(packet, accel) ((packet)->mpu6000.accel_y = (accel)) -#define ao_data_accel_invert(a) (-(a)) +#if HAS_ACCEL -#else /* HAS_MPU6000 && !HAS_HIGHG_ACCEL */ +/* This section is for an analog accelerometer hooked to one of the ADC pins. As + * those are 5V parts, this also requires that the 5V supply be hooked to to anothe ADC + * pin so that the both can be measured to correct for changes between the 3.3V and 5V rails + */ typedef int16_t accel_t; #define ao_data_accel(packet) ((packet)->adc.accel) @@ -245,6 +248,35 @@ typedef int16_t accel_t; #endif /* HAS_ACCEL_REF */ -#endif /* else some other accel sensor */ +#endif /* HAS_ACCEL */ + +#if !HAS_ACCEL && HAS_MMA655X + +#define HAS_ACCEL 1 + +typedef int16_t accel_t; + +/* MMA655X is hooked up so that positive values represent negative acceleration */ + +#define ao_data_accel(packet) ((packet)->mma655x) +#define ao_data_accel_cook(packet) ((packet)->mma655x) +#define ao_data_set_accel(packet, accel) ((packet)->mma655x = (accel)) +#define ao_data_accel_invert(accel) (4095 - (accel)) + +#endif + +#if !HAS_ACCEL && HAS_MPU6000 + +#define HAS_ACCEL 1 + +typedef int16_t accel_t; + +/* MPU6000 is hooked up so that positive y is positive acceleration */ +#define ao_data_accel(packet) ((packet)->mpu6000.accel_y) +#define ao_data_accel_cook(packet) (-(packet)->mpu6000.accel_y) +#define ao_data_set_accel(packet, accel) ((packet)->mpu6000.accel_y = (accel)) +#define ao_data_accel_invert(a) (-(a)) + +#endif #endif /* _AO_DATA_H_ */ diff --git a/src/core/ao_sample.c b/src/core/ao_sample.c index 6461def0..985c0940 100644 --- a/src/core/ao_sample.c +++ b/src/core/ao_sample.c @@ -134,10 +134,12 @@ ao_sample(void) ao_data = (struct ao_data *) &ao_data_ring[ao_sample_data]; ao_sample_tick = ao_data->tick; +#if HAS_BARO ao_data_pres_cook(ao_data); ao_sample_pres = ao_data_pres(ao_data); ao_sample_alt = pres_to_altitude(ao_sample_pres); ao_sample_height = ao_sample_alt - ao_ground_height; +#endif #if HAS_ACCEL ao_sample_accel = ao_data_accel_cook(ao_data); diff --git a/src/core/ao_sample.h b/src/core/ao_sample.h index 189b2019..9336bdf9 100644 --- a/src/core/ao_sample.h +++ b/src/core/ao_sample.h @@ -69,7 +69,11 @@ /* * Above this height, the baro sensor doesn't work */ +#if HAS_MS5607 +#define AO_MAX_BARO_HEIGHT 30000 +#else #define AO_MAX_BARO_HEIGHT 12000 +#endif /* * Above this speed, baro measurements are unreliable @@ -90,20 +94,19 @@ #define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16)) extern __pdata uint16_t ao_sample_tick; /* time of last data */ -extern __pdata pres_t ao_sample_pres; /* most recent pressure sensor reading */ -extern __pdata alt_t ao_sample_alt; /* MSL of ao_sample_pres */ -extern __pdata alt_t ao_sample_height; /* AGL of ao_sample_pres */ extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */ extern __data uint8_t ao_sample_data; /* Ring position of last processed sample */ -#if HAS_ACCEL -extern __pdata accel_t ao_sample_accel; /* most recent accel sensor reading */ -#endif - +#if HAS_BARO +extern __pdata pres_t ao_sample_pres; /* most recent pressure sensor reading */ +extern __pdata alt_t ao_sample_alt; /* MSL of ao_sample_pres */ +extern __pdata alt_t ao_sample_height; /* AGL of ao_sample_pres */ extern __pdata pres_t ao_ground_pres; /* startup pressure */ extern __pdata alt_t ao_ground_height; /* MSL of ao_ground_pres */ +#endif #if HAS_ACCEL +extern __pdata accel_t ao_sample_accel; /* most recent accel sensor reading */ extern __pdata accel_t ao_ground_accel; /* startup acceleration */ extern __pdata accel_t ao_accel_2g; /* factory accel calibration */ extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */ diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index a4ef8dc0..b9e291ce 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -54,6 +54,15 @@ struct ao_adc { #define __code #define __reentrant +#define HAS_FLIGHT 1 +#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 #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5)) @@ -200,24 +209,17 @@ struct ao_config ao_config; #define DATA_TO_XDATA(x) (x) -#define HAS_FLIGHT 1 -#define HAS_IGNITE 1 -#define HAS_ADC 1 -#define HAS_USB 1 -#define HAS_GPS 1 -#ifndef HAS_ACCEL -#define HAS_ACCEL 1 -#define HAS_ACCEL_REF 0 -#endif #define GRAVITY 9.80665 extern int16_t ao_ground_accel, ao_flight_accel; extern int16_t ao_accel_2g; +typedef int16_t accel_t; + extern uint16_t ao_sample_tick; extern int16_t ao_sample_height; -extern int16_t ao_sample_accel; +extern accel_t ao_sample_accel; extern int32_t ao_accel_scale; extern int16_t ao_ground_height; extern int16_t ao_sample_alt; -- cgit v1.2.3