+commit f31d842d0e07a1893441cb89fb287b31b86d28c1
+Merge: 0fd503fb f615725c
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Jun 15 20:26:35 2020 -0600
+
+ Merge branch 'master' into branch-1.9
+
+commit f615725cb6f963cf46715e936e1d60ce7866c3bb
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 15 19:11:49 2020 -0700
+
+ Version 1.9.3
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 765d4c96510c823b4e9410c55ba8466438846029
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 22:50:40 2020 -0700
+
+ doc: Update doc for 1.9.3
+
+ Add release notes.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4ab5855abccf704cc4cdbafb0e995de0a0162af5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 21:37:44 2020 -0700
+
+ Update 1.9.3 release notes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d304f0ea2bfc48abc8c310828aa10c6d642065d0
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 14 00:04:31 2020 -0700
+
+ altos: Leave floating printf enabled on m3 devices
+
+ These devices all use floating point computations, so leave the
+ floating point printf included in case they print one of those
+ values. If we run short on flash space, we can switch back.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 91b6d1e56a37a2cfae53c3727feaaa40505f48d9
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 23:39:00 2020 -0700
+
+ altos: Fix printf format mis-matches
+
+ Lots of values passed to printf are 'long' instead of 'int', so
+ fix the formats to use the right size indicator.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d0adf3f44b4a1b4bfc966dd4841c74157f60d604
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 23:36:13 2020 -0700
+
+ altos: Remove newlib-nano defines from Makedefs.in
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4802fe6dcae0e57c2e992dde008e3bcc84ea8d7f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 23:13:35 2020 -0700
+
+ altos/test: Ignore ao_flight_test_mini binary
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f550b645438e9f41afe0a45ff09caf05cf20003f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 23:12:55 2020 -0700
+
+ map-server: Manifest files are generated now
+
+ Ignore in .gitignore
+ Remove in 'make clean'
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 52e0efd79e9043cde384089863920986a7331764
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 23:11:49 2020 -0700
+
+ Add EasyTimer firmware to packages and Releasing
+
+ Make sure we include EasyTimer bits where required
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 00646d2700a2f4cf500e716e5a111057e3820475
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 23:09:54 2020 -0700
+
+ Check for picolibc when testing arm compilers
+
+ Remove configuration checks for newlib as picolibc doesn't need
+ separate configuration variables.
+
+ Make sure test program actually links as this tests to make sure
+ picolibc is working.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b9cc05bd3d417c957f47a64493f4a22caf660c55
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 22:40:42 2020 -0700
+
+ doc: Update for EasyTimer
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d2eee4b8a3f358e2d649096149f3cedc1a39927e
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 13 22:39:35 2020 -0700
+
+ doc: Avoid mis-interpretation of '+' in device wiring tables
+
+ Looks like asciidoctor does something magic with '+' characters in
+ table contents. Avoid this by using +++. Sigh.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d779d8e5b1106aaec6170761e6f5bd4e8d5ac6e7
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 9 11:48:17 2020 -0700
+
+ altos: Fix HAS_FLIGHT_DEBUG for easytimer
+
+ Remove baro-specific bits of the debug output when
+ there's no barometer.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d9c84d834f7fb4f36cee815dec2642737f73edc4
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 9 11:47:22 2020 -0700
+
+ altos: Don't include baro-specific config values for easytimer
+
+ These settings aren't used on easytimer, so don't include them in the
+ configuration system. This makes sure they don't appear in altosui.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 97cd271b3febf36d3e9943cea8d74332a128060c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 9 11:46:31 2020 -0700
+
+ altosui: Remove six-axis pad orientation for easy timer
+
+ Wait until easytimer actually has six-axis support
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2781c187d58955bbac5c9fcf498c3b46a84a13d5
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 9 11:45:53 2020 -0700
+
+ altoslib: Fix easytimer voltage conversions
+
+ Battery and pyros all use the same circuit (100k/27k).
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b00a155bef319984ec2cf11898355edf94348a4a
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 22:08:28 2020 -0700
+
+ Add some release note notes
+
+commit 869bc258b727d2046835ac52a361d2ef529895ee
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 20:55:28 2020 -0700
+
+ altoslib: Add EasyTimer idle monitor support
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b07ca2827a498e6dd3c6b62819f71679291f9acc
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 5 17:15:10 2020 -0700
+
+ Add EasyTimer configuration support
+
+ Needed six-axis pad orientation support
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fa30825d015d92bdbc95d2684386beef9fe9dc01
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 21:26:23 2020 -0700
+
+ altos: Leave accel data in ring raw; swap for orientation on fetch
+
+ Instead of re-writing the acceleration data in the ring to adjust for
+ pad orientation, just leave it alone and flip it each time it is
+ fetched. Much simpler this way.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c246a366a6e0117e70abafc30db71c0545b88f6f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 21:05:17 2020 -0700
+
+ altos: Handle flight_log_max not being multiple of ao_storage_block
+
+ In this case, flight records start in the middle of an erase block, but
+ now end at the erase block before the next flight.
+
+ When checking for an empty log slot, the entire erase block containing
+ the start of the flight is checked to make sure it's clear, skipping
+ it if not.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 89726f5b1adceb243c5e2d5c958fc13c10f9a2d0
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 21:03:31 2020 -0700
+
+ altos: Round selected log size down to ao_storage_block multiple
+
+ There was some (broken) code that complained if the value set wasn't
+ correct, that has been replaced by code that accepts any value and
+ just rounds it down to a multiple of ao_storage_block. The code also
+ stops complaining when set to the current value when storage isn't
+ empty.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 936eceded2d08f4eb7318b28bd1be6cd3b06a7b3
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 21:01:31 2020 -0700
+
+ altos: Move ao_storage_erase to shared code. Add len
+
+ This makes ao_storage_erase take an arbitrary length. The new version
+ erases each storage block if there's any un-erased data present, and
+ then also checks after erasing to make sure the block is clear.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e142c4bd6f2fbab74fb7b7cea7e9a19234ed0123
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 20:52:09 2020 -0700
+
+ altosui: Adjust max log setting for storage block size
+
+ Need to round log sizes down to a multiple of the block size so that
+ erasing works sensibly on the device.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e4c93942bbde7a538d1dca114f20dc827275a8e1
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 8 20:49:42 2020 -0700
+
+ altoslib: Remember flight list in AltosConfigData
+
+ Do this instead of having to re-fetch and re-parse in AltosEepromList
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 00492a0801eb93ad98be496585741a025ffea16b
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 16:45:00 2020 -0700
+
+ altos: Initialize pyro code for easytimer-v1
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0f110d01245762d905ad5b7fd1fc7753e17fb249
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 16:23:44 2020 -0700
+
+ easytimer-v1: Enable pyro commands
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5bfcefc475698dada8be8a2d66afbfcc064d4612
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 16:23:09 2020 -0700
+
+ altos: Fix ao_ignite.c to work without HAS_IGNITE
+
+ Need to register commands even if HAS_IGNITE is not set
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0fb9e53a6b62c96d067e2974c5317e3bce638fb2
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 15:48:16 2020 -0700
+
+ altos: Build easytimer-v1 by default
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a901ec5fef409a6675c24518aead2925dcd66cc3
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Apr 8 13:43:22 2020 -0600
+
+ altos: add easytimer-v1 source directory
+
+commit 9416e5d71dc57df6612f62451433a34bf669b2cc
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 16:03:23 2020 -0700
+
+ altos: Allow flight support without logging
+
+ EasyTimer flies rockets, but doesn't have SPI flash for logging.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d4f1dd045465fbb7436a22d82b279319f7449fed
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 16:02:54 2020 -0700
+
+ altos: Allow BMX160 to be used as primary accel
+
+ EasyTimer doesn't have a high-g part.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d553e7448fe22f593eb8ab8246e872d856484bab
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 16:01:45 2020 -0700
+
+ altos: Allow igniter status beeping with only 'extra' channels
+
+ EasyTimer doesn't have main/apogee charges.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2f32a19aedb7d0e33899038e3fb04fe8a773291a
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 12 17:00:47 2019 -0700
+
+ altos: Allow accel-only flight code
+
+ EasyTimer won't have a baro sensor, so we need some way to track at least
+ the ascent part of a flight.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6363403d6c08310a16769bf49b8acc45a08bd619
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 28 16:00:04 2020 -0700
+
+ altos: Allow MPU9250 SPI speed to be set by application
+
+ Rather than requiring 1MHz
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e5e7edb0aed5a183bbdd7484fec75a11160d01d4
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Apr 8 17:20:23 2020 -0700
+
+ ao-tools/ao-usbload: stubs in man page for missing options
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7797000eeaf11027200f12ee7f1eee5ed677f268
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon May 4 11:58:54 2020 -0700
+
+ Mark stm_interrupt_vector as const so it is READONLY
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2108da105ed9c915fc09d1251dc655bf11203d79
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 17:05:17 2019 -0700
+
+ altos: Move from newlib-nano to picolibc
+
+ Use picolibc.ld, which involved some .ld file hacking, including:
+
+ 1) Defining ao_boot RAM address in the .ld file and declaring it 'extern'
+ 2) Changing how m0 interrupt vector got moved to ram
+ 3) Using -Taltos.ld instead of -Wl,-Taltos.ld so picolibc.specs wouldn't add picolibc.ld
+ 4) Placing romconfig vars in '.init.1' and '.init.2' sections instead of '.romconfig'
+ 5) Place code needing to run out of RAM in section .srodata instead of .ramtext
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 74d5dfd1801da8efbb7693a607fd25e35ad1158d
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon May 4 10:36:41 2020 -0700
+
+ ignore .map files
+
+commit f32488556ce25e439fbab941f8019db639824f98
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 3 20:01:14 2020 -0700
+
+ altos/lpc: Add explicit defines for all register groups
+
+ This lets the compiler see the constant address, rather than
+ having the linker stick it in later.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0459a4c7239c3017a61926bc8aab59e556b7eb5e
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon May 4 10:35:23 2020 -0700
+
+ Create map file for all programs
+
+commit 3d70ca6bae383878d8a7c13b862031531fa4ff81
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 3 18:31:19 2020 -0700
+
+ altos/stm: Make ao_eeprom_total a #define instead of a const variable
+
+ This is unused outside of ao_eeprom_stm.c, and as global const takes
+ up space in flash.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b62e2b4831eb90c65ecdf05c219e8711840ef1e
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu May 14 12:44:27 2020 -0600
+
+ point turnon_telemetrum_v2 to correct test script for v2.0
+
+commit 918865cca7297dde522e1886edf71b46d6ee2534
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Apr 17 12:53:47 2020 -0700
+
+ ao-tools: Declare ao_verbose as extern in shared header.
+
+ gcc-10 disables 'common' behavior by defaul, so we need to only define
+ variables in one location now.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c2acda26c1e4e0d7ffda9cd985180562f61aa88b
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Apr 17 12:51:13 2020 -0700
+
+ ao-tools: Use array indexing instead of addition to make gcc-10 happy
+
+ A struct with a trailing zero-length array (for variable-length data) is
+ treated as a zero-sized object when doing pointer arithmetic, but treated
+ correctly when treated as an array. This generates a warning from gcc-10
+
+ load->data + address - load->address
+
+ while this, which is 'the same', does not:
+
+ &load->data[address - load->address]
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 769f0e6049ae0440cf32f8cb0b5e504f67f5e911
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Mar 26 10:09:51 2020 -0700
+
+ Start release notes for 1.9.4
+
+commit a6687ce902a3011796aee93f87d08545e5f0cec9
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Mar 26 10:01:48 2020 -0700
+
+ altosui: Report baro ground alt for 'Pad Altitude' when GPS missing
+
+ The 'Pad Altitude' field in the pad tab of AltosUI was originally one
+ of three fields designed to report the GPS position of the pad. When
+ TeleMini was added, the code was updated to separate the lat/lon from
+ altitude display, but the pad_alt field in AltosState used for that
+ was still only computed from GPS data.
+
+ This fix gets rid of the confusing 'pad_alt' field in AltosState and
+ has the 'Pad Altitude' data select either GPS ground altitude or baro
+ ground altitude, depending on whether GPS data is available.
+
+ signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 455a059b9c44332b8dadd87fba31d194f66997b5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Mar 21 21:13:08 2020 -0700
+
+ map-server: Create Manifest.txt at build time
+
+ This ensures the libraries have the right names
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c9c4c615578c94201140cf904cfd7e3334853973
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Mar 4 18:52:35 2020 -0800
+
+ doc: start release notes for 1.9.3
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d8716b015cfeb4955c0224c32d3c01e66b092209
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Mar 4 18:51:00 2020 -0800
+
+ doc: Document APRS offset configuration value
+
+ Update screen shots including this as well.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 47f4121ae6596bdf18566295df2fdbe94fe676b8
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Mar 4 18:23:14 2020 -0800
+
+ altoslib, altosui, telegps: Add configuration support for APRS offset
+
+ Configure the position within each minute that APRS transmissions
+ occur
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f4ff561bfaa7c59493eb9d6b99f0347db381a167
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Mar 4 17:26:49 2020 -0800
+
+ altos: add APRS 'offset' value to set APRS transmision time
+
+ This value is the offset from the top of the minute for the first APRS
+ packet in the minute. Subsequent packets will be transmitted
+ 'interval' seconds apart for the rest of the minute.
+
+ This allows multiple transmitters to be configured to share the same
+ frequency and not transmit at the same time.
+
+ Note that this offset only works when the device has GPS lock.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0fd503fb65d513f54dade10256545043725d83e3
+Author: Bdale Garbee <bdale@gag.com>
+Date: Tue Feb 25 23:57:51 2020 -0700
+
+ update ChangeLog for release 1.9.2
+
commit 28e77f3520095a1e47ab25721b186e42110ffd3e
Merge: c6ea2666 91ab3acc
Author: Bdale Garbee <bdale@gag.com>
src/easymega-v1.0/easymega-v1.0-$(VERSION).ihx \
src/easymega-v2.0/easymega-v2.0-$(VERSION).ihx \
src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx \
+ src/easytimer-v1/easytimer-v1-$(VERSION).ihx \
src/telebt-v3.0/telebt-v3.0-$(VERSION).ihx \
src/telebt-v4.0/telebt-v4.0-$(VERSION).ihx \
src/teledongle-v3.0/teledongle-v3.0-$(VERSION).ihx \
src/easymega-v2.0/{*.elf,*.ihx} \
src/easymini-v1.0/{*.elf,*.ihx} \
src/easymini-v2.0/{*.elf,*.ihx} \
+ src/easytimer-v1/{*.elf,*.ihx} \
src/telebt-v3.0/{*.elf,*.ihx} \
src/telebt-v4.0/{*.elf,*.ihx} \
src/teledongle-v3.0/{*.elf,*.ihx} \
src/easymega-v2.0/flash-loader/*.elf \
src/easymini-v1.0/flash-loader/*.elf \
src/easymini-v2.0/flash-loader/{*.elf,*.bin} \
+ src/easytimer-v1/flash-loader/{*.elf,*.bin} \
src/telebt-v3.0/flash-loader/*.elf \
src/telebt-v4.0/flash-loader/{*.elf,*.bin} \
src/teledongle-v3.0/flash-loader/*.elf \
if (want_product == AltosLib.product_basestation)
return have_product == AltosLib.product_teledongle ||
- have_product == AltosLib.product_teleterra ||
have_product == AltosLib.product_telebt ||
have_product == AltosLib.product_megadongle;
have_product == AltosLib.product_easymega ||
have_product == AltosLib.product_telegps ||
have_product == AltosLib.product_easymini ||
- have_product == AltosLib.product_telemini;
+ have_product == AltosLib.product_telemini ||
+ have_product == AltosLib.product_easytimer;
if (have_product == AltosLib.product_altusmetrum) /* old devices match any request */
return true;
public int aprs_interval;
public int aprs_ssid;
public int aprs_format;
+ public int aprs_offset;
/* HAS_BEEP */
public int beep;
/* Log listing replies */
public int stored_flight;
+ public AltosEepromFlight[] flights;
/* HAS_TRACKER */
public int tracker_motion;
public int log_available() {
switch (log_format) {
case AltosLib.AO_LOG_FORMAT_TINY:
- if (stored_flight == 0)
+ if (flights == null)
return 1;
return 0;
case AltosLib.AO_LOG_FORMAT_TELEMETRY:
int log_space = log_space();
int log_used;
- if (stored_flight <= 0)
+ if (flights == null)
log_used = 0;
else
- log_used = stored_flight * log_max;
+ log_used = flights.length * log_max;
int log_avail;
if (log_used >= log_space)
aprs_interval = AltosLib.MISSING;
aprs_ssid = AltosLib.MISSING;
aprs_format = AltosLib.MISSING;
+ aprs_offset = AltosLib.MISSING;
beep = AltosLib.MISSING;
storage_size = AltosLib.MISSING;
storage_erase_unit = AltosLib.MISSING;
- stored_flight = AltosLib.MISSING;
+ stored_flight = 0;
+ flights = null;
accel_zero_along = AltosLib.MISSING;
accel_zero_across = AltosLib.MISSING;
adjust_accel_cal();
switch (pad_orientation) {
case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP:
+ case AltosLib.AO_PAD_ORIENTATION_WORDS_UPRIGHT:
+ case AltosLib.AO_PAD_ORIENTATION_BIG_PARTS_UP:
return accel_cal_plus_cooked;
case AltosLib.AO_PAD_ORIENTATION_ANTENNA_DOWN:
+ case AltosLib.AO_PAD_ORIENTATION_WORDS_UPSIDEDOWN:
+ case AltosLib.AO_PAD_ORIENTATION_BIG_PARTS_DOWN:
return invert_accel_value(accel_cal_minus_cooked);
default:
return AltosLib.MISSING;
adjust_accel_cal();
switch (pad_orientation) {
case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP:
+ case AltosLib.AO_PAD_ORIENTATION_WORDS_UPRIGHT:
+ case AltosLib.AO_PAD_ORIENTATION_BIG_PARTS_UP:
return accel_cal_minus_cooked;
case AltosLib.AO_PAD_ORIENTATION_ANTENNA_DOWN:
+ case AltosLib.AO_PAD_ORIENTATION_WORDS_UPSIDEDOWN:
+ case AltosLib.AO_PAD_ORIENTATION_BIG_PARTS_DOWN:
return invert_accel_value(accel_cal_plus_cooked);
default:
return AltosLib.MISSING;
{
switch (pad_orientation) {
case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP:
+ case AltosLib.AO_PAD_ORIENTATION_WORDS_UPRIGHT:
+ case AltosLib.AO_PAD_ORIENTATION_BIG_PARTS_UP:
accel_cal_plus_cooked = accel_cal_plus;
accel_cal_minus_cooked = accel_cal_minus;
accel_cal_adjusted = true;
break;
case AltosLib.AO_PAD_ORIENTATION_ANTENNA_DOWN:
+ case AltosLib.AO_PAD_ORIENTATION_WORDS_UPSIDEDOWN:
+ case AltosLib.AO_PAD_ORIENTATION_BIG_PARTS_DOWN:
accel_cal_plus_cooked = invert_accel_value(accel_cal_minus);
accel_cal_minus_cooked = invert_accel_value(accel_cal_plus);
accel_cal_adjusted = true;
try { aprs_interval = get_int(line, "APRS interval:"); } catch (Exception e) {}
try { aprs_ssid = get_int(line, "APRS SSID:"); } catch (Exception e) {}
try { aprs_format = get_int(line, "APRS format:"); } catch (Exception e) {}
+ try { aprs_offset = get_int(line, "APRS offset:"); } catch (Exception e) {}
/* HAS_BEEP */
try { beep = get_int(line, "Beeper setting:"); } catch (Exception e) {}
try { storage_erase_unit = get_int(line, "Storage erase unit:"); } catch (Exception e) {}
/* Log listing replies */
- try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {}
+ try {
+ int flight = get_int(line, "flight");
+ String[] tokens = line.split("\\s+");
+ if (tokens.length >= 6) {
+ int start = -1, end = -1;
+ try {
+ if (tokens[2].equals("start"))
+ start = AltosParse.parse_hex(tokens[3]);
+ if (tokens[4].equals("end"))
+ end = AltosParse.parse_hex(tokens[5]);
+ if (flight != 0 && start >= 0 && end > 0) {
+ int len;
+ if (flights == null)
+ len = 0;
+ else
+ len = flights.length;
+ AltosEepromFlight [] new_flights = new AltosEepromFlight[len + 1];
+ for (int i = 0; i < len; i++)
+ new_flights[i] = flights[i];
+ new_flights[len] = new AltosEepromFlight(flight, start, end);
+ flights = new_flights;
+ stored_flight = flights.length;
+ }
+ } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); }
+ }
+ } catch (Exception e) {}
/* HAS_GYRO */
try {
aprs_ssid = source.aprs_ssid();
if (aprs_format != AltosLib.MISSING)
aprs_format = source.aprs_format();
+ if (aprs_offset != AltosLib.MISSING)
+ aprs_offset = source.aprs_offset();
/* HAS_BEEP */
if (beep != AltosLib.MISSING)
max_enabled = false;
break;
default:
- if (stored_flight != AltosLib.MISSING)
+ if (flights != null)
max_enabled = false;
break;
}
dest.set_flight_log_max_enabled(max_enabled);
dest.set_radio_enable(radio_enable);
- dest.set_flight_log_max_limit(log_space() / 1024);
+ dest.set_flight_log_max_limit(log_space() >> 10, storage_erase_unit >> 10);
dest.set_flight_log_max(flight_log_max);
dest.set_ignite_mode(ignite_mode);
dest.set_pad_orientation(pad_orientation);
dest.set_aprs_interval(aprs_interval);
dest.set_aprs_ssid(aprs_ssid);
dest.set_aprs_format(aprs_format);
+ dest.set_aprs_offset(aprs_offset);
dest.set_beep(beep);
dest.set_tracker_motion(tracker_motion);
dest.set_tracker_interval(tracker_interval);
link.printf("c a %d %d\n", plus, minus);
/* HAS_LOG */
- if (flight_log_max != 0)
+ if (flight_log_max != 0 && flight_log_max != AltosLib.MISSING)
link.printf("c l %d\n", flight_log_max);
/* HAS_IGNITE */
link.printf("c S %d\n", aprs_ssid);
if (aprs_format != AltosLib.MISSING)
link.printf("c C %d\n", aprs_format);
+ if (aprs_offset != AltosLib.MISSING)
+ link.printf("c O %d\n", aprs_offset);
/* HAS_BEEP */
if (beep != AltosLib.MISSING)
public abstract int flight_log_max() throws AltosConfigDataException;
- public abstract void set_flight_log_max_limit(int flight_log_max_limit);
+ public abstract void set_flight_log_max_limit(int flight_log_max_limit, int storage_erase_unit);
public abstract void set_ignite_mode(int new_ignite_mode);
public abstract void set_aprs_format(int new_aprs_format);
+ public abstract int aprs_offset() throws AltosConfigDataException;
+
+ public abstract void set_aprs_offset(int new_aprs_offset);
+
public abstract int beep() throws AltosConfigDataException;
public abstract void set_beep(int new_beep);
return 3.3 * mega_adc(raw) * (5.1 + 10.0) / 10.0;
}
+ static double easy_timer_voltage(int sensor) {
+ return 3.3 * mega_adc(sensor) * (100.0 + 27.0) / 27.0;
+ }
+
static double easy_mini_2_adc(int raw) {
return raw / 4095.0;
}
start = in_start;
end = in_end;
}
+
+ public AltosEepromFlight() {
+ flight = 0;
+ start = 0;
+ end = 0;
+ }
}
/*
if (remote)
link.start_remote();
config_data = new AltosConfigData (link);
-// if (config_data.serial == 0)
-// throw new IOException("no serial number found");
-
- ArrayList<AltosEepromFlight> flights = new ArrayList<AltosEepromFlight>();
-
- if (config_data.flight_log_max != 0 || config_data.log_format != 0) {
-
- /* Devices with newer firmware will support the 'l'
- * command which will list the region of storage
- * occupied by each available flight
- */
- link.printf("l\n");
- for (;;) {
- String line = link.get_reply(5000);
- if (line == null)
- throw new TimeoutException();
- if (line.contains("done"))
- break;
- if (line.contains("Syntax"))
- continue;
- String[] tokens = line.split("\\s+");
- if (tokens.length < 6)
- break;
-
- int flight = -1, start = -1, end = -1;
- try {
- if (tokens[0].equals("flight"))
- flight = AltosParse.parse_int(tokens[1]);
- if (tokens[2].equals("start"))
- start = AltosParse.parse_hex(tokens[3]);
- if (tokens[4].equals("end"))
- end = AltosParse.parse_hex(tokens[5]);
- if (flight != 0 && start >= 0 && end > 0)
- flights.add(new AltosEepromFlight(flight, start, end));
- } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); }
- }
- } else {
-
- /* Older devices will hold only a single
- * flight. This also assumes that any older
- * device will have a 1MB flash device
- */
- flights.add(new AltosEepromFlight(0, 0, 0xfff));
- }
/* With the list of flights collected, collect more complete
* information on them by reading the first block or two of
* data. This will add GPS coordinates and a date. For older
* firmware, this will also extract the flight number.
*/
- for (AltosEepromFlight flight : flights) {
- add(new AltosEepromLog(config_data, link,
- flight.flight, flight.start, flight.end));
+ if (config_data.flights != null) {
+ for (AltosEepromFlight flight : config_data.flights) {
+ add(new AltosEepromLog(config_data, link,
+ flight.flight, flight.start, flight.end));
+ }
}
} finally {
if (remote)
case imu_type_easymega_v2:
return counts_per_g_mpu;
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return counts_per_g_bmx;
default:
return AltosLib.MISSING;
case imu_type_easymega_v1:
case imu_type_easymega_v2:
return counts_per_degree_mpu;
- case imu_type_telemega_v4:
+ case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return counts_per_degree_bmx;
default:
return AltosLib.MISSING;
case imu_type_easymega_v2:
return counts_per_gauss_mpu;
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return 100.0;
default:
return AltosLib.MISSING;
public static final int imu_type_easymega_v1 = 3; /* MPU6000 */
public static final int imu_type_easymega_v2 = 4; /* MPU9250 */
+ public static final int imu_type_easytimer_v1 = 5; /* BMX160 */
+
private int accel_across(int imu_type) {
switch (imu_type) {
case imu_type_telemega_v1_v2:
return accel_x;
case imu_type_easymega_v2:
return -accel_y;
- case imu_type_telemega_v4:
+ case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return -accel_y;
default:
return AltosLib.MISSING;
return accel_y;
case imu_type_easymega_v2:
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return accel_x;
default:
return AltosLib.MISSING;
return gyro_y;
case imu_type_easymega_v2:
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return gyro_x;
default:
return AltosLib.MISSING;
case imu_type_easymega_v2:
return -gyro_y;
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return -gyro_y;
default:
return AltosLib.MISSING;
case imu_type_telemega_v3:
case imu_type_easymega_v1:
return imu_axis_x;
- case imu_type_telemega_v4:
case imu_type_easymega_v2:
+ case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return imu_axis_y;
default:
return AltosLib.MISSING;
case imu_type_easymega_v2:
return -mag_y;
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return mag_y;
default:
return AltosLib.MISSING;
return imu_axis_y;
case imu_type_easymega_v2:
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return imu_axis_x;
default:
return AltosLib.MISSING;
return mag_y;
case imu_type_easymega_v2:
case imu_type_telemega_v4:
+ case imu_type_easytimer_v1:
return mag_x;
default:
return AltosLib.MISSING;
static final int idle_imu_tm_v4 = 3;
static final int idle_imu_em_v1 = 4;
static final int idle_imu_em_v2 = 5;
- static final int idle_mag = 6;
- static final int idle_mma655x = 7;
- static final int idle_ms5607 = 8;
- static final int idle_adxl375 = 9;
-
- static final int idle_sensor_tm = 10;
- static final int idle_sensor_metrum = 11;
- static final int idle_sensor_mega = 12;
- static final int idle_sensor_emini1 = 13;
- static final int idle_sensor_emini2 = 14;
- static final int idle_sensor_tmini2 = 15;
- static final int idle_sensor_tgps1 = 16;
- static final int idle_sensor_tgps2 = 17;
- static final int idle_sensor_tmini3 = 18;
+ static final int idle_imu_et_v1 = 6;
+ static final int idle_mag = 7;
+ static final int idle_mma655x = 8;
+ static final int idle_ms5607 = 9;
+ static final int idle_adxl375 = 10;
+
+ static final int idle_sensor_tm = 100;
+ static final int idle_sensor_metrum = 101;
+ static final int idle_sensor_mega = 102;
+ static final int idle_sensor_emini1 = 103;
+ static final int idle_sensor_emini2 = 104;
+ static final int idle_sensor_tmini2 = 105;
+ static final int idle_sensor_tgps1 = 106;
+ static final int idle_sensor_tgps2 = 107;
+ static final int idle_sensor_tmini3 = 108;
+ static final int idle_sensor_easytimer1 = 109;
public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException, TimeoutException, AltosUnknownProduct {
for (int idler : idlers) {
case idle_imu_em_v2:
AltosIMU.provide_data(listener, link, AltosIMU.imu_type_easymega_v2);
break;
+ case idle_imu_et_v1:
+ AltosIMU.provide_data(listener, link, AltosIMU.imu_type_easytimer_v1);
+ break;
case idle_mag:
AltosMag.provide_data(listener, link);
break;
case idle_sensor_tmini3:
AltosSensorTMini3.provide_data(listener, link);
break;
+ case idle_sensor_easytimer1:
+ AltosSensorEasyTimer1.provide_data(listener, link);
+ break;
}
}
}
new AltosIdler("TeleGPS-v2",
AltosIdler.idle_gps,
AltosIdler.idle_sensor_tgps2),
+ new AltosIdler("EasyTimer-v1",
+ AltosIdler.idle_imu_et_v1,
+ AltosIdler.idle_sensor_easytimer1),
};
AltosLink link;
} else if (object instanceof String) {
type = type_string;
string = (String) object;
+ } else if (object == null) {
+ System.out.printf("unexpected null object\n");
+ } else if (object.getClass() == null) {
+ System.out.printf("unexpected null object class\n");
} else if (object.getClass().isArray()) {
assert_array(true);
public final static int product_altusmetrum = 0x000a;
public final static int product_telemetrum = 0x000b;
public final static int product_teledongle = 0x000c;
- public final static int product_teleterra = 0x000d;
+ public final static int product_easytimer = 0x000d;
public final static int product_telebt = 0x000e;
public final static int product_telelaunch = 0x000f;
public final static int product_telelco = 0x0010;
new Product("telemetrum", product_telemetrum),
new Product("teleballoon", product_telemetrum),
new Product("teledongle", product_teledongle),
- new Product("teleterra", product_teledongle),
+ new Product("easytimer", product_easytimer),
new Product("telebt", product_telebt),
new Product("telelaunch", product_telelaunch),
new Product("telelco", product_telelco),
public static final int AO_PAD_ORIENTATION_ANTENNA_UP = 0;
public static final int AO_PAD_ORIENTATION_ANTENNA_DOWN = 1;
+ public static final int AO_PAD_ORIENTATION_WORDS_UPRIGHT = 2;
+ public static final int AO_PAD_ORIENTATION_WORDS_UPSIDEDOWN = 3;
+ public static final int AO_PAD_ORIENTATION_BIG_PARTS_UP = 4;
+ public static final int AO_PAD_ORIENTATION_BIG_PARTS_DOWN = 5;
public static final int AO_LOG_FORMAT_UNKNOWN = 0;
public static final int AO_LOG_FORMAT_FULL = 1;
case product_altusmetrum: return "AltusMetrum";
case product_telemetrum: return "TeleMetrum";
case product_teledongle: return "TeleDongle";
- case product_teleterra: return "TeleTerra";
+ case product_easytimer: return "EasyTimer";
case product_telebt: return "TeleBT";
case product_telelaunch: return "TeleLaunch";
case product_telelco: return "TeleLco";
int accel = mma655x.accel;
if (cal_data.mma655x_inverted)
accel = 4095 - accel;
- if (cal_data.pad_orientation == 1)
+ if (cal_data.pad_orientation == AltosLib.AO_PAD_ORIENTATION_ANTENNA_DOWN)
accel = 4095 - accel;
listener.set_acceleration(cal_data.acceleration(accel));
}
double z,
int pad_orientation) {
AltosQuaternion orient = AltosQuaternion.vector(x, y, z).normalize();
- double sky = pad_orientation == 0 ? 1 : -1;
+ double sky = (pad_orientation & 1) == 0 ? 1 : -1;
AltosQuaternion up = new AltosQuaternion(0, 0, 0, sky);
rotation = up.vectors_to_rotation(orient);
}
--- /dev/null
+/*
+ * Copyright © 2020 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_14;
+
+import java.util.concurrent.TimeoutException;
+
+class AltosSensorEasyTimer1 {
+ int tick;
+ int[] sense;
+ int v_batt;
+ int v_pbatt;
+ int temp;
+
+ public AltosSensorEasyTimer1() {
+ sense = new int[2];
+ }
+
+ public AltosSensorEasyTimer1(AltosLink link) throws InterruptedException, TimeoutException {
+ this();
+ String[] items = link.adc();
+ for (int i = 0; i < items.length;) {
+ if (items[i].equals("tick:")) {
+ tick = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("A:")) {
+ sense[0] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("B:")) {
+ sense[1] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("batt:")) {
+ v_batt = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ i++;
+ }
+ }
+
+ static public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException {
+ try {
+ AltosSensorEasyTimer1 sensor_easytimer1 = new AltosSensorEasyTimer1(link);
+
+ listener.set_battery_voltage(AltosConvert.easy_timer_voltage(sensor_easytimer1.v_batt));
+
+ double[] igniter_voltage = new double[2];
+ for (int i = 0; i < 2; i++)
+ igniter_voltage[i] = AltosConvert.easy_timer_voltage(sensor_easytimer1.sense[i]);
+ listener.set_igniter_voltage(igniter_voltage);
+
+ } catch (TimeoutException te) {
+ }
+ }
+}
+
class AltosGpsGroundAltitude extends AltosValue {
void set(double a, double t) {
super.set(a, t);
- pad_alt = value();
+
gps_altitude.set_gps_height();
}
void set_filtered(double a, double t) {
super.set_filtered(a, t);
- pad_alt = value();
gps_altitude.set_gps_height();
}
public double gps_height;
- public double pad_lat, pad_lon, pad_alt;
+ public double pad_lat, pad_lon;
public int speak_tick;
public double speak_altitude;
pad_lat = AltosLib.MISSING;
pad_lon = AltosLib.MISSING;
- pad_alt = AltosLib.MISSING;
gps_altitude = new AltosGpsAltitude();
gps_ground_altitude = new AltosGpsGroundAltitude();
AltosUsbId.java \
AltosSensorMM.java \
AltosSensorEMini.java \
+ AltosSensorEasyTimer1.java \
AltosSensorTM.java \
AltosSensorTMini2.java \
AltosSensorTMini3.java \
try {
/* bounds check stuff */
- if (config_ui.flight_log_max() > data.log_space() / 1024) {
+ if (config_ui.flight_log_max() != AltosLib.MISSING &&
+ config_ui.flight_log_max() > data.log_space() / 1024)
+ {
JOptionPane.showMessageDialog(owner,
String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
config_ui.flight_log_max(),
JLabel aprs_interval_label;
JLabel aprs_ssid_label;
JLabel aprs_format_label;
+ JLabel aprs_offset_label;
JLabel flight_log_max_label;
JLabel ignite_mode_label;
JLabel pad_orientation_label;
JComboBox<String> aprs_interval_value;
JComboBox<Integer> aprs_ssid_value;
JComboBox<String> aprs_format_value;
+ JComboBox<Integer> aprs_offset_value;
JComboBox<String> flight_log_max_value;
JComboBox<String> ignite_mode_value;
JComboBox<String> pad_orientation_value;
0, 1, 2 ,3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
+ static Integer[] aprs_offset_values = {
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18
+ };
+
static String[] beep_values = {
"3750",
"4000",
"4250",
};
- static String[] pad_orientation_values = {
+ static String[] pad_orientation_values_radio = {
"Antenna Up",
"Antenna Down",
};
+ static String[] pad_orientation_values_no_radio = {
+ "Beeper Up",
+ "Beeper Down",
+ };
+
+ String[] pad_orientation_values;
+
static String[] tracker_motion_values_m = {
"2",
"5",
return product != null && product.startsWith("TeleMetrum");
}
+ boolean is_telemega() {
+ String product = product_value.getText();
+ return product != null && product.startsWith("TeleMega");
+ }
+
+ boolean is_easymega() {
+ String product = product_value.getText();
+ return product != null && product.startsWith("EasyMega");
+ }
+
+ boolean is_easytimer() {
+ String product = product_value.getText();
+ return product != null && product.startsWith("EasyTimer");
+ }
+
+ boolean has_radio() {
+ return is_telemega() || is_telemetrum() || is_telemini();
+ }
+
void set_radio_enable_tool_tip() {
if (radio_enable_value.isVisible())
radio_enable_value.setToolTipText("Enable/Disable telemetry and RDF transmissions");
aprs_format_value.setToolTipText("Hardware doesn't support APRS");
}
+ void set_aprs_offset_tool_tip() {
+ if (aprs_offset_value.isVisible())
+ aprs_offset_value.setToolTipText("Set the APRS offset from top of minute");
+ else if (aprs_offset_value.isVisible())
+ aprs_offset_value.setToolTipText("Software version doesn't support setting the APRS offset");
+ else
+ aprs_offset_value.setToolTipText("Hardware doesn't support APRS");
+ }
+
void set_flight_log_max_tool_tip() {
if (flight_log_max_value.isVisible())
flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)");
pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");
else if (is_telemini() || is_easymini())
pad_orientation_value.setToolTipText("TeleMini and EasyMini don't care how they are mounted");
+ else if (is_easytimer())
+ pad_orientation_value.setToolTipText("EasyTimer can be mounted in any of six orientations");
else
pad_orientation_value.setToolTipText("Can't select orientation");
}
set_aprs_format_tool_tip();
row++;
+ /* APRS offset */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = row;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ aprs_offset_label = new JLabel("APRS offset:");
+ pane.add(aprs_offset_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = row;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ aprs_offset_value = new JComboBox<Integer>(aprs_offset_values);
+ aprs_offset_value.setEditable(false);
+ aprs_offset_value.addItemListener(this);
+ aprs_offset_value.setMaximumRowCount(aprs_offset_values.length);
+ pane.add(aprs_offset_value, c);
+ set_aprs_offset_tool_tip();
+ row++;
+
/* Callsign */
c = new GridBagConstraints();
c.gridx = 0; c.gridy = row;
c.anchor = GridBagConstraints.LINE_START;
c.insets = ir;
c.ipady = 5;
+ if (has_radio())
+ pad_orientation_values = pad_orientation_values_radio;
+ else
+ pad_orientation_values = pad_orientation_values_no_radio;
+
pad_orientation_value = new JComboBox<String>(pad_orientation_values);
pad_orientation_value.setEditable(false);
pad_orientation_value.addItemListener(this);
return AltosLib.MISSING;
}
- public void set_flight_log_max_limit(int new_flight_log_max_limit) {
+ public void set_flight_log_max_limit(int new_flight_log_max_limit, int new_storage_erase_unit) {
flight_log_max_limit = new_flight_log_max_limit;
if (new_flight_log_max_limit != AltosLib.MISSING) {
flight_log_max_value.removeAllItems();
for (int i = 8; i >= 1; i--) {
int size = flight_log_max_limit / i;
+ if (new_storage_erase_unit != 0)
+ size &= ~(new_storage_erase_unit - 1);
flight_log_max_value.addItem(String.format("%d (%d flights)", size, i));
}
}
- if (flight_log_max != 0)
+ if (flight_log_max != 0 && flight_log_max != AltosLib.MISSING)
set_flight_log_max(flight_log_max);
}
return aprs_format_value.getSelectedIndex();
return AltosLib.MISSING;
}
+
+ public void set_aprs_offset(int new_aprs_offset) {
+ if (new_aprs_offset != AltosLib.MISSING)
+ aprs_offset_value.setSelectedItem(new_aprs_offset);
+ aprs_offset_value.setVisible(new_aprs_offset != AltosLib.MISSING);
+ aprs_offset_label.setVisible(new_aprs_offset != AltosLib.MISSING);
+ set_aprs_offset_tool_tip();
+ }
+
+ public int aprs_offset() throws AltosConfigDataException {
+ if (aprs_offset_value.isVisible()) {
+ Integer i = (Integer) aprs_offset_value.getSelectedItem();
+ return i;
+ }
+ return AltosLib.MISSING;
+ }
}
class PadAlt extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
- if (report_pad(state))
- return state.pad_alt;
- else if (state.gps != null)
+ if (report_pad(state)) {
+ double alt = state.gps_ground_altitude();
+ if (alt == AltosLib.MISSING)
+ alt = state.ground_altitude();
+ return alt;
+ }
+ else if (state.gps != null && state.gps.alt != AltosLib.MISSING)
return state.gps.alt;
else
return state.altitude();
FIRMWARE_EMEGA_2_0=$(top_srcdir)/src/easymega-v2.0/easymega-v2.0-$(VERSION).ihx
FIRMWARE_EMEGA=$(FIRMWARE_EMEGA_1_0) $(FIRMWARE_EMEGA_2_0)
+FIRMWARE_ETIMER_1=$(top_srcdir)/src/easytimer-v1/easytimer-v1-$(VERSION).ihx
+FIRMWARE_ETIMER=$(FIRMWARE_ETIMER_1)
+
FIRMWARE_TGPS_1_0=$(top_srcdir)/src/telegps-v1.0/telegps-v1.0-$(VERSION).ihx
FIRMWARE_TGPS_2_0=$(top_srcdir)/src/telegps-v2.0/telegps-v2.0-$(VERSION).ihx
FIRMWARE_TGPS=$(FIRMWARE_TGPS_1_0) $(FIRMWARE_TGPS_2_0)
-FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI) $(FIRMWARE_TGPS) $(FIRMWARE_EMEGA)
+FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI) $(FIRMWARE_TGPS) $(FIRMWARE_EMEGA) $(FIRMWARE_ETIMER)
ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf
ALTOS_DOC=$(top_srcdir)/doc/altos.pdf
File "../src/easymini-v2.0/easymini-v2.0-${VERSION}.ihx"
File "../src/easymega-v1.0/easymega-v1.0-${VERSION}.ihx"
File "../src/easymega-v2.0/easymega-v2.0-${VERSION}.ihx"
+ File "../src/easytimer-v1/easytimer-v1-${VERSION}.ihx"
SectionEnd
serial_line.printf("d %d\n", log.flight);
for (;;) {
/* It can take a while to erase the flash... */
- String line = serial_line.get_reply(20000);
+ String line = serial_line.get_reply(200000);
if (line == null)
throw new TimeoutException();
if (line.equals("Erased"))
break;
+ if (line.equals("Failed to erase"))
+ throw new IOException(line);
if (line.startsWith("No such"))
throw new IOException(line);
}
"telemetrum-v1",
"telemini-v1",
"telenano",
- "teleshield",
- "teleterra"
+ "teleshield"
};
private static final String[] pair_programmed_devices = {
"TeleMetrum-v1",
"TeleMini-v1",
"TeleNano",
- "TeleShield",
- "TeleTerra"
+ "TeleShield"
};
private boolean is_pair_programmed() {
}
info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S');
info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
- info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt);
+ info_add_row(1, "Pad GPS alt", "%6.0f m", state.gps_ground_altitude());
}
if (state.gps.year != AltosLib.MISSING)
info_add_row(2, "GPS date", "%04d-%02d-%02d",
if (want_product == AltosUILib.product_basestation)
return have_product == AltosUILib.product_teledongle ||
- have_product == AltosUILib.product_teleterra ||
have_product == AltosUILib.product_telebt ||
have_product == AltosUILib.product_megadongle;
if (want_product == AltosUILib.product_altimeter)
return have_product == AltosUILib.product_telemetrum ||
have_product == AltosUILib.product_telemega ||
+ have_product == AltosUILib.product_easytimer ||
have_product == AltosUILib.product_easymega ||
have_product == AltosUILib.product_telegps ||
have_product == AltosUILib.product_easymini ||
echo 'E 1' > $dev
-./test-telemetrum
+./test-telemetrum-v2.0
exit $?
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
[\--cal \fIradio-calibration\fP]
-[\--serial \fserial-number\fP]
+[\--serial \fIserial-number\fP]
+[\--raw]
+[\--verbose=\fIverbose\fP]
+[\--wait\\
\fIfile.elf\fP or \fIfile.ihx\fP
.SH DESCRIPTION
.I ao-usbload
if (address < load->address || load->address + load->length < address + length)
return false;
- memcpy(load->data + address - load->address, data, length);
+ memcpy(&load->data[address - load->address], data, length);
return true;
}
#include <stdint.h>
#include <stdarg.h>
-uint32_t ao_verbose;
+extern uint32_t ao_verbose;
#define AO_VERBOSE_EXE 1
#define AO_VERBOSE_SELF 2
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.9.2)
+AC_INIT([altos], 1.9.3)
ANDROID_VERSION=27
AC_CONFIG_SRCDIR([src/kernel/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
-RELEASE_DATE=2020-02-26
+RELEASE_DATE=2020-06-15
AC_SUBST(RELEASE_DATE)
DOC_DATE=`LC_ALL=C date -d $RELEASE_DATE +'%d %b %Y'`
save_LIBS="$LIBS"
CC="$ARM_CC"
CFLAGS="-mthumb -mcpu=cortex-m0"
- LIBS="-ffreestanding -nostdlib"
+ LIBS="--specs=picolibc.specs"
AC_LANG_PUSH([C])
AC_MSG_CHECKING([if ]$ARM_CC[ supports cortex-m0])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int i;])],
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[HAVE_ARM_M0_CC=yes],
[HAVE_ARM_M0_CC=no])
AC_MSG_RESULT([$HAVE_ARM_M0_CC])
CFLAGS="-mthumb -mcpu=cortex-m3"
AC_MSG_CHECKING([if ]$ARM_CC[ supports cortex-m3])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int i;])],
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[HAVE_ARM_M3_CC=yes],
[HAVE_ARM_M3_CC=no])
AC_MSG_RESULT([$HAVE_ARM_M3_CC])
fi
if test "x$HAVE_ARM_M0_CC" = "xno"; then
- AC_MSG_WARN([No cortex-m0 arm compiler found, LPC11U14 binaries will not be built])
-fi
-
-AC_ARG_WITH([newlib-nano],
- [AS_HELP_STRING([--with-newlib-nano],
- [Root of newlib nano install])],
- [],
- [with_newlib_nano=auto])
-
-HAVE_NEWLIB_NANO=no
-if test "x$with_newlib_nano" != "xno"; then
- if test "x$with_newlib_nano" = "xauto"; then
- for d in /usr/local/lib/newlib-nano /usr/lib/newlib-nano; do
- if test "x$with_newlib_nano" = "xauto" -a -d "$d"; then
- with_newlib_nano="$d"
- HAVE_NEWLIB_NANO=yes
- fi
- done
- else
- HAVE_NEWLIB_NANO=yes
- fi
+ AC_MSG_WARN([No cortex-m0 arm compiler found, LPC11U14 and STM32F0 binaries will not be built])
fi
-if test "x$HAVE_NEWLIB_NANO" = "xno"; then
- AC_MSG_WARN([No newlib-nano library found, ARM binaries will not be built])
- HAVE_ARM_M3_CC=no
- HAVE_ARM_M0_CC=no
-else
- NEWLIB_NANO="$with_newlib_nano"
-fi
-AC_SUBST(HAVE_NEWLIB_NANO)
-AC_SUBST(NEWLIB_NANO)
#
# Configure AVR compiler
echo " Android support.............: ${HAVE_ANDROID_SDK}"
echo " Android release support.....: ${ANDROID_RELEASE}"
echo " STlink support..............: ${HAVE_STLINK}"
-echo " Newlib-nano support.........: ${NEWLIB_NANO}"
echo " i386 and amd64 libaltos.....: ${MULTI_ARCH}"
echo " install shared mime info....: ${INSTALL_SHARED_MIME_INFO}"
echo " Strip jar timestamps........: ${STRIP_NONDETERMINISM}"
endif
RELNOTES_INC=\
+ release-notes-1.9.3.inc \
release-notes-1.9.2.inc \
release-notes-1.9.1.inc \
release-notes-1.9.inc \
easymega-v1.0-top.jpg \
easymini.svg \
easymini-top.jpg \
+ easytimer.jpg \
fire-igniter.png \
graph-configure.png \
graph-map.png \
easymini-device.inc \
telemega.inc \
easymega.inc \
+ easytimer.inc \
installation.inc \
using-am-products.inc \
updating-firmware.inc \
similar unit as a programming dongle (pair
programming).
endif::telemetrum,telemini[]
- ifdef::telemega,easymega,telemetrum[]
+ ifdef::telemega,easymega,easytimer,telemetrum[]
TeleMega, EasyMega, TeleMetrum v2 or newer,
- EasyMini, TeleBT v3 or newer and TeleDongle v3
+ EasyMini, EasyTimer, TeleBT v3 or newer and TeleDongle v3
or newer are all
- endif::telemega,easymega,telemetrum[]
- ifndef::telemega,easymega,telemetrum[]
+ endif::telemega,easymega,easytimer,telemetrum[]
+ ifndef::telemega,easymega,easytimer,telemetrum[]
EasyMini is
- endif::telemega,easymega,telemetrum[]
+ endif::telemega,easymega,easytimer,telemetrum[]
programmed directly
over USB (self programming). Please read
the directions for flashing devices in
:telemega: 1
:easymega: 1
:telegps: 1
+:easytimer: 1
:application: AltosUI
:pdf-stylesdir: .
:pdf-style: altusmetrum
include::easymega.adoc[]
+ include::easytimer.adoc[]
+
include::installation.adoc[]
include::using-am-products.adoc[]
=== APRS
{aprsdevices} can send APRS if desired, and the
- interval between APRS packets can be configured. As each APRS
- packet takes a full second to transmit, we recommend an
- interval of at least 5 seconds to avoid consuming too much
- battery power or radio channel bandwidth. You can configure
- the APRS interval using {application}; that process is described in
- <<{configure_section}>>.
+ interval between APRS packets can be configured. As
+ each APRS packet takes a full second to transmit, we
+ recommend an interval of at least 5 seconds to avoid
+ consuming too much battery power or radio channel
+ bandwidth. You can configure the time within each
+ minute that APRS transmits by changing the APRS offset
+ value. When the GPS signal is locked and knows the
+ current time, the APRS offset selects the time with
+ each minute for the first APRS transmission;
+ subsequent transmissions occur each APRS interval
+ seconds thereafter. You can configure the APRS
+ interval and APRS offset using {application}; that
+ process is described in <<{configure_section}>>.
AltOS supports both compressed and uncompressed APRS
position report data formats. The compressed format
altitude with Compressed format. Test before
you fly to see which to use.
+ ==== APRS Offset
+
+ The delay from the top of the minute before sending
+ the first APRS packet of the minute. Coordinating
+ values for this parameter between multiple devices can
+ allow a single receiver to reliably receive APRS
+ packets from multiple devices. Note that this offset only
+ takes effect while the GPS signal is locked so that the
+ transmitting device knows the current time.
+
==== Callsign
This sets the call sign included in each
is fired first, followed after a two second
delay by the 'main' channel.
- ifdef::telemetrum,telemega,easymega[]
+ ifdef::telemetrum,telemega,easymega,easytimer[]
==== Pad Orientation
Because they include accelerometers,
with the antenna pointing aft instead.
Antenna Up::
- In this mode, the antenna end of the flight
- computer must point forward, in line with the
- expected flight path.
+ In this mode, the antenna (or beeper, for devices
+ without an antenna) of the flight computer must point
+ forward, in line with the expected flight path.
Antenna Down::
- In this mode, the antenna end of the flight
- computer must point aft, in line with the
- expected flight path.
- endif::telemetrum,telemega,easymega[]
+
+ In this mode, the antenna (or beeper, for devices
+ without an antenna) end of the flight computer must
+ point aft, in line with the expected flight path.
+ endif::telemetrum,telemega,easymega,easytimer[]
==== Beeper Frequency
in the log.
endif::telegps[]
-ifdef::telemega,easymega,telemetrum[]
+ifdef::telemega,easymega,easytimer,telemetrum[]
==== Calibrate Accelerometer
Configure Altimeter window and save the new
calibration values.
-endif::telemega,easymega,telemetrum[]
+endif::telemega,easymega,easytimer,telemetrum[]
-ifdef::telemega,easymega[]
+ifdef::telemega,easymega,easytimer[]
==== Configure Pyro Channels
image::configure-pyro.png[width=400]
This opens a separate window to configure the
- additional pyro channels available on TeleMega
- and EasyMega. One column is presented for
+ additional pyro channels available on TeleMega,
+ EasyMega and EasyTimer. One column is presented for
each channel. Each row represents a single
parameter, if enabled the parameter must meet
the specified test for the pyro channel to be
include::pyro-channels.adoc[]
-endif::telemega,easymega[]
+endif::telemega,easymega,easytimer[]
== EasyMega
.EasyMega Board
- image::easymega-v1.0-top.jpg[width=430]
+ image::easymega-v1.0-top.jpg[width=400]
EasyMega is a 1¼ inch by 2¼ inch circuit board. It was
designed to easily fit in a 38mm coupler. Like TeleMetrum,
|Main pyro channel connection to pyro circuit
|Top 5
- |Main +
- |Main pyro channel common connection to battery +
+ |Main +++
+ |Main pyro channel common connection to battery +++
|Top 6
|Apogee -
|Apogee pyro channel connection to pyro circuit
|Top 7
- |Apogee +
- |Apogee pyro channel common connection to battery +
+ |Apogee +++
+ |Apogee pyro channel common connection to battery +++
|Top 8
|D -
|D pyro channel connection to pyro circuit
|Top 9
- |D +
- |D pyro channel common connection to battery +
+ |D +++
+ |D pyro channel common connection to battery +++
|Bottom 1
|GND
|A pyro channel connection to pyro circuit
|Bottom 5
- |A +
- |A pyro channel common connection to battery +
+ |A +++
+ |A pyro channel common connection to battery +++
|Bottom 6
|B -
|B pyro channel connection to pyro circuit
|Bottom 7
- |B +
- |B pyro channel common connection to battery +
+ |B +++
+ |B pyro channel common connection to battery +++
|Bottom 8
|C -
|C pyro channel connection to pyro circuit
|Bottom 9
- |C +
- |C pyro channel common connection to battery +
+ |C +++
+ |C pyro channel common connection to battery +++
|====
=== Using a Separate Pyro Battery with EasyMega
|Main pyro channel connection to pyro circuit
|Top 2
- |Main +
- |Main pyro channel common connection to battery +
+ |Main +++
+ |Main pyro channel common connection to battery +++
|Top 3
- |Battery +
+ |Battery +++
|Positive external battery terminal
|Top 4
|Apogee pyro channel connection to pyro circuit
|Bottom 2
- |Apogee +
- |Apogee pyro channel common connection to battery +
+ |Apogee +++
+ |Apogee pyro channel common connection to battery +++
|Bottom 3
|Switch Output
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.3.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.1.adoc[]
--- /dev/null
+== EasyTimer
+
+ .EasyTimer Board
+ image::easytimer.jpg[width=400]
+
+ EasyTimer is built on a 0.8 inch by 1½ inch circuit board. It's
+ designed to fit in a 24mm coupler tube.
+
+ EasyTimer is designed to control events during ascent. It has
+ an accelerometer and gyroscope that can measure acceleration
+ and rotation and compute speed and tilt angle. EasyTimer has
+ two pyro channels which can be configured to fire at various
+ points during flight. Because EasyTimer has no barometric
+ sensor, it cannot be used to fire recovery charges at apogee
+ or during descent. EasyTimer is configured using the AltosUI
+ application which is available for Linux, Mac OS X and Windows.
+
+ === EasyTimer Screw Terminals
+
+ EasyTimer has two sets of four screw terminals near
+ one end of the board. Using the picture above, the top
+ four have connections for pyro channel B and an
+ external battery and the bottom four have connections
+ for pyro circuit A and the power switch. Counting from
+ the left, the connections are as follows:
+
+ .EasyTimer Screw Terminals
+ [options="header",grid="all",cols="2,3,10"]
+ |====
+ |Terminal #|Terminal Name|Description
+ |Top 1
+ |B -
+ |Pyro channel B connection to pyro circuit
+
+ |Top 2
+ |B +++
+ |Pyro channel B common connection to battery +++
+
+ |Top 3
+ |Battery +++
+ |Positive external battery terminal
+
+ |Top 4
+ |Battery -
+ |Negative external battery terminal
+
+ |Bottom 1
+ |A -
+ |Pyro channel A connection to pyro circuit
+
+ |Bottom 2
+ |A +++
+ |Pyro channel A common connection to battery +++
+
+ |Bottom 3
+ |Switch Output
+ |Switch connection to flight computer
+
+ |Bottom 4
+ |Switch Input
+ |Switch connection to positive battery terminal
+ |====
+
+ === Connecting A Battery To EasyTimer
+
+ There are two possible battery connections on
+ EasyTimer. You can use either method; both feed
+ through the power switch terminals.
+
+ One battery connection is the standard Altus Metrum
+ white JST plug. This mates with single-cell Lithium
+ Polymer batteries sold by Altus Metrum.
+
+ The other is a pair of screw terminals marked 'Battery
+ +' and 'Battery -'. Connect a battery from 4 to 12
+ volts to these terminals, being careful to match polarity.
+
+ === Charging Lithium Batteries
+
+ Because EasyTimer allows for batteries other than the
+ standard Altus Metrum Lithium Polymer cells, it cannot
+ incorporate a battery charger circuit. Therefore, when
+ using a Litium Polymer cell, you'll need an external
+ charger. These are available from Altus Metrum, or
+ from Spark Fun.
+
+ === Using a Separate Pyro Battery with EasyTimer
+
+ As described above, using an external pyro battery involves
+ connecting the negative battery terminal to the flight
+ computer ground, connecting the positive battery terminal to
+ one of the igniter leads and connecting the other igniter
+ lead to the per-channel pyro circuit connection.
+
+ To connect the negative pyro battery terminal to EasyTimer
+ ground, connect it to the negative external battery
+ connection, top terminal 4.
+
+ Connecting the switched positive battery terminal to the pyro
+ charges must be done separate from EasyTimer, by soldering
+ them together or using some other connector. Note that for
+ safety, you must put a switch between the pyro battery and
+ the rest of the circuit!
+
+ The other lead from each pyro charge is then inserted into
+ the appropriate per-pyro channel screw terminal (top
+ terminal 1 for pyro channel A charge, bottom terminal 1 for
+ pyro channel B charge).
+
+ === Using an Active Switch with EasyTimer
+
+ As explained above, an external active switch requires three
+ connections, one to the positive battery terminal, one to
+ the flight computer positive input and one to ground. Use
+ the negative external battery connection, top terminal 4 for
+ ground.
+
+ The positive battery terminal is available on bottom
+ terminal 4, the positive flight computer input is on the
+ bottom terminal 3.
charging circuitry.
endif::telemetrum,telemega,easymega[]
The Lithium Polymer
+ ifdef::easytimer[EasyTimer, ]
ifdef::telemini[TeleMini and]
EasyMini battery can be charged by disconnecting it
from the board and plugging it into a standalone
USB power source.
You can also choose to use another battery with
+ ifdef::easytimer[EasyTimer and]
EasyMini, anything supplying between 4 and 12 volts should
work fine (like a standard 9V battery), but if you are planning
to fire pyro charges, ground testing is required to verify that
during these phases of the flight.
Height above pad:: Select a value, and then choose whether the height
-above the launch pad should be above or below that value.
-
-Orientation:: TeleMega and EasyMega contain a 3-axis gyroscope and
-accelerometer which is used to compute the orientation of the
-rocket. A record of orientations over the last 0.64 seconds is kept
-and the largest value within this period is compared with the
+above the launch pad should be above or below that value. Note that
+because EasyTimer has only a low-range accelerometer and no barometer,
+this value will not be very reliable on that device.
+
+Orientation:: TeleMega, EasyMega and EasyTimer contain a 3-axis
+gyroscope and accelerometer which is used to compute the orientation
+of the rocket. A record of orientations over the last 0.64 seconds is
+kept and the largest value within this period is compared with the
specified value. Note that the tilt angle is not the change in angle
from the launch pad, but rather absolute relative to gravity—the
3-axis accelerometer is used to compute the angle of the rocket on the
than 200m/s. Ascent rate will greater than zero. Vertical
acceleration will be less than zero.
- * Drogue. The rocket has reached apogee and
- is heading back down, but is above the
- configured Main altitude. Ascent rate will be less than zero during
- this state. Vertical acceleration will be negative until the rocket
- reaches a terminal descent rate, at which point Vertical
- acceleration will be zero. Both Ascent rate and Vertical
+ * Drogue. The rocket has reached apogee and is heading back down, but
+ is above the configured Main altitude. Ascent rate will be less
+ than zero during this state. Vertical acceleration will be negative
+ until the rocket reaches a terminal descent rate, at which point
+ Vertical acceleration will be zero. Both Ascent rate and Vertical
acceleration are very noisy in this state, so be careful when
- trying to use them to control pyro channels.
+ trying to use them to control pyro channels. This state selection
+ is not available on EasyTimer.
* Main. The rocket is still descending, and
is below the Main altitude. Ascent rate will be less than zero
it will settle down to a zero value once the rocket has reached the
terminal velocity under the main chute. Ascent rate and Vertical
acceleration should be much less noisy once the main chute has
- deployed.
+ deployed. This state selection is not available on EasyTimer.
* Landed. The rocket is no longer moving.
--- /dev/null
+= Release Notes for Version 1.9.3
+include::release-head.adoc[]
+:doctype: article
+
+ Version 1.9.3
+
+ == AltOS
+
+ * Add APRS offset. Allows multiple APRS transmitters to coordinate when
+ transmission occurs to allow them to share a frequency.
+
+ * Fix max log size. Flight computer storage is erased in 64kB chunks. Adjust max
+ log size to be a multiple of this size.
+
+ * Check flight erasing more carefully. Handle interrupting erasing in the
+ middle.
+
+ * Add EasyTimer support.
+
+ == AltosUI, TeleGPS, MicroPeak
+
+ * Add configuration support for APRS offset.
+
+ * Adjust flight log sizes to be a multiple of the flight
+ computer erase block size.
+
+ * Report barometric pad altitude in Pad tab for TeleMini.
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.3.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.2.adoc[]
|3.7V
endif::easymega[]
+ ifdef::easytimer[]
+ |EasyTimer v1.0
+ |-
+ |16g
+ |-
+ |BMX160
+ |-
+ |-
+ |3.7-12V
+ endif::easytimer[]
+
+
|===
<<<<
|38mm coupler
endif::easymega[]
+ ifdef::easytimer[]
+ |EasyMini
+ |Debug USB Battery
+ |Pyro A Pyro B Battery
+ |0.8 inch (2.03cm)
+ |1½ inch (3.81cm)
+ |24mm coupler
+ endif::easytimer[]
+
|===
fundamental modes, “idle” and “flight”. Which of these modes
the firmware operates in is determined at start up
time.
- ifdef::telemetrum,telemega,easymega[]
+ ifdef::telemetrum,telemega,easymega,easytimer[]
For
- TeleMetrum, TeleMega and EasyMega, which have accelerometers, the mode is
+ TeleMetrum, TeleMega, EasyMega and EasyTimer, which have accelerometers, the mode is
controlled by the orientation of the
rocket (well, actually the board, of course...) at the time
power is switched on. If the rocket is “nose up”, then
launch, so the firmware chooses flight mode. However, if the
rocket is more or less horizontal, the firmware instead enters
idle mode.
- endif::telemetrum,telemega,easymega[]
+ endif::telemetrum,telemega,easymega,easytimer[]
Since
EasyMini doesn't
have an
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.3.adoc[]
+
+ <<<<
+
:leveloffset: 2
include::release-notes-1.9.1.adoc[]
|Main pyro channel connection to pyro circuit
|Top 5
- |Main +
- |Main pyro channel common connection to battery +
+ |Main +++
+ |Main pyro channel common connection to battery +++
|Top 6
|Apogee -
|Apogee pyro channel connection to pyro circuit
|Top 7
- |Apogee +
- |Apogee pyro channel common connection to battery +
+ |Apogee +++
+ |Apogee pyro channel common connection to battery +++
|Top 8
|D -
|D pyro channel connection to pyro circuit
|Top 9
- |D +
- |D pyro channel common connection to battery +
+ |D +++
+ |D pyro channel common connection to battery +++
|Bottom 1
|GND
|A pyro channel connection to pyro circuit
|Bottom 5
- |A +
- |A pyro channel common connection to battery +
+ |A +++
+ |A pyro channel common connection to battery +++
|Bottom 6
|B -
|B pyro channel connection to pyro circuit
|Bottom 7
- |B +
- |B pyro channel common connection to battery +
+ |B +++
+ |B pyro channel common connection to battery +++
|Bottom 8
|C -
|C pyro channel connection to pyro circuit
|Bottom 9
- |C +
- |C pyro channel common connection to battery +
+ |C +++
+ |C pyro channel common connection to battery +++
|====
=== Using a Separate Pyro Battery with TeleMega
|Terminal #|Terminal Name|Description
|1 |Switch Output |Switch connection to flight computer
|2 |Switch Input |Switch connection to positive battery terminal
- |3 |Main + |Main pyro channel common connection to battery +
+ |3 |Main +++ |Main pyro channel common connection to battery +++
|4 |Main - |Main pyro channel connection to pyro circuit
- |5 |Apogee + |Apogee pyro channel common connection to battery +
+ |5 |Apogee +++ |Apogee pyro channel common connection to battery +++
|6 |Apogee - |Apogee pyro channel connection to pyro circuit
|===
|Apogee pyro channel connection to pyro circuit
|2
- |Apogee +
- |Apogee pyro channel common connection to battery +
+ |Apogee +++
+ |Apogee pyro channel common connection to battery +++
|3
|Main -
|Main pyro channel connection to pyro circuit
|4
- |Main +
- |Main pyro channel common connection to battery +
+ |Main +++
+ |Main pyro channel common connection to battery +++
|Left
|Switch Output
the board.
endif::easymega[]
+ ifdef::easytimer[]
+ EasyTimer::
+
+ Connect pin 5 and pin 1 of the debug connector, which
+ is the six holes next to the beeper. Pin 1 can be
+ identified by the square pad around it, and then the
+ pins could sequentially across the board, making Pin 5
+ the one on the other end of the row.
+ endif::easytimer[]
+
ifdef::telemetrum[]
TeleMetrum v2 and newer::
signals, but no record of the flight will be
stored in on-board flash.
- ifdef::easymega,telemega[]
+ ifdef::easymega,telemega,easytimer[]
|Additional Igniters
|four very short beeps
- |Continuity indication for the four additional pyro
- channels on TeleMega and EasyMega. One high tone for
- no continuity, one low tone for continuity. These are
+ |Continuity indication for the additional pyro
+ channels on TeleMega, EasyMega and EasyTimer. One high tone for
+ no continuity, one low tone for continuity. On TeleMega and EasyMegay, these are
produced after the continuity indicators for the two
primary igniter channels.
- endif::easymega,telemega[]
+ endif::easymega,telemega,easytimer[]
|====
the current state. See below for how to get the flight
computer to come up in Idle mode at power on.
- ifdef::telemetrum,easymega,telemega[]
+ ifdef::telemetrum,easymega,telemega,easytimer[]
For flight computers with accelerometers (TeleMetrum,
- EasyMega and TeleMega), the mode is selected by the
+ EasyMega, TeleMega and EasyTimer), the mode is selected by the
orientation of the board during the self test
interval. If the board is pointing upwards as if ready
to fly, it will enter Flight/Pad mode. Otherwise, it will
enter Idle mode.
- endif::telemetrum,easymega,telemega[]
+ endif::telemetrum,easymega,telemega,easytimer[]
ifdef::easymini[]
For EasyMini, if the USB cable is connected to a
=== Using a Different Kind of Battery
EasyMini
- ifdef::telemini[and TeleMini v2 are]
- ifndef::telemini[is]
+ ifdef::easytimer[and EasyTimer are]
+ ifndef::easytimer[is]
designed to use either a
lithium polymer battery or any other battery producing
between 4 and 12 volts, such as a rectangular 9V
battery.
- ifdef::telemega,easymega,telemetrum[]
+ ifdef::telemega,easymega,telemetrum,telemini[]
[WARNING]
+ ifdef::telemini[TeleMini, ]
TeleMega, EasyMega and TeleMetrum are only designed to
operate off a single-cell Lithium Polymer battery and
cannot be used with any other kind. Connecting a
different kind of battery to any of these will destroy
the board.
- endif::telemega,easymega,telemetrum[]
+ endif::telemega,easymega,telemetrum,telemini[]
=== Using Packet Link Mode
In the rocket itself, you just need a flight computer
and a single-cell, 3.7 volt nominal Li-Po rechargeable
battery.
- ifdef::telemetrum,telemega,easymega[]
+ ifdef::telemetrum,telemega,easymega,easytimer[]
An 850mAh battery weighs less than a 9V
- alkaline battery, and will run a TeleMetrum, TeleMega
- or EasyMega for hours.
- endif::telemetrum,telemega,easymega[]
+ alkaline battery, and will run a TeleMetrum, TeleMega,
+ EasyMega or EasyTimer for hours.
+ endif::telemetrum,telemega,easymega,easytimer[]
A 110mAh battery weighs less
than a triple A battery and is a good choice for use
with
altos-mapd-jdb
altos-mapd-test
classes
+Manifest.txt
echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(altosmapddir)/altosmapd.jar" "$$@"' >> $@
chmod +x $@
+Manifest.txt: Makefile
+ echo 'Main-Class: altosmapd.AltosMapd' > $@
+ echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)" >> $@
+
altos-mapd-test: Makefile
echo '#!/bin/sh' > $@
echo 'dir="$$(dirname $$0)"' >> $@
-rm -f "$@"
$(LN_S) ../../altoslib/"$@" .
+
+clean::
+ rm -f Manifest.txt
+++ /dev/null
-Main-Class: altosmapd.AltosMapd
-Class-Path: altoslib_13.jar
*.jar
*.stamp
classes
+Manifest.txt
+Manifest-fat.txt
all-local: classes/altosmap $(JAR) altos-mapj altos-mapj-test altos-mapj-jdb
+fat: $(FATJAR)
+
install-altosmapJAVA: altosmap.jar
@$(NORMAL_INSTALL)
test -z "$(altosmapdir)" || $(MKDIR_P) "$(DESTDIR)$(altosmapdir)"
echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(altosmapdir)/altosmap.jar" "$$@"' >> $@
chmod +x $@
+Manifest.txt: Makefile
+ echo 'Main-Class: altosmap.AltosMap' > $@
+ echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)" >> $@
+
+Manifest-fat.txt: Makefile
+ echo 'Main-Class: altosmap.AltosMap' > $@
+ echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)" >> $@
+
altos-mapj-test: Makefile
echo '#!/bin/sh' > $@
echo 'dir="$$(dirname $$0)"' >> $@
-rm -f "$@"
$(LN_S) ../../altoslib/"$@" .
+clean::
+ rm -f Manifest.txt Manifest-fat.txt
+++ /dev/null
-Main-Class: altosmap.AltosMap
-Class-Path: altoslib_13.jar
altitude-pa.h
altitude-pa-small.h
ao_whiten.h
+*.map
ARM_CC=@ARM_CC@
HAVE_ARM_M3_CC=@HAVE_ARM_M3_CC@
HAVE_ARM_M0_CC=@HAVE_ARM_M0_CC@
-NEWLIB_NANO=@NEWLIB_NANO@
-HAVE_NEWLIB_NANO=@HAVE_NEWLIB_NANO@
AVR_CC=@AVR_CC@
AVR_OBJCOPY=@AVR_OBJCOPY@
ARMM3DIRS=\
easymega-v1.0 easymega-v1.0/flash-loader \
easymega-v2.0 easymega-v2.0/flash-loader \
+ easytimer-v1 easytimer-v1/flash-loader \
telemega-v0.1 telemega-v0.1/flash-loader \
telemega-v1.0 telemega-v1.0/flash-loader \
telemega-v2.0 telemega-v2.0/flash-loader \
-Wshadow \
-Warray-bounds=2
-OPT=-Os
+OPT=-Os -Wl,-Map=$(PROGNAME)-$(VERSION).map
-NEWLIB_PRINTF_CFLAGS = -DNEWLIB_INTEGER_PRINTF_SCANF
-
-NEWLIB_CFLAGS= \
- -ffreestanding -nostdlib \
- -isystem $(NEWLIB_NANO)/arm-none-eabi/include \
- $(NEWLIB_PRINTF_CFLAGS)
+PICOLIBC_CFLAGS= \
+ -specs=picolibc.specs \
+ $(PICOLIBC_PRINTF_CFLAGS)
AO_CFLAGS=\
-std=gnu99 \
static void
ao_adxl375_dump(void)
{
- printf ("ADXL375 value %d %d %d self test %d min %d max %d\n",
+ printf ("ADXL375 value %d %d %d self test %ld min %ld max %ld\n",
ao_adxl375_current.x,
ao_adxl375_current.y,
ao_adxl375_current.z,
- self_test_value,
- MIN_SELF_TEST,
- MAX_SELF_TEST);
+ (long) self_test_value,
+ (long) MIN_SELF_TEST,
+ (long) MAX_SELF_TEST);
}
const struct ao_cmds ao_adxl375_cmds[] = {
#define TNC_TX_DELAY 45
/// The size of the TNC output buffer.
-#define TNC_BUFFER_SIZE 40
+#define TNC_BUFFER_SIZE 48
/// States that define the current mode of the 1200 bps (A-FSK) state machine.
typedef enum
return (float) sensor * ((float) (BMX160_ACCEL_FULLSCALE * GRAVITY / 32767.0));
}
+#define ao_bmx_accel_to_sample(accel) ((accel_t) (accel) * (32767.0f / (BMX160_ACCEL_FULLSCALE * GRAVITY)))
+
#endif /* _BMX160_H_ */
uint8_t class, id;
struct ao_ublox_cksum cksum;
uint8_t i;
+ AO_TICK_TYPE packet_start_tick;
+ AO_TICK_TYPE solution_tick = 0;
ao_gps_setup();
/* Locate the begining of the next record */
while (ao_ublox_byte() != (uint8_t) 0xb5)
;
+ packet_start_tick = ao_tick_count;
+
if (ao_ublox_byte() != (uint8_t) 0x62)
continue;
ao_ublox_len = header_byte();
ao_ublox_len |= header_byte() << 8;
- ao_gps_dbg(DBG_PROTO, "class %02x id %02x len %d\n", class, id, ao_ublox_len);
+ ao_gps_dbg(DBG_PROTO, "%6u class %02x id %02x len %d\n", packet_start_tick, class, id, ao_ublox_len);
if (ao_ublox_len > 1023)
continue;
if (ao_ublox_len != 52)
break;
ao_ublox_parse_nav_sol();
+ solution_tick = packet_start_tick;
break;
case UBLOX_NAV_SVINFO:
if (ao_ublox_len < 8)
switch (id) {
case UBLOX_NAV_TIMEUTC:
ao_mutex_get(&ao_gps_mutex);
- ao_gps_tick = ao_time();
+ ao_gps_tick = solution_tick;
ao_gps_data.flags = 0;
ao_gps_data.flags |= AO_GPS_RUNNING;
ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
for (;;) {
- PRINTD("Drag monitor count %d active %d delay %d\n",
- ao_lco_drag_beep_count, ao_lco_drag_active, delay);
+ PRINTD("Drag monitor count %d active %d delay %lu\n",
+ ao_lco_drag_beep_count, ao_lco_drag_active, (unsigned long) delay);
if (delay == (AO_TICK_TYPE) ~0)
ao_sleep(&ao_lco_drag_beep_count);
else
for (;;) {
ao_event_get(&event);
- PRINTD("event type %d unit %d value %d\n",
- event.type, event.unit, event.value);
+ PRINTD("event type %d unit %d value %ld\n",
+ event.type, event.unit, (long) event.value);
switch (event.type) {
case AO_EVENT_QUADRATURE:
switch (event.unit) {
#if DEBUG
extern uint8_t ao_lco_debug;
-#define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0)
+#define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5lu %s: ", (unsigned long) ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0)
#else
#define PRINTD(...)
#endif
AO_TICK_TYPE
ao_lco_drag_beep_check(AO_TICK_TYPE now, AO_TICK_TYPE delay)
{
- PRINTD("beep check count %d delta %d\n",
+ PRINTD("beep check count %d delta %ld\n",
ao_lco_drag_beep_count,
- (AO_TICK_SIGNED) (now - ao_lco_drag_beep_time));
+ (long) (AO_TICK_SIGNED) (now - ao_lco_drag_beep_time));
if (ao_lco_drag_beep_count) {
if ((AO_TICK_SIGNED) (now - ao_lco_drag_beep_time) >= 0) {
if (ao_lco_drag_beep_on) {
ao_event_get(&event);
}
ao_lco_wakeup();
- PRINTD("event type %d unit %d value %d\n",
- event.type, event.unit, event.value);
+ PRINTD("event type %d unit %d value %ld\n",
+ event.type, event.unit, (long) event.value);
switch (event.type) {
case AO_EVENT_BUTTON:
switch (event.unit) {
* Erase the specified sector
*/
uint8_t
-ao_storage_erase(uint32_t pos)
+ao_storage_device_erase(uint32_t pos)
{
ao_port_t cs;
#define DEBUG_LOW 1
#define DEBUG_HIGH 2
#if 1
-#define PRINTD(l, ...) do { if (DEBUG & (l)) { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } } while(0)
+#define PRINTD(l, ...) do { if (DEBUG & (l)) { printf ("\r%5lu %s: ", (unsigned long) ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } } while(0)
#else
#define PRINTD(l,...)
#endif
#if AO_MPU9250_SPI
-#define ao_mpu9250_spi_get() ao_spi_get(AO_MPU9250_SPI_BUS, AO_SPI_SPEED_1MHz)
+#ifndef AO_MPU9250_SPI_SPEED
+#define AO_MPU9250_SPI_SPEED AO_SPI_SPEED_1MHz
+#endif
+
+#define ao_mpu9250_spi_get() ao_spi_get(AO_MPU9250_SPI_BUS, AO_MPU9250_SPI_SPEED)
#define ao_mpu9250_spi_put() ao_spi_put(AO_MPU9250_SPI_BUS)
#define ao_mpu9250_spi_start() ao_spi_set_cs(AO_MPU9250_SPI_CS_PORT, \
*/
ao_cur_task = &ao_mpu9250_task;
- ao_spi_get(AO_MPU9250_SPI_BUS, AO_SPI_SPEED_1MHz);
+ ao_mpu9250_spi_get();
ao_cur_task = NULL;
#endif
ao_cmd_register(&ao_mpu9250_cmds[0]);
break;
}
if ((AO_TICK_SIGNED) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) {
- PRINTD ("late pad arm_time %d time %d\n",
- ao_pad_arm_time, ao_time());
+ PRINTD ("late pad arm_time %ld time %ld\n",
+ (long) ao_pad_arm_time, ao_time());
break;
}
PRINTD ("ignite\n");
if (!ao_log_running) ao_log_start();
#endif
if ((AO_TICK_SIGNED) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) {
- PRINTD ("late pad arm_time %d time %d\n",
- ao_pad_arm_time, ao_time());
+ PRINTD ("late pad arm_time %ld time %ld\n",
+ (long) ao_pad_arm_time, (long) ao_time());
break;
}
PRINTD ("ignite\n");
t = ao_quadrature_step[q];
printf("step %3d ", t);
#endif
- printf ("count %3d state %2x\n", c, s);
+ printf ("count %3ld state %2x\n", (long) c, s);
flush();
}
}
--- /dev/null
+ao_product.h
+easytimer-*.elf
--- /dev/null
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_boot.h \
+ ao_companion.h \
+ ao_data.h \
+ ao_sample.h \
+ ao_pins.h \
+ altitude-pa.h \
+ ao_kalman.h \
+ ao_product.h \
+ ao_profile.h \
+ ao_task.h \
+ ao_whiten.h \
+ ao_sample_profile.h \
+ ao_mpu.h \
+ stm32l.h \
+ Makefile
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+#SAMPLE_PROFILE=ao_sample_profile.c \
+# ao_sample_profile_timer.c
+#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
+
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+
+ALTOS_SRC = \
+ ao_boot_chain.c \
+ ao_interrupt.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_config.c \
+ ao_task.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_data.c \
+ ao_bmx160.c \
+ ao_adc_stm.c \
+ ao_beep_stm.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_eeprom_stm.c \
+ ao_convert_volt.c \
+ ao_report.c \
+ ao_sample.c \
+ ao_kalman.c \
+ ao_pyro.c \
+ ao_flight.c \
+ ao_ignite.c \
+ $(PROFILE) \
+ $(SAMPLE_PROFILE) \
+ $(STACK_GUARD)
+
+PRODUCT=EasyTimer-v1
+PRODUCT_DEF=-DEASYTIMER_V_1
+IDPRODUCT=0x000d
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
+
+PROGNAME=easytimer-v1
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_easytimer.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_ms5607.h>
+#include <ao_adxl375.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_packet.h>
+#include <ao_companion.h>
+#include <ao_eeprom.h>
+#include <ao_profile.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+
+int
+main(void)
+{
+ ao_clock_init();
+
+#if HAS_STACK_GUARD
+ ao_mpu_init();
+#endif
+
+ ao_task_init();
+ ao_timer_init();
+
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_adc_init();
+ ao_beep_init();
+ ao_cmd_init();
+
+ ao_eeprom_init();
+
+// ao_storage_init();
+
+ ao_bmx160_init();
+
+ ao_flight_init();
+ // ao_log_init();
+ ao_report_init();
+
+ ao_usb_init();
+ ao_pyro_init();
+ ao_igniter_init();
+
+ ao_config_init();
+#if AO_PROFILE
+ ao_profile_init();
+#endif
+#if HAS_SAMPLE_PROFILE
+ ao_sample_profile_init();
+#endif
+
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE 1
+
+/* 16MHz High speed external crystal */
+#define AO_HSE 16000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL 6
+#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_6)
+
+/* SYSCLK = 32MHz (no need to go faster than CPU) */
+#define AO_PLLDIV 3
+#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3)
+
+/* HCLK = 32MHz (CPU clock) */
+#define AO_AHB_PRESCALER 1
+#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1
+
+/* Run APB1 at 16MHz (HCLK/2) */
+#define AO_APB1_PRESCALER 2
+#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2
+
+/* Run APB2 at 16MHz (HCLK/2) */
+#define AO_APB2_PRESCALER 2
+#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2
+
+#define HAS_SERIAL_1 0
+#define USE_SERIAL_1_STDIN 0
+#define SERIAL_1_PB6_PB7 0
+#define SERIAL_1_PA9_PA10 0
+
+#define HAS_SERIAL_2 0
+#define USE_SERIAL_2_STDIN 0
+#define SERIAL_2_PA2_PA3 0
+#define SERIAL_2_PD5_PD6 0
+
+#define HAS_SERIAL_3 0
+#define USE_SERIAL_3_STDIN 0
+#define SERIAL_3_PB10_PB11 0
+#define SERIAL_3_PC10_PC11 0
+#define SERIAL_3_PD8_PD9 0
+
+#define AO_CONFIG_MAX_SIZE 1024
+
+#define HAS_EEPROM 1
+#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
+#define HAS_USB 1
+#define HAS_BEEP 1
+#define HAS_BATTERY_REPORT 1
+#define BEEPER_CHANNEL 1
+#define BEEPER_TIMER 4
+#define BEEPER_PORT (&stm_gpiob)
+#define BEEPER_PIN 6
+#define HAS_RADIO 0
+#define HAS_TELEMETRY 0
+#define HAS_APRS 0
+#define HAS_COMPANION 0
+
+#define HAS_SPI_1 1
+#define SPI_1_PA5_PA6_PA7 0
+#define SPI_1_PB3_PB4_PB5 1 /* IMU */
+#define SPI_1_PE13_PE14_PE15 0
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2 0
+#define SPI_2_PB13_PB14_PB15 0 /* Flash, Companion, Radio */
+#define SPI_2_PD1_PD3_PD4 0
+#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
+
+#define SPI_2_PORT (&stm_gpiob)
+#define SPI_2_SCK_PIN 13
+#define SPI_2_MISO_PIN 14
+#define SPI_2_MOSI_PIN 15
+
+#define HAS_I2C_1 0
+#define I2C_1_PB8_PB9 0
+
+#define HAS_I2C_2 0
+#define I2C_2_PB10_PB11 0
+
+#define PACKET_HAS_SLAVE 0
+#define PACKET_HAS_MASTER 0
+
+#define LOW_LEVEL_DEBUG 0
+
+#define LEDS_AVAILABLE 0
+
+#define HAS_GPS 0
+#define HAS_FLIGHT 1
+#define HAS_ADC 1
+#define HAS_ADC_TEMP 1
+#define HAS_LOG 0
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE 0
+#define HAS_IGNITE_REPORT 1
+#define AO_PYRO_NUM 2
+
+#define AO_SENSE_PYRO(p,n) ((p)->adc.sense[n])
+#define AO_IGNITER_CLOSED 400
+#define AO_IGNITER_OPEN 60
+
+/* Pyro A */
+#define AO_PYRO_PORT_0 (&stm_gpiob)
+#define AO_PYRO_PIN_0 0
+
+#define AO_ADC_SENSE_A 1
+#define AO_ADC_SENSE_A_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_A_PIN 1
+
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpiob)
+#define AO_PYRO_PIN_1 11
+
+#define AO_ADC_SENSE_B 0
+#define AO_ADC_SENSE_B_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_B_PIN 0
+
+
+/*
+ * ADC
+ */
+#define AO_DATA_RING 32
+#define AO_ADC_NUM_SENSE 2
+
+struct ao_adc {
+ int16_t sense[AO_ADC_NUM_SENSE];
+ int16_t v_batt;
+ int16_t temp;
+};
+
+#define AO_ADC_DUMP(p) \
+ printf("tick: %5u A: %5d B: %5d batt: %5d\n", \
+ (p)->tick, \
+ (p)->adc.sense[0], (p)->adc.sense[1], \
+ (p)->adc.v_batt);
+
+#define AO_ADC_V_BATT 2
+#define AO_ADC_V_BATT_PORT (&stm_gpioa)
+#define AO_ADC_V_BATT_PIN 2
+
+#define AO_ADC_TEMP 16
+
+#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+ (1 << STM_RCC_AHBENR_GPIOEEN) | \
+ (1 << STM_RCC_AHBENR_GPIOBEN))
+
+#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 1)
+
+#define AO_ADC_PIN0_PORT AO_ADC_SENSE_A_PORT
+#define AO_ADC_PIN0_PIN AO_ADC_SENSE_A_PIN
+#define AO_ADC_PIN1_PORT AO_ADC_SENSE_B_PORT
+#define AO_ADC_PIN1_PIN AO_ADC_SENSE_B_PIN
+#define AO_ADC_PIN2_PORT AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN2_PIN AO_ADC_V_BATT_PIN
+
+#define AO_NUM_ADC (AO_NUM_ADC_PIN + 1)
+
+#define AO_ADC_SQ1 AO_ADC_SENSE_A
+#define AO_ADC_SQ2 AO_ADC_SENSE_B
+#define AO_ADC_SQ3 AO_ADC_V_BATT
+#define AO_ADC_SQ4 AO_ADC_TEMP
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS 100 /* 100k */
+#define AO_BATTERY_DIV_MINUS 27 /* 27k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS 100 /* 100k */
+#define AO_IGNITE_DIV_MINUS 27 /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV 33
+
+/*
+ * bmx160
+ */
+
+#define HAS_BMX160 1
+#define AO_BMX160_INT_PORT (&stm_gpioc)
+#define AO_BMX160_INT_PIN 13
+#define AO_BMX160_SPI_BUS (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_0)
+#define AO_BMX160_SPI_CS_PORT (&stm_gpioa)
+#define AO_BMX160_SPI_CS_PIN 15
+#define HAS_IMU 1
+
+#define ao_data_along(packet) ((packet)->bmx160.acc_x)
+#define ao_data_across(packet) (-(packet)->bmx160.acc_y)
+#define ao_data_through(packet) ((packet)->bmx160.acc_z)
+
+#define ao_data_roll(packet) ((packet)->bmx160.gyr_x)
+#define ao_data_pitch(packet) (-(packet)->bmx160.gyr_y)
+#define ao_data_yaw(packet) ((packet)->bmx160.gyr_z)
+
+#define ao_data_mag_along(packet) ((packet)->bmx160.mag_x)
+#define ao_data_mag_across(packet) (-(packet)->bmx160.mag_y)
+#define ao_data_mag_through(packet) ((packet)->bmx160.mag_z)
+
+#define ao_data_accel_cook(packet) (-ao_data_along(packet))
+
+/*
+ * Monitor
+ */
+
+#define HAS_MONITOR 0
+#define LEGACY_MONITOR 0
+#define HAS_MONITOR_PUT 1
+#define AO_MONITOR_LED 0
+#define HAS_RSSI 0
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=easytimer-v1
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2020 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 16MHz */
+#define AO_HSE 16000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port cs_companion0 PB6 */
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpioc
+#define AO_BOOT_APPLICATION_PIN 15
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
printf("manufacturer %s\n"
"product %s\n"
"serial-number %u\n"
-#if HAS_FLIGHT || HAS_TRACKER
+#if HAS_LOG && (HAS_FLIGHT || HAS_TRACKER)
"current-flight %u\n"
#endif
#if HAS_LOG
, ao_manufacturer
, ao_product
, ao_serial_number
-#if HAS_FLIGHT || HAS_TRACKER
+#if HAS_LOG && (HAS_FLIGHT || HAS_TRACKER)
, ao_flight_number
#endif
#if HAS_LOG
ao_config_setup();
ao_config_erase();
ao_config_write(0, &ao_config, sizeof (ao_config));
-#if HAS_FLIGHT
+#if HAS_FLIGHT && HAS_LOG
ao_log_write_erase(0);
#endif
ao_config_flush();
ao_config.pad_box = 1;
if (minor < 23)
ao_config.pad_idle = 120;
+#endif
+#if HAS_APRS
+ if (minor < 24)
+ ao_config.aprs_offset = 0;
#endif
ao_config.minor = AO_CONFIG_MINOR;
ao_config_dirty = 1;
#if HAS_FLIGHT
+#if HAS_BARO
+
static void
ao_config_main_deploy_show(void)
{
_ao_config_edit_finish();
}
+#endif
+
#if HAS_ACCEL
static void
ao_config_accel_calibrate_show(void)
}
#endif /* HAS_ACCEL */
+#if HAS_BARO
static void
ao_config_apogee_delay_show(void)
{
ao_config.apogee_lockout = r;
_ao_config_edit_finish();
}
+#endif
#endif /* HAS_FLIGHT */
ao_config_log_set(void)
{
#if FLIGHT_LOG_APPEND
- printf("Flight log fixed size %d kB\n", ao_storage_log_max >> 10);
+ printf("Flight log fixed size %u kB\n", (unsigned) (ao_storage_log_max >> 10));
#else
- uint16_t block = (uint16_t) (ao_storage_block >> 10);
- uint16_t log_max = (uint16_t) (ao_storage_log_max >> 10);
uint32_t r;
r = 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 && (r & (block - 1)))
- printf("Flight log size must be multiple of %d kB\n", block);
- else if (r > log_max)
- printf("Flight log max %d kB\n", log_max);
- else {
- _ao_config_edit_start();
- ao_config.flight_log_max = r << 10;
- _ao_config_edit_finish();
+ r = r << 10;
+ if (ao_log_present()) {
+ if (r != ao_config.flight_log_max)
+ printf("Storage must be empty before changing log size\n");
+ return;
+ }
+ if (r > ao_storage_log_max) {
+ printf("Flight log max %u kB\n", (unsigned) (ao_storage_log_max >> 10));
+ return;
}
+ _ao_config_edit_start();
+ ao_config.flight_log_max = r & ~(ao_storage_block - 1);
+ _ao_config_edit_finish();
#endif
}
#endif /* HAS_LOG */
ao_telemetry_reset_interval();
}
+static void
+ao_config_aprs_offset_show(void)
+{
+ printf ("APRS offset: %d\n", ao_config.aprs_offset);
+}
+
+static void
+ao_config_aprs_offset_set(void)
+{
+ uint16_t r = ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.aprs_offset = r;
+ _ao_config_edit_finish();
+ ao_telemetry_reset_interval();
+}
+
#endif /* HAS_APRS */
#if HAS_RADIO_AMP
#endif
const struct ao_config_var ao_config_vars[] = {
-#if HAS_FLIGHT
+#if HAS_FLIGHT && HAS_BARO
{ "m <meters>\0Main deploy (m)",
ao_config_main_deploy_set, ao_config_main_deploy_show, },
{ "d <delay>\0Apogee delay (s)",
ao_config_aprs_ssid_set, ao_config_aprs_ssid_show },
{ "C <0 compressed, 1 uncompressed>\0APRS format",
ao_config_aprs_format_set, ao_config_aprs_format_show },
+ { "O <aprs-offset>\0APRS Offset from top of minute",
+ ao_config_aprs_offset_set, ao_config_aprs_offset_show },
#endif
#if HAS_FIXED_PAD_BOX
{ "B <box>\0Set pad box (1-99)",
#include <ao_storage.h>
#define ao_config_setup() ao_storage_setup()
-#define ao_config_erase() ao_storage_erase(ao_storage_config)
+#define ao_config_erase() ao_storage_erase(ao_storage_config, ao_storage_block)
#define ao_config_write(pos,bytes, len) ao_storage_write(ao_storage_config+(pos), bytes, len)
#define ao_config_read(pos,bytes, len) ao_storage_read(ao_storage_config+(pos), bytes, len)
#define ao_config_flush() ao_storage_flush()
#endif
#define AO_CONFIG_MAJOR 1
-#define AO_CONFIG_MINOR 23
+#define AO_CONFIG_MINOR 24
#define AO_AES_LEN 16
uint8_t pad_box; /* minor version 22 */
uint8_t pad_idle; /* minor version 23 */
#endif
+#if HAS_APRS
+ uint8_t aprs_offset; /* minor version 24 */
+#endif
};
#define AO_APRS_FORMAT_COMPRESSED 0
void
ao_data_get(struct ao_data *packet)
{
-#if HAS_FLIGHT
- uint8_t i = ao_data_ring_prev(ao_sample_data);
-#else
uint8_t i = ao_data_ring_prev(ao_data_head);
-#endif
memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data));
}
#endif
+
+#if HAS_ACCEL
+accel_t
+ao_data_accel(volatile struct ao_data *packet) {
+ accel_t raw;
+ raw = ao_data_accel_raw(packet);
+ if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
+ raw = ao_data_accel_invert(raw);
+ return raw;
+}
+#endif
#endif
#if HAS_MPU9250
struct ao_mpu9250_sample mpu9250;
+#if !HAS_MMA655X
+ int16_t z_accel;
+#endif
#endif
#if HAS_HMC5883
struct ao_hmc5883_sample hmc5883;
#endif
#if HAS_BMX160
struct ao_bmx160_sample bmx160;
+#if !HAS_ADXL375
+ int16_t z_accel;
+#endif
#endif
};
#endif
-#if !HAS_BARO && HAS_ADC
-
-#define HAS_BARO 1
-
-typedef int16_t pres_t;
-typedef int16_t alt_t;
-
-#define ao_data_pres(packet) ((packet)->adc.pres)
-#define ao_data_temp(packet) ((packet)->adc.temp)
-#define pres_to_altitude(p) ao_pres_to_altitude(p)
-#define ao_data_pres_cook(p)
-
-#endif
-
/*
* Need a few macros to pull data from the sensors:
*
- * ao_data_accel_sample - pull raw sensor and convert to normalized values
- * ao_data_accel - pull normalized value (lives in the same memory)
- * ao_data_set_accel - store normalized value back in the sensor location
+ * ao_data_accel_raw - pull raw sensor
* ao_data_accel_invert - flip rocket ends for positive acceleration
*/
*/
typedef int16_t accel_t;
-#define ao_data_accel(packet) ((packet)->adc.accel)
-#define ao_data_set_accel(packet, a) ((packet)->adc.accel = (a))
+#define ao_data_accel_raw(packet) ((packet)->adc.accel)
#define ao_data_accel_invert(a) (0x7fff -(a))
/*
#if HAS_ACCEL_REF
-#define ao_data_accel_cook(packet) \
+#define ao_data_accel_raw(packet) \
((uint16_t) ((((uint32_t) (packet)->adc.accel << 16) / ((packet)->adc.accel_ref << 1))) >> 1)
#else
-#define ao_data_accel_cook(packet) ((packet)->adc.accel)
+#define ao_data_accel_raw(packet) ((packet)->adc.accel)
#endif /* HAS_ACCEL_REF */
#error AO_MMA655X_INVERT not defined
#endif
-#define ao_data_accel(packet) ((packet)->mma655x)
#if AO_MMA655X_INVERT
-#define ao_data_accel_cook(packet) (AO_ACCEL_INVERT - (packet)->mma655x)
+#define ao_data_accel_raw(packet) (AO_ACCEL_INVERT - (packet)->mma655x)
#else
-#define ao_data_accel_cook(packet) ((packet)->mma655x)
+#define ao_data_accel_raw(packet) ((packet)->mma655x)
#endif
-#define ao_data_set_accel(packet, accel) ((packet)->mma655x = (accel))
#define ao_data_accel_invert(accel) (AO_ACCEL_INVERT - (accel))
#endif
#error AO_ADXL375_INVERT not defined
#endif
-#define ao_data_accel(packet) ((packet)->adxl375.AO_ADXL375_AXIS)
#if AO_ADXL375_INVERT
-#define ao_data_accel_cook(packet) (-ao_data_accel(packet))
+#define ao_data_accel_raw(packet) (-(packet)->adxl375.AO_ADXL375_AXIS)
#else
-#define ao_data_accel_cook(packet) ao_data_accel(packet)
+#define ao_data_accel_raw(packet) ((packet)->adxl375.AO_ADXL375_AXIS)
#endif
-#define ao_data_set_accel(packet, accel) (ao_data_accel(packet) = (accel))
#define ao_data_accel_invert(accel) (-(accel))
#endif /* HAS_ADXL375 */
typedef int16_t accel_t;
/* MPU6000 is hooked up so that positive y is positive acceleration */
-#define ao_data_accel(packet) ((packet)->z_accel)
-#define ao_data_accel_cook(packet) (-(packet)->mpu6000.accel_y)
-#define ao_data_set_accel(packet, accel) ((packet)->z_accel = (accel))
+#define ao_data_accel_raw(packet) (-(packet)->mpu6000.accel_y)
#define ao_data_accel_invert(a) (-(a))
#endif
#endif
+#if !HAS_ACCEL && HAS_MPU9250
+
+#define HAS_ACCEL 1
+
+typedef int16_t accel_t;
+
+/* MPU9250 is hooked up so that positive y is positive acceleration */
+#define ao_data_accel_raw(packet) (-(packet)->mpu9250.accel_y)
+#define ao_data_accel_invert(a) (-(a))
+
+#endif
+
#if !HAS_GYRO && HAS_MPU9250
#define HAS_GYRO 1
#endif
+#if !HAS_ACCEL && HAS_BMX160
+
+#define HAS_ACCEL 1
+
+typedef int16_t accel_t;
+
+#define ao_data_accel_raw(packet) -ao_data_along(packet)
+#define ao_data_accel_invert(a) (-(a))
+#define ao_data_accel_to_sample(accel) ao_bmx_accel_to_sample(accel)
+
+#endif
+
#if !HAS_GYRO && HAS_BMX160
#define HAS_GYRO 1
#endif
+#if HAS_ACCEL
+accel_t
+ao_data_accel(volatile struct ao_data *packet);
+#endif
+
#endif /* _AO_DATA_H_ */
#ifndef _AO_EEPROM_H_
#define _AO_EEPROM_H_
-extern const ao_pos_t ao_eeprom_total;
-
/*
* Write to eeprom
*/
#include <ao_log.h>
#endif
+#include <ao_flight.h>
+
#if HAS_MPU6000 || HAS_MPU9250
#include <ao_quaternion.h>
#endif
* resting
*/
static uint16_t ao_interval_end;
+#ifdef HAS_BARO
static ao_v_t ao_interval_min_height;
static ao_v_t ao_interval_max_height;
+#else
+static accel_t ao_interval_min_accel_along, ao_interval_max_accel_along;
+static accel_t ao_interval_min_accel_across, ao_interval_max_accel_across;
+static accel_t ao_interval_min_accel_through, ao_interval_max_accel_through;
+#endif
#if HAS_ACCEL
static ao_v_t ao_coast_avg_accel;
#endif
+#define init_bounds(_cur, _min, _max) do { \
+ _min = _max = _cur; \
+ } while (0)
+
+#define check_bounds(_cur, _min, _max) do { \
+ if (_cur < _min) \
+ _min = _cur; \
+ if (_cur > _max) \
+ _max = _cur; \
+ } while(0)
+
uint8_t ao_flight_force_idle;
/* We also have a clock, which can be used to sanity check things in
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 ||
- ao_ground_height < -1000 ||
- ao_ground_height > 7000)
+ ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP
+#if HAS_BARO
+ || ao_ground_height < -1000 ||
+ ao_ground_height > 7000
+#endif
+ )
{
/* Detected an accel value outside -1.5g to 1.5g
* (or uncalibrated values), so we go into invalid mode
ao_launch_tick = ao_boost_tick = ao_sample_tick;
/* start logging data */
+#if HAS_LOG
ao_log_start();
+#endif
#if HAS_TELEMETRY
/* Increase telemetry rate */
(int16_t) (ao_sample_tick - ao_boost_tick) > BOOST_TICKS_MAX)
{
#if HAS_ACCEL
+#if HAS_BARO
ao_flight_state = ao_flight_fast;
+#else
+ ao_flight_state = ao_flight_coast;
+
+ /* Initialize landing detection interval values */
+ ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+
+ init_bounds(ao_sample_accel_along, ao_interval_min_accel_along, ao_interval_max_accel_along);
+ init_bounds(ao_sample_accel_across, ao_interval_min_accel_across, ao_interval_max_accel_across);
+ init_bounds(ao_sample_accel_through, ao_interval_min_accel_through, ao_interval_max_accel_through);
+#endif
ao_coast_avg_accel = ao_accel;
#else
ao_flight_state = ao_flight_coast;
ao_wakeup(&ao_flight_state);
}
break;
-#if HAS_ACCEL
+#if HAS_ACCEL && HAS_BARO
case ao_flight_fast:
/*
* This is essentially the same as coast,
#endif
case ao_flight_coast:
+#if HAS_BARO
/*
* By customer request - allow the user
* to lock out apogee detection for a specified
ao_flight_state = ao_flight_drogue;
ao_wakeup(&ao_flight_state);
}
+ else
+#else /* not HAS_BARO */
+ /* coast to land:
+ *
+ * accel: values stable
+ */
+ check_bounds(ao_sample_accel_along, ao_interval_min_accel_along, ao_interval_max_accel_along);
+ check_bounds(ao_sample_accel_across, ao_interval_min_accel_across, ao_interval_max_accel_across);
+ check_bounds(ao_sample_accel_through, ao_interval_min_accel_through, ao_interval_max_accel_through);
+
+#define MAX_QUIET_ACCEL 2
+
+ if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
+ if (ao_interval_max_accel_along - ao_interval_min_accel_along <= ao_data_accel_to_sample(MAX_QUIET_ACCEL) &&
+ ao_interval_max_accel_across - ao_interval_min_accel_across <= ao_data_accel_to_sample(MAX_QUIET_ACCEL) &&
+ ao_interval_max_accel_through - ao_interval_min_accel_through <= ao_data_accel_to_sample(MAX_QUIET_ACCEL))
+ {
+ ao_flight_state = ao_flight_landed;
+#if HAS_ADC
+ /* turn off the ADC capture */
+ ao_timer_set_adc_interval(0);
+#endif
+
+ ao_wakeup(&ao_flight_state);
+ }
+
+ /* Reset interval values */
+ ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+
+ init_bounds(ao_sample_accel_along, ao_interval_min_accel_along, ao_interval_max_accel_along);
+ init_bounds(ao_sample_accel_across, ao_interval_min_accel_across, ao_interval_max_accel_across);
+ init_bounds(ao_sample_accel_through, ao_interval_min_accel_through, ao_interval_max_accel_through);
+ }
+#endif
#if HAS_ACCEL
- else {
+ {
+#if HAS_BARO
check_re_boost:
+#endif
ao_coast_avg_accel = ao_coast_avg_accel + ((ao_accel - ao_coast_avg_accel) >> 5);
if (ao_coast_avg_accel > AO_MSS_TO_ACCEL(20)) {
ao_boost_tick = ao_sample_tick;
#endif
break;
+#if HAS_BARO
case ao_flight_drogue:
/* drogue to main deploy:
*
* 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_end = ao_sample_tick + AO_INTERVAL_TICKS;
}
break;
+#endif /* HAS_BARO */
#if HAS_FLIGHT_DEBUG
case ao_flight_test:
#if HAS_GYRO
printf ("sample:\n");
printf (" tick %d\n", ao_sample_tick);
+#if HAS_BARO
printf (" raw pres %d\n", ao_sample_pres);
+#endif
#if HAS_ACCEL
printf (" raw accel %d\n", ao_sample_accel);
#endif
+#if HAS_BARO
printf (" ground pres %d\n", ao_ground_pres);
printf (" ground alt %d\n", ao_ground_height);
+#endif
#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
+#if HAS_BARO
printf (" alt %d\n", ao_sample_alt);
printf (" height %d\n", ao_sample_height);
+#endif
+
#if HAS_ACCEL
printf (" accel %d.%02d\n", int_part(accel), frac_part(accel));
#endif
ao_ignite_set_pins();
ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
#endif
+#if HAS_IGNITE || AO_PYRO_NUM
ao_cmd_register(&ao_ignite_cmds[0]);
+#endif
}
ao_k_speed += (ao_k_t) ao_accel * AO_K_STEP_100;
}
+#if HAS_BARO
static void
ao_kalman_err_height(void)
{
#endif
}
}
+#endif
+#if HAS_BARO
static void
ao_kalman_correct_baro(void)
{
ao_k_speed += (ao_k_t) AO_BARO_K1_100 * ao_error_h;
ao_k_accel += (ao_k_t) AO_BARO_K2_100 * ao_error_h;
}
+#endif
#if HAS_ACCEL
ao_error_a = (accel - ao_k_accel) >> 16;
}
-#ifndef FORCE_ACCEL
+#if !defined(FORCE_ACCEL) && HAS_BARO
static void
ao_kalman_correct_both(void)
{
{
ao_kalman_err_accel();
+#ifdef AO_FLIGHT_TEST
if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 5) {
ao_k_height +=(ao_k_t) AO_ACCEL_K0_10 * ao_error_a;
ao_k_speed += (ao_k_t) AO_ACCEL_K1_10 * ao_error_a;
ao_k_accel += (ao_k_t) AO_ACCEL_K2_10 * ao_error_a;
return;
}
+#endif
ao_k_height += (ao_k_t) AO_ACCEL_K0_100 * ao_error_a;
ao_k_speed += (ao_k_t) AO_ACCEL_K1_100 * ao_error_a;
ao_k_accel += (ao_k_t) AO_ACCEL_K2_100 * ao_error_a;
ao_kalman(void)
{
ao_kalman_predict();
+#if HAS_BARO
#if HAS_ACCEL
if (ao_flight_state <= ao_flight_coast) {
#ifdef FORCE_ACCEL
} else
#endif
ao_kalman_correct_baro();
+#else
+#if HAS_ACCEL
+ ao_kalman_correct_accel();
+#endif
+#endif
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;
+#if HAS_BARO
ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
+#else
+ ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_height;
+#endif
#ifdef AO_FLIGHT_TEST
if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 50)
ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
ao_config_put();
}
+/* Position of first flight record in slot */
+static uint32_t
+ao_log_pos(uint8_t slot)
+{
+ return ((slot) * ao_config.flight_log_max);
+}
+
+/* Start of erase block containing first flight record */
+static uint32_t
+ao_log_pos_block_start(uint8_t slot)
+{
+ return ao_log_pos(slot) & ~(ao_storage_block - 1);
+}
+
+/* End of erase block containing last flight record */
+static uint32_t
+ao_log_pos_block_end(uint8_t slot)
+{
+ return ao_log_pos_block_start(slot + 1);
+}
+
#ifndef AO_LOG_UNCOMMON
/*
* Common logging functions which depend on the type of the log data
return 1;
}
-uint8_t
-ao_log_check_clear(void)
-{
- uint8_t *b = (uint8_t *) &ao_log_data;
- uint8_t i;
-
- for (i = 0; i < sizeof (ao_log_type); i++) {
- if (*b++ != 0xff)
- return 0;
- }
- return 1;
-}
-
int16_t
ao_log_flight(uint8_t slot)
{
+ if (ao_storage_is_erased(ao_log_pos_block_start(slot)))
+ return 0;
+
if (!ao_storage_read(ao_log_pos(slot),
&ao_log_data,
sizeof (ao_log_type)))
return -(int16_t) (slot + 1);
- if (ao_log_check_clear())
- return 0;
-
if (!ao_log_check_data() || ao_log_data.type != AO_LOG_FLIGHT)
return -(int16_t) (slot + 1);
return (uint8_t) (ao_storage_log_max / ao_config.flight_log_max);
}
-uint32_t
-ao_log_pos(uint8_t slot)
-{
- return ((slot) * ao_config.flight_log_max);
-}
-
static int16_t
ao_log_max_flight(void)
{
return max_flight;
}
-static void
+static uint8_t
ao_log_erase(uint8_t slot)
{
- uint32_t log_current_pos, log_end_pos;
+ uint32_t start_pos;
+ uint32_t end_pos;
ao_log_erase_mark();
- log_current_pos = ao_log_pos(slot);
- log_end_pos = log_current_pos + ao_config.flight_log_max;
- while (log_current_pos < log_end_pos) {
- uint8_t i;
- static 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(log_current_pos + i, &b, 1))
- if (b != 0xff)
- break;
- }
- if (i == 16)
- break;
- ao_storage_erase(log_current_pos);
- log_current_pos += ao_storage_block;
- }
+ start_pos = ao_log_pos_block_start(slot);
+ end_pos = ao_log_pos_block_end(slot);
+ return ao_storage_erase(start_pos, end_pos - start_pos);
}
static void
log_slots = ao_log_slots();
for (log_slot = 1; log_slot < log_slots; log_slot++) {
if (ao_log_flight(log_slot) != 0)
- ao_log_erase(log_slot);
+ if (!ao_log_erase(log_slot))
+ printf("erase %d failed\n", log_slot);
}
ao_config_log_fix_append();
}
ao_log_current_pos = ao_log_pos(0);
- ao_log_end_pos = ao_log_current_pos + ao_storage_log_max;
+ ao_log_end_pos = ao_log_pos_block_end(0);
if (ao_flight_number) {
uint32_t full = ao_log_current_pos;
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;
+ ao_log_end_pos = ao_log_pos_block_end(log_slot);
break;
}
if (++log_slot >= log_slots)
printf ("flight %d start %x end %x\n",
flight,
(uint16_t) (ao_log_pos(slot) >> 8),
- (uint16_t) (ao_log_pos(slot+1) >> 8));
+ (uint16_t) (ao_log_pos_block_end(slot) >> 8));
+ else
+ printf ("slot %d start %x end %x\n",
+ slot,
+ (uint16_t) (ao_log_pos(slot) >> 8),
+ (uint16_t) (ao_log_pos_block_end(slot) >> 8));
}
printf ("done\n");
}
#if HAS_TRACKER
ao_tracker_erase_start(cmd_flight);
#endif
- ao_log_erase(slot);
+ if (ao_log_erase(slot))
+ puts("Erased");
+ else
+ puts("Failed to erase");
#if HAS_TRACKER
ao_tracker_erase_end();
#endif
- puts("Erased");
return;
}
}
uint8_t
ao_log_scan(void);
-/* 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);
int8_t
ao_log_check(uint32_t pos)
{
+ if (ao_storage_is_erased(pos & ~(ao_storage_block - 1)))
+ return 0;
+
if (!ao_storage_read(pos,
&ao_log_data,
sizeof (struct ao_log_gps)))
return AO_LOG_INVALID;
- if (ao_log_check_clear())
- return AO_LOG_EMPTY;
-
if (!ao_log_check_data())
return AO_LOG_INVALID;
return AO_LOG_VALID;
#include <ao_data.h>
#include <ao_flight.h>
-static struct ao_log_telestatic log;
+static struct ao_log_telestatic log_data;
const uint8_t ao_log_format = AO_LOG_FORMAT_TELESTATIC;
{
uint8_t wrote = 0;
/* set checksum */
- log.csum = 0;
- log.csum = ao_log_csum((uint8_t *) &log);
+ log_data.csum = 0;
+ log_data.csum = ao_log_csum((uint8_t *) &log_data);
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,
+ &log_data,
sizeof (struct ao_log_telestatic));
ao_log_current_pos += sizeof (struct ao_log_telestatic);
}
while (!ao_log_running)
ao_sleep(&ao_log_running);
- log.type = AO_LOG_FLIGHT;
- log.tick = ao_time();
- log.u.flight.flight = ao_flight_number;
+ log_data.type = AO_LOG_FLIGHT;
+ log_data.tick = ao_time();
+ log_data.u.flight.flight = ao_flight_number;
ao_log_telestatic();
/* Write the whole contents of the ring to the log
for (;;) {
/* Write samples to EEPROM */
while (ao_log_data_pos != ao_data_head) {
- log.tick = ao_data_ring[ao_log_data_pos].tick;
- log.type = AO_LOG_SENSOR;
+ log_data.tick = ao_data_ring[ao_log_data_pos].tick;
+ log_data.type = AO_LOG_SENSOR;
#if HAS_ADS131A0X
- log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].ads131a0x.ain[0];
- log.u.sensor.pressure2 = ao_data_ring[ao_log_data_pos].ads131a0x.ain[1];
- log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].ads131a0x.ain[2];
- log.u.sensor.mass = ao_data_ring[ao_log_data_pos].ads131a0x.ain[3];
+ log_data.u.sensor.pressure = ao_data_ring[ao_log_data_pos].ads131a0x.ain[0];
+ log_data.u.sensor.pressure2 = ao_data_ring[ao_log_data_pos].ads131a0x.ain[1];
+ log_data.u.sensor.thrust = ao_data_ring[ao_log_data_pos].ads131a0x.ain[2];
+ log_data.u.sensor.mass = ao_data_ring[ao_log_data_pos].ads131a0x.ain[3];
#endif
- log.u.sensor.t_low = ao_data_ring[ao_log_data_pos].max6691.sensor[0].t_low;
+ log_data.u.sensor.t_low = ao_data_ring[ao_log_data_pos].max6691.sensor[0].t_low;
int i;
for (i = 0; i < 4; i++)
- log.u.sensor.t_high[i] = ao_data_ring[ao_log_data_pos].max6691.sensor[i].t_high;
+ log_data.u.sensor.t_high[i] = ao_data_ring[ao_log_data_pos].max6691.sensor[i].t_high;
ao_log_telestatic();
ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
}
#define TOTAL_LENGTH (HEADER_LEN + AO_USB_HAS_INT * CONTROL_CLASS_LEN + DATA_LEN)
#define NUM_INTERFACES (AO_USB_HAS_INT + 1)
+#ifndef AO_USBCONFIG_SYMBOL
+#define AO_USBCONFIG_SYMBOL AO_ROMCONFIG_SYMBOL
+#endif
+
/* USB descriptors in one giant block of bytes */
-AO_ROMCONFIG_SYMBOL uint8_t ao_usb_descriptors [] =
+AO_USBCONFIG_SYMBOL uint8_t ao_usb_descriptors [] =
{
/* Device descriptor */
0x12,
MORSE4(1,0,0,1), /* invalid 'X' */
};
+static enum ao_flight_state ao_report_state;
+
#if HAS_BEEP
#define low(time) ao_beep_for(AO_BEEP_LOW, time)
#define mid(time) ao_beep_for(AO_BEEP_MID, time)
#endif
#define pause(time) ao_delay(time)
-static enum ao_flight_state ao_report_state;
-
/*
* Farnsworth spacing
*
*/
static void
-ao_report_beep(void)
+ao_report_flight_state(void)
{
uint8_t r = flight_reports[ao_flight_state];
uint8_t l = r & 7;
#endif
#if HAS_IGNITE_REPORT
+#if HAS_IGNITE
static uint8_t
ao_report_igniter_ready(enum ao_igniter igniter)
{
return (ao_report_igniter_ready(ao_igniter_drogue) |
(ao_report_igniter_ready(ao_igniter_main) << 1));
}
+#endif
static void
ao_report_continuity(void)
{
- uint8_t c;
-
-#if !HAS_IGNITE
- if (!ao_igniter_present)
- return;
-#endif
+ uint8_t c;
+#if HAS_IGNITE
c = ao_report_igniter();
if (c) {
while (c--) {
low(AO_MS_TO_TICKS(20));
}
}
+#endif
#if AO_PYRO_NUM
+#if HAS_IGNITE
pause(AO_MS_TO_TICKS(250));
+#endif
for(c = 0; c < AO_PYRO_NUM; c++) {
enum ao_igniter_status status = ao_pyro_status(c);
if (status == ao_igniter_ready)
ao_report_battery();
else
#endif
- ao_report_beep();
+ ao_report_flight_state();
#if HAS_SENSOR_ERRORS
if (ao_report_state == ao_flight_invalid && ao_sensor_errors)
ao_report_number(ao_sensor_errors);
#endif
uint16_t ao_sample_tick; /* time of last data */
+#if HAS_BARO
pres_t ao_sample_pres;
alt_t ao_sample_alt;
alt_t ao_sample_height;
+#endif
#if HAS_ACCEL
accel_t ao_sample_accel;
#endif
* Sensor calibration values
*/
+#if HAS_BARO
pres_t ao_ground_pres; /* startup pressure */
alt_t ao_ground_height; /* MSL of ao_ground_pres */
+#endif
#if HAS_ACCEL
accel_t ao_ground_accel; /* startup acceleration */
static uint8_t ao_preflight; /* in preflight mode */
static uint16_t nsamples;
+#if HAS_BARO
int32_t ao_sample_pres_sum;
+#endif
#if HAS_ACCEL
int32_t ao_sample_accel_sum;
#endif
#if HAS_ACCEL
ao_sample_accel_sum += ao_sample_accel;
#endif
+#if HAS_BARO
ao_sample_pres_sum += ao_sample_pres;
+#endif
#if HAS_GYRO
ao_sample_accel_along_sum += ao_sample_accel_along;
ao_sample_accel_across_sum += ao_sample_accel_across;
ao_ground_accel = ao_sample_accel_sum >> 9;
ao_sample_accel_sum = 0;
#endif
+#if HAS_BARO
ao_ground_pres = ao_sample_pres_sum >> 9;
ao_ground_height = pres_to_altitude(ao_ground_pres);
ao_sample_pres_sum = 0;
+#endif
#if HAS_GYRO
ao_ground_accel_along = ao_sample_accel_along_sum >> 9;
ao_ground_accel_across = ao_sample_accel_across_sum >> 9;
ao_quaternion_vectors_to_rotation(&ao_rotation, &up, &orient);
#if HAS_FLIGHT_DEBUG
if (ao_orient_test)
- printf("\n\treset\n");
+ printf("\n\treset across %d through %d along %d\n",
+ (ao_ground_accel_across - ao_config.accel_zero_across),
+ (ao_ground_accel_through - ao_config.accel_zero_through),
+ (ao_ground_accel_along - ao_config.accel_zero_along));
#endif
ao_sample_compute_orient();
#endif
#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);
+ ao_sample_accel = ao_data_accel(ao_data);
#endif
#if HAS_GYRO
ao_sample_accel_along = ao_data_along(ao_data);
{
ao_config_get();
nsamples = 0;
+#if HAS_BARO
ao_sample_pres_sum = 0;
ao_sample_pres = 0;
+#endif
#if HAS_ACCEL
ao_sample_accel_sum = 0;
ao_sample_accel = 0;
#include <ao.h>
#include <ao_storage.h>
+#define AO_STORAGE_DATA_SIZE 256
+
+static uint8_t storage_data[AO_STORAGE_DATA_SIZE];
+
uint8_t
-ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len)
+ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len)
{
uint8_t *buf = v_buf;
uint16_t this_len;
return 1;
}
-static uint8_t storage_data[128];
+uint8_t
+ao_storage_is_erased(uint32_t pos)
+{
+ uint32_t read_pos;
+ uint32_t read_len;
+ uint32_t i;
+
+ read_pos = pos;
+ read_len = ao_storage_block;
+ while (read_len) {
+ uint32_t this_time = AO_STORAGE_DATA_SIZE;
+ if (this_time > read_len)
+ this_time = read_len;
+ if (!ao_storage_read(read_pos, storage_data, this_time))
+ return 0;
+ for (i = 0; i < this_time; i++)
+ if (storage_data[i] != 0xff)
+ return 0;
+ read_pos += this_time;
+ read_len -= this_time;
+ }
+ return 1;
+}
+
+uint8_t
+ao_storage_erase(uint32_t start_pos, uint32_t len)
+{
+ /* Round 'len' up to ao_storage_block units */
+ len = ((len + ao_storage_block - 1) / ao_storage_block) * ao_storage_block;
+
+ /*
+ * Start at the end of the area to erase so that the
+ * last block cleared is the first block; this will ensure
+ * that partially erased flight logs still appear in the list
+ * and can be re-erased.
+ */
+ uint32_t pos = start_pos + len - ao_storage_block;
+ while (len) {
+ int tries;
+
+#define MAX_TRIES 4 /* needs to be at least 2 */
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+ if (ao_storage_is_erased(pos))
+ break;
+ if (!ao_storage_device_erase(pos))
+ return 0;
+ }
+ if (tries == MAX_TRIES)
+ return 0;
+ pos -= ao_storage_block;
+ len -= ao_storage_block;
+ }
+ return 1;
+}
static void
ao_storage_dump(void)
uint32_t v = ao_cmd_hex();
if (ao_cmd_status != ao_cmd_success)
return;
- ao_storage_erase((uint32_t) v << 8);
+ ao_storage_erase((uint32_t) v << 8, ao_storage_block);
}
static void
ao_storage_zapall(void)
{
- uint32_t pos;
-
ao_cmd_white();
if (!ao_match_word("DoIt"))
return;
- for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
- ao_storage_erase(pos);
+ ao_storage_erase(0, ao_storage_log_max);
}
#if AO_STORAGE_TEST
static uint8_t
ao_storage_test_block(uint32_t pos)
{
- ao_storage_erase(pos);
+ ao_storage_erase(pos, ao_storage_block);
printf(" erase"); flush();
if (!ao_storage_check_block(pos, 0xff))
return 0;
printf(" zero"); flush();
if (!ao_storage_fill_check_block(pos, 0x00))
return 0;
- ao_storage_erase(pos);
+ ao_storage_erase(pos, ao_storage_block);
printf(" 0xaa"); flush();
if (!ao_storage_fill_check_block(pos, 0xaa))
return 0;
- ao_storage_erase(pos);
+ ao_storage_erase(pos, ao_storage_block);
printf(" 0x55"); flush();
if (!ao_storage_fill_check_block(pos, 0x55))
return 0;
- ao_storage_erase(pos);
+ ao_storage_erase(pos, ao_storage_block);
printf(" increment"); flush();
if (!ao_storage_incr_check_block(pos))
return 0;
- ao_storage_erase(pos);
+ ao_storage_erase(pos, ao_storage_block);
printf(" pass\n"); flush();
return 1;
}
}
printf("Test complete\n");
}
+
+static void
+ao_storage_fill(void)
+{
+ uint32_t pos;
+
+ ao_cmd_white();
+ if (!ao_match_word("DoIt"))
+ return;
+ printf("erase "); flush();
+ ao_storage_erase(0, ao_storage_log_max);
+ for (pos = 0; pos < sizeof (storage_data); pos++)
+ storage_data[pos] = (uint8_t) pos;
+ for (pos = 0; pos < ao_storage_log_max; pos += sizeof (storage_data)) {
+ if ((pos & 0xffff) == 0) {
+ printf("Fill 0x%x\n", pos); flush();
+ }
+ ao_storage_write(pos, storage_data, sizeof (storage_data));
+ }
+ printf("Fill complete\n");
+}
#endif /* AO_STORAGE_TEST */
static void
{ ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
#if AO_STORAGE_TEST
{ ao_storage_test, "V <key>\0Validate flash (destructive). <key> is doit with D&I" },
+ { ao_storage_fill, "F <key>\0Fill flash with data. <key> is doit with D&I" },
#endif
{ 0, NULL },
};
/* Erase a block of storage. This always clears ao_storage_block bytes */
uint8_t
-ao_storage_erase(ao_pos_t pos);
+ao_storage_erase(ao_pos_t pos, uint32_t len);
+
+/* Check storage starting at pos to see if the chunk there
+ * is erased
+ */
+uint8_t
+ao_storage_is_erased(uint32_t pos);
/* Flush any pending writes to stable storage */
void
uint8_t
ao_storage_device_write(ao_pos_t pos, void *buf, uint16_t len);
+/* Erase device from pos through pos + ao_storage_block */
+uint8_t
+ao_storage_device_erase(uint32_t pos);
+
/* Initialize low-level device bits */
void
ao_storage_device_init(void);
}
#endif
+#if HAS_APRS
+static void
+ao_set_aprs_time(void)
+{
+ uint16_t interval = ao_config.aprs_interval;
+
+ if ((ao_gps_data.flags & AO_GPS_DATE_VALID) && interval != 0) {
+ int second = (ao_gps_data.second / interval + 1) * interval + ao_config.aprs_offset;
+ int delta;
+ if (second >= 60) {
+ second = ao_config.aprs_offset;
+ delta = second + 60 - ao_gps_data.second;
+ } else {
+ delta = second - ao_gps_data.second;
+ }
+ ao_aprs_time = ao_gps_tick + AO_SEC_TO_TICKS(delta);
+ } else {
+ ao_aprs_time += AO_SEC_TO_TICKS(ao_config.aprs_interval);
+ }
+}
+#endif
+
static void
ao_telemetry(void)
{
#endif
#if HAS_APRS
ao_aprs_time = time;
+ ao_set_aprs_time();
#endif
while (ao_telemetry_interval) {
time = ao_time() + AO_SEC_TO_TICKS(100);
#if HAS_APRS
if (ao_config.aprs_interval != 0) {
if ((int16_t) (ao_time() - ao_aprs_time) >= 0) {
- ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval);
+ ao_set_aprs_time();
ao_aprs_send();
}
if ((int16_t) (time - ao_aprs_time) > 0)
height = -height;
if (ao_tracker_force_telem > 1)
- printf("head %d ring %d ground_distance %d height %d\n", gps_head, ring, ground_distance, height);
+ printf("head %d ring %d ground_distance %ld height %d\n", gps_head, ring, (long) ground_distance, height);
if (ground_distance > ao_config.tracker_motion ||
height > (ao_config.tracker_motion << 1))
{
CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS)
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos-loader.ld
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/lpc -Taltos-loader.ld
PROGNAME=altos-flash
PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
TOPDIR=..
endif
+# Disable floating-point support in printf to save space
+
+PICOLIBC_PRINTF_CFLAGS = -DPICOLIBC_INTEGER_PRINTF_SCANF
+
include $(TOPDIR)/Makefile.defs
vpath % $(TOPDIR)/lpc:$(AO_VPATH)
CC=$(ARM_CC)
-LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v6-m -lc -lm -lgcc
+LIBS=-lm
LPC_CFLAGS=-mlittle-endian -mcpu=cortex-m0 -mthumb\
- -I$(TOPDIR)/lpc $(AO_CFLAGS) $(NEWLIB_CFLAGS)
+ -I$(TOPDIR)/lpc $(AO_CFLAGS) $(PICOLIBC_CFLAGS)
include $(TOPDIR)/lpc/Makefile-lpc.defs
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld -n
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/lpc -Taltos.ld -n
ao_serial_lpc.h: $(TOPDIR)/lpc/baud_rate ao_pins.h
nickle $(TOPDIR)/lpc/baud_rate `awk '/AO_LPC_CLKOUT/{print $$3}' ao_pins.h` > $@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-MEMORY {
- rom : ORIGIN = 0x00000000, LENGTH = 4K
- ram : ORIGIN = 0x10000000, LENGTH = 4k - 128 - 32
- usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
- stack (!w) : ORIGIN = 0x10000000 + 4K - 128 - 32, LENGTH = 128
-}
+__flash = 0x0;
+__flash_size = 4K;
+__ram = 0x10000000;
+__ram_size = 4k;
+__stack_size = 128;
INCLUDE registers.ld
-
-EXTERN (lpc_interrupt_vector)
-
-SECTIONS {
- /*
- * Rom contents
- */
-
- .interrupt : {
- __text_start__ = .;
- *(.interrupt) /* Interrupt vectors */
-
- } > rom
-
- .text ORIGIN(rom) + 0x100 : {
- ao_romconfig.o(.romconfig*)
- ao_product.o(.romconfig*)
-
- *(.text*) /* Executable code */
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- *(.rodata*) /* Constants */
- __text_end__ = .;
- } > rom
-
- /* Boot data which must live at the start of ram so that
- * the application and bootloader share the same addresses.
- * This must be all uninitialized data
- */
- .boot ORIGIN(ram) + SIZEOF(.interrupt) (NOLOAD) : {
- __boot_start__ = .;
- *(.boot*)
- __boot_end__ = .;
- } >ram
-
- /* Data -- relocated to RAM, but written to ROM
- */
- .data : {
- _start__ = .;
- *(.data*) /* initialized data */
- _end__ = .;
- } >ram AT>rom
-
-
- .bss : {
- __bss_start__ = .;
- *(.bss*)
- *(COMMON*)
- __bss_end__ = .;
- } >ram
-
- PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram));
- PROVIDE(end = .);
-}
-
-ENTRY(start);
+INCLUDE picolibc.ld
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-MEMORY {
- rom (rx) : ORIGIN = 0x00001000, LENGTH = 28K
- ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K - 128
- usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
- stack (!w) : ORIGIN = 0x10000000 + 4K - 128, LENGTH = 128
-}
+__flash = 0x1000;
+__flash_size = 28K;
+__ram = 0x10000000;
+__ram_size = 4k;
+__stack_size = 128;
INCLUDE registers.ld
-
-EXTERN (lpc_interrupt_vector)
-
-SECTIONS {
- /*
- * Rom contents
- */
-
- .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) {
- __interrupt_start__ = .;
- __interrupt_rom__ = ORIGIN(rom);
- *(.interrupt) /* Interrupt vectors */
- __interrupt_end__ = .;
- } > ram
-
- .text ORIGIN(rom) + 0x100 : {
- __text_start__ = .;
-
- ao_romconfig.o(.romconfig*)
- ao_product.o(.romconfig*)
-
- *(.text*) /* Executable code */
- *(.rodata*) /* Constants */
-
- } > rom
-
- .ARM.exidx : {
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- __text_end__ = .;
- } > rom
-
- /* Boot data which must live at the start of ram so that
- * the application and bootloader share the same addresses.
- * This must be all uninitialized data
- */
- .boot : {
- __boot_start__ = .;
- *(.boot)
- . = ALIGN(4);
- __boot_end__ = .;
- } >ram
-
- /* Data -- relocated to RAM, but written to ROM
- */
- .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
- _start__ = .;
- *(.data) /* initialized data */
- _end__ = .;
- __bss_start__ = .;
- } >ram
-
- .bss : {
- __bss_start__ = .;
- *(.bss)
- *(COMMON)
- __bss_end__ = .;
- } >ram
- PROVIDE(end = .);
-
- PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
-}
-
-ENTRY(start);
-
-
+INCLUDE picolibc.ld
* ao_romconfig.c
*/
-#define AO_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
+#define AO_ROMCONFIG_SYMBOL __attribute__((section(".init.1"))) const
+#define AO_USBCONFIG_SYMBOL __attribute__((section(".init.2"))) const
#define ao_arch_block_interrupts() asm("cpsid i")
#define ao_arch_release_interrupts() asm("cpsie i")
uint32_t check;
};
-static struct ao_boot __attribute__ ((section(".boot"))) ao_boot;
+struct ao_boot ao_boot __attribute__((section(".preserve.2")));
int
ao_boot_check_chain(void)
#define RELOCATE_INTERRUPT 1
#endif
-extern void main(void);
-extern char __stack__;
-extern char __text_start__, __text_end__;
-extern char _start__, _end__;
-extern char __bss_start__, __bss_end__;
-#if RELOCATE_INTERRUPT
-extern char __interrupt_rom__, __interrupt_start__, __interrupt_end__;
-#endif
-
/* Interrupt functions */
void lpc_halt_isr(void)
{
}
-void start(void) {
-#ifdef AO_BOOT_CHAIN
- if (ao_boot_check_chain()) {
-#ifdef AO_BOOT_PIN
- if (ao_boot_check_pin())
-#endif
- {
- ao_boot_chain(AO_BOOT_APPLICATION_BASE);
- }
- }
-#endif
-#if RELOCATE_INTERRUPT
- memcpy(&__interrupt_start__, &__interrupt_rom__, &__interrupt_end__ - &__interrupt_start__);
- lpc_scb.sysmemremap = LPC_SCB_SYSMEMREMAP_MAP_RAM << LPC_SCB_SYSMEMREMAP_MAP;
-#endif
- memcpy(&_start__, &__text_end__, &_end__ - &_start__);
- memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
- main();
-}
-
#define STRINGIFY(x) #x
#define isr(name) \
#define i(addr,name) [(addr)/4] = lpc_ ## name ## _isr
#define c(addr,value) [(addr)/4] = (value)
-__attribute__ ((section(".interrupt")))
-const void *lpc_interrupt_vector[] = {
- [0] = &__stack__,
- [1] = start,
+extern char __stack[];
+void _start(void) __attribute__((__noreturn__));
+
+__attribute__ ((section(".init")))
+const void *const __interrupt_vector[0x30] = {
+ [0] = __stack,
+ [1] = _start,
i(0x08, nmi),
i(0x0c, hardfault),
c(0x10, 0),
i(0xb8, usb_wakeup),
i(0xbc, hardfault),
};
+
+/*
+ * Previous versions of this code had a 256 byte interupt vector. Add
+ * some padding to make sure the other low ROM variables land at the
+ * same address
+ */
+
+__attribute__ ((section(".init.0")))
+const void *const __interrupt_pad[0x10];
+
+void main(void) __attribute__((__noreturn__));
+
+void *__interrupt_ram[sizeof(__interrupt_vector)/sizeof(__interrupt_vector[0])] __attribute((section(".preserve.1")));
+
+extern char __data_source[];
+extern char __data_start[];
+extern char __data_size[];
+extern char __bss_start[];
+extern char __bss_size[];
+
+void _start(void) {
+ memcpy(__data_start, __data_source, (uintptr_t) __data_size);
+ memset(__bss_start, '\0', (uintptr_t) __bss_size);
+
+#ifdef AO_BOOT_CHAIN
+ if (ao_boot_check_chain()) {
+#ifdef AO_BOOT_PIN
+ if (ao_boot_check_pin())
+#endif
+ {
+ ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+ }
+ }
+#endif
+#if RELOCATE_INTERRUPT
+ memcpy(__interrupt_ram, __interrupt_vector, sizeof(__interrupt_ram));
+ lpc_scb.sysmemremap = LPC_SCB_SYSMEMREMAP_MAP_RAM << LPC_SCB_SYSMEMREMAP_MAP;
+#endif
+ main();
+}
static uint8_t ao_usb_out_rx_cur;
static uint8_t ao_usb_rx_count, ao_usb_rx_pos;
-extern struct lpc_usb_endpoint lpc_usb_endpoint;
-
/* Marks when we don't need to send an IN packet.
* This happens only when the last IN packet is not full,
* otherwise the host will expect to keep seeing packets.
};
extern struct lpc_ioconf lpc_ioconf;
+#define lpc_ioconf (*(struct lpc_ioconf *) 0x40044000)
#define LPC_IOCONF_FUNC 0
};
extern struct lpc_scb lpc_scb;
+#define lpc_scb (*(struct lpc_scb *) 0x40048000)
#define LPC_SCB_SYSMEMREMAP_MAP 0
# define LPC_SCB_SYSMEMREMAP_MAP_BOOT_LOADER 0
};
extern struct lpc_flash lpc_flash;
+#define lpc_flash (*(struct lpc_flash *) 0x4003c000)
struct lpc_gpio_pin {
vuint32_t isel; /* 0x00 */
};
extern struct lpc_gpio_pin lpc_gpio_pin;
+#define lpc_gpio_pin (*(struct lpc_gpio_pin *) 0x4004c000)
struct lpc_gpio_group0 {
};
};
extern struct lpc_gpio lpc_gpio;
+#define lpc_gpio (*(struct lpc_gpio *) 0x50000000)
struct lpc_systick {
uint8_t r0000[0x10]; /* 0x0000 */
};
extern struct lpc_systick lpc_systick;
+#define lpc_systick (*(struct lpc_systick *) 0xe000e000)
#define LPC_SYSTICK_CSR_ENABLE 0
#define LPC_SYSTICK_CSR_TICKINT 1
};
extern struct lpc_usart lpc_usart;
+#define lpc_usart (*(struct lpc_usart *) 0x40008000)
#define LPC_USART_IER_RBRINTEN 0
#define LPC_USART_IER_THREINTEN 1
} lpc_usb;
extern struct lpc_usb lpc_usb;
+#define lpc_usb (*(struct lpc_usb *) 0x40080000)
#define LPC_USB_DEVCMDSTAT_DEV_ADDR 0
#define LPC_USB_DEVCMDSTAT_DEV_ADDR_MASK 0x7f
vuint32_t reserved_0c;
struct lpc_usb_epn epn[4];
};
+#define lpc_usb_endpoint (*(struct lpc_usb_endpoint *) 0x20004700)
/* Assigned in registers.ld to point at the base
* of USB ram
*/
extern uint8_t lpc_usb_sram[];
+#define lpc_usb_sram ((uint8_t*) 0x20004000)
#define LPC_USB_EP_ACTIVE 31
#define LPC_USB_EP_DISABLED 30
};
extern struct lpc_nvic lpc_nvic;
+#define lpc_nvic (*(struct lpc_nvic *) 0xe000e100)
static inline void
lpc_nvic_set_enable(int irq) {
};
extern struct arm_scb arm_scb;
+#define arm_scb (*(struct arm_scb *) 0xe000ed00)
struct lpc_ssp {
vuint32_t cr0; /* 0x00 */
};
extern struct lpc_ssp lpc_ssp0, lpc_ssp1;
+#define lpc_ssp0 (*(struct lpc_ssp *) 0x40040000)
+#define lpc_ssp1 (*(struct lpc_ssp *) 0x40058000)
#define LPC_NUM_SPI 2
};
extern struct lpc_adc lpc_adc;
+#define lpc_adc (*(struct lpc_adc *) 0x4001c000)
#define LPC_ADC_CR_SEL 0
#define LPC_ADC_CR_CLKDIV 8
};
extern struct lpc_ct16b lpc_ct16b0, lpc_ct16b1;
-
#define lpc_ct16b0 (*(struct lpc_ct16b *) 0x4000c000)
#define lpc_ct16b1 (*(struct lpc_ct16b *) 0x40010000)
};
extern struct lpc_ct32b lpc_ct32b0, lpc_ct32b1;
+#define lpc_ct32b0 (*(struct lpc_ct32b *) 0x40014000)
+#define lpc_ct32b1 (*(struct lpc_ct32b *) 0x40018000)
#define LPC_CT32B_TCR_CEN 0
#define LPC_CT32B_TCR_CRST 1
all: $(PROG) $(HEX)
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tmicropeak.ld -n
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stmf0 -Tmicropeak.ld -n
$(PROG): Makefile $(OBJ) micropeak.ld
- $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS) -Wl,-Map=$(PROGNAME)-$(VERSION).map
distclean: clean
static void
ao_log_erase(void)
{
- uint32_t pos;
- for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
- ao_storage_erase(pos);
+ ao_storage_erase(0, ao_storage_log_max);
}
uint8_t ao_on_battery;
if (ao_log_present())
printf ("flight %d start %x end %x\n",
1,
- 0, MAX_LOG_OFFSET >> 8);
+ 0, (unsigned) (MAX_LOG_OFFSET >> 8));
printf ("done\n");
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-MEMORY {
- rom (rx) : ORIGIN = 0x08001000, LENGTH = 20K
- flash(rx) : ORIGIN = 0x08006000, LENGTH = 8K
- ram (!w) : ORIGIN = 0x20000000, LENGTH = 6k - 512
- stack (!w) : ORIGIN = 0x20000000 + 6k - 512, LENGTH = 512
-}
+__flash = 0x08001000;
+__flash_size = 22K;
+__flash__ = __flash + __flash_size;
+__flash_end__ = __flash__ + 6K;
+__ram = 0x20000000;
+__ram_size = 6K;
+__stack_size = 512;
INCLUDE registers.ld
-
-EXTERN (stm_interrupt_vector)
-
-SECTIONS {
- /*
- * Rom contents
- */
-
- .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) {
- __interrupt_start__ = .;
- __interrupt_rom__ = ORIGIN(rom);
- *(.interrupt) /* Interrupt vectors */
- __interrupt_end__ = .;
- } > ram
-
- .text ORIGIN(rom) + 0x100 : {
- __text_start__ = .;
-
- /* Ick. What I want is to specify the
- * addresses of some global constants so
- * that I can find them across versions
- * of the application. I can't figure out
- * how to make gnu ld do that, so instead
- * we just load the two files that include
- * these defines in the right order here and
- * expect things to 'just work'. Don't change
- * the contents of those files, ok?
- */
- ao_romconfig.o(.romconfig*)
- ao_product.o(.romconfig*)
-
- *(.text*) /* Executable code */
- } > rom
-
- .ARM.exidx : {
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- } > rom
-
- .rodata : {
- *(.rodata*) /* Constants */
- } > rom
-
- __text_end__ = .;
-
- /* Boot data which must live at the start of ram so that
- * the application and bootloader share the same addresses.
- * This must be all uninitialized data
- */
- .boot (NOLOAD) : {
- __boot_start__ = .;
- *(.boot)
- . = ALIGN(4);
- __boot_end__ = .;
- } >ram
-
- /* Functions placed in RAM (required for flashing)
- *
- * Align to 8 bytes as that's what the ARM likes text
- * segment alignments to be, and if we don't, then
- * we end up with a mismatch between the location in
- * ROM and the desired location in RAM. I don't
- * entirely understand this, but at least this appears
- * to work...
- */
-
- .textram BLOCK(8): {
- _start__ = .;
- *(.ramtext)
- } >ram AT>rom
-
- /* Data -- relocated to RAM, but written to ROM,
- * also aligned to 8 bytes to agree with textram
- */
- .data BLOCK(8): {
- *(.data) /* initialized data */
- _end__ = .;
- } >ram AT>rom
-
- .bss : {
- __bss_start__ = .;
- *(.bss)
- *(COMMON)
- . = ALIGN(4);
- __bss_end__ = .;
- } >ram
-
- PROVIDE(end = .);
-
- PROVIDE(__flash__ = ORIGIN(flash));
- PROVIDE(__flash_end__ = ORIGIN(flash) + LENGTH(flash));
-
- PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
-}
-
-ENTRY(start);
-
-
+INCLUDE picolibc.ld
.textram BLOCK(8): {
_start__ = .;
__text_ram_start__ = .;
- *(.ramtext)
+ *(.srodata)
__text_ram_end = .;
} >ram AT>rom
CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Wl,-Taltos-loader.ld -n
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stm -Taltos-loader.ld -n
PROGNAME=altos-flash
PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
$(PROG): Makefile $(OBJ) altos-loader.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
vpath % $(TOPDIR)/stm:$(AO_VPATH)
CC=$(ARM_CC)
-LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v7-m -lm -lc -lgcc
+LIBS=-lm
STM_CFLAGS=-mlittle-endian -mcpu=cortex-m3 -mthumb \
- -I$(TOPDIR)/stm $(AO_CFLAGS) $(NEWLIB_CFLAGS)
+ -I$(TOPDIR)/stm $(AO_CFLAGS) $(PICOLIBC_CFLAGS)
include $(TOPDIR)/stm/Makefile-stm.defs
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Wl,-Taltos.ld -n
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stm -Taltos.ld -n
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-MEMORY {
- rom : ORIGIN = 0x08000000, LENGTH = 4K
- ram : ORIGIN = 0x20000000, LENGTH = 16K
-}
+__flash = 0x08000000;
+__flash_size = 4K;
+__ram = 0x20000000;
+__ram_size = 16K;
+__stack_size = 512;
INCLUDE registers.ld
-
-EXTERN (stm_interrupt_vector)
-
-SECTIONS {
- /*
- * Rom contents
- */
-
- .text : {
- __text_start__ = .;
- *(.interrupt) /* Interrupt vectors */
-
- . = ORIGIN(rom) + 0x100;
-
- ao_romconfig.o(.romconfig*)
- ao_product.o(.romconfig*)
- *(.text*) /* Executable code */
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- *(.rodata*) /* Constants */
- } > rom
- __text_end__ = .;
-
- /* Boot data which must live at the start of ram so that
- * the application and bootloader share the same addresses.
- * This must be all uninitialized data
- */
- .boot (NOLOAD) : {
- __boot_start__ = .;
- *(.boot)
- __boot_end__ = .;
- } >ram
-
- /* Functions placed in RAM (required for flashing)
- *
- * Align to 8 bytes as that's what the ARM likes text
- * segment alignments to be, and if we don't, then
- * we end up with a mismatch between the location in
- * ROM and the desired location in RAM. I don't
- * entirely understand this, but at least this appears
- * to work...
- */
-
- .textram BLOCK(8): {
- _start__ = .;
- __text_ram_start__ = .;
- *(.ramtext)
- __text_ram_end = .;
- } >ram AT>rom
-
- /* Data -- relocated to RAM, but written to ROM
- * Also aligned to 8 bytes to agree with textram
- */
- .data BLOCK(8): {
- *(.data) /* initialized data */
- _end__ = .;
- } >ram AT>rom
-
-
- .bss : {
- __bss_start__ = .;
- *(.bss)
- *(COMMON)
- __bss_end__ = .;
- } >ram
-
- PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram));
- PROVIDE(end = .);
-}
-
-ENTRY(start);
-
-
+INCLUDE picolibc.ld
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-MEMORY {
- rom (rx) : ORIGIN = 0x08001000, LENGTH = 124K
- ram (!w) : ORIGIN = 0x20000000, LENGTH = 15872
- stack (!w) : ORIGIN = 0x20003e00, LENGTH = 512
-}
+__flash = 0x08001000;
+__flash_size = 124K;
+__ram = 0x20000000;
+__ram_size = 16k;
+__stack_size = 512;
INCLUDE registers.ld
-
-EXTERN (stm_interrupt_vector)
-
-SECTIONS {
- /*
- * Rom contents
- */
-
- .text ORIGIN(rom) : {
- __text_start__ = .;
- *(.interrupt) /* Interrupt vectors */
-
- . = ORIGIN(rom) + 0x100;
-
-
- /* Ick. What I want is to specify the
- * addresses of some global constants so
- * that I can find them across versions
- * of the application. I can't figure out
- * how to make gnu ld do that, so instead
- * we just load the two files that include
- * these defines in the right order here and
- * expect things to 'just work'. Don't change
- * the contents of those files, ok?
- */
- ao_romconfig.o(.romconfig*)
- ao_product.o(.romconfig*)
- *(.text*) /* Executable code */
- *(.rodata*) /* Constants */
-
- } > rom
-
- .ARM.exidx : {
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- } > rom
- __text_end__ = .;
-
- /* Boot data which must live at the start of ram so that
- * the application and bootloader share the same addresses.
- * This must be all uninitialized data
- */
- .boot (NOLOAD) : {
- __boot_start__ = .;
- *(.boot)
- . = ALIGN(4);
- __boot_end__ = .;
- } >ram
-
- /* Data -- relocated to RAM, but written to ROM
- */
- .data : {
- _start__ = .;
- *(.data) /* initialized data */
- . = ALIGN(4);
- _end__ = .;
- } >ram AT>rom
-
- .bss : {
- __bss_start__ = .;
- *(.bss)
- *(COMMON)
- . = ALIGN(4);
- __bss_end__ = .;
- } >ram
-
- PROVIDE(end = .);
-
- PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
-}
-
-ENTRY(start);
-
-
+INCLUDE picolibc.ld
* ao_romconfig.c
*/
-#define AO_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
+#define AO_ROMCONFIG_SYMBOL __attribute__((section(".init.1"))) const
+#define AO_USBCONFIG_SYMBOL __attribute__((section(".init.2"))) const
/*
* For now, we're running at a weird frequency
uint32_t check;
};
-static struct ao_boot __attribute__ ((section(".boot"))) ao_boot;
-
+struct ao_boot ao_boot __attribute__((section(".preserve.2")));
+
int
ao_boot_check_chain(void)
{
#include <ao_eeprom.h>
/* Total bytes of available storage */
-const ao_pos_t ao_eeprom_total = 4096;
+#define ao_eeprom_total 4096
/* Location of eeprom in address space */
#define stm_eeprom ((uint8_t *) 0x08080000)
;
}
-static void __attribute__ ((section(".ramtext"),noinline))
+static void __attribute__ ((section(".sdata2.flash"), noinline))
_ao_flash_erase_page(uint32_t *page)
{
stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG);
ao_arch_release_interrupts();
}
-static void __attribute__ ((section(".ramtext"), noinline))
+static void __attribute__ ((section(".sdata2.flash"), noinline))
_ao_flash_half_page(uint32_t *dst, uint32_t *src)
{
uint8_t i;
#include <ao_boot.h>
extern void main(void);
-extern char __stack__;
-extern char __text_start__, __text_end__;
-extern char _start__, _end__;
-extern char __bss_start__, __bss_end__;
/* Interrupt functions */
{
}
-const void *stm_interrupt_vector[];
-
uint32_t
stm_flash_size(void) {
uint16_t dev_id = stm_dev_id();
return (uint32_t) kbytes * 1024;
}
-void start(void)
-{
-#ifdef AO_BOOT_CHAIN
- if (ao_boot_check_chain()) {
-#ifdef AO_BOOT_PIN
- if (ao_boot_check_pin())
-#endif
- {
- ao_boot_chain(AO_BOOT_APPLICATION_BASE);
- }
- }
-#endif
- /* Set interrupt vector table offset */
- stm_nvic.vto = (uint32_t) &stm_interrupt_vector;
- memcpy(&_start__, &__text_end__, &_end__ - &_start__);
- memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
- main();
-}
-
#define STRINGIFY(x) #x
#define isr(name) \
#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr
-__attribute__ ((section(".interrupt")))
-const void *stm_interrupt_vector[] = {
- [0] = &__stack__,
- [1] = start,
+extern char __stack[];
+void _start(void) __attribute__((__noreturn__));
+void main(void) __attribute__((__noreturn__));
+
+/* This must be exactly 256 bytes long so that the configuration data
+ * gets loaded at the right place
+ */
+
+__attribute__ ((section(".init")))
+const void * const __interrupt_vector[64] = {
+ [0] = &__stack,
+ [1] = _start,
i(0x08, nmi),
i(0x0c, hardfault),
i(0x10, memmanage),
i(0xec, tim6),
i(0xf0, tim7),
};
+
+extern char __data_source[];
+extern char __data_start[];
+extern char __data_size[];
+extern char __bss_start[];
+extern char __bss_size[];
+
+void _start(void) {
+ memcpy(__data_start, __data_source, (uintptr_t) __data_size);
+ memset(__bss_start, '\0', (uintptr_t) __bss_size);
+
+#ifdef AO_BOOT_CHAIN
+ if (ao_boot_check_chain()) {
+#ifdef AO_BOOT_PIN
+ if (ao_boot_check_pin())
+#endif
+ {
+ ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+ }
+ }
+#endif
+ /* Set interrupt vector table offset */
+ stm_nvic.vto = (uint32_t) &__interrupt_vector;
+ main();
+}
.textram BLOCK(8): {
_start__ = .;
__text_ram_start__ = .;
- *(.ramtext)
+ *(.srodata)
__text_ram_end = .;
} >ram AT>rom
CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos-loader.ld
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stmf0 -Taltos-loader.ld
PROGNAME=altos-flash
PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(BIN)
$(PROG): Makefile $(OBJ) altos-loader.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(BIN): $(PROG)
$(MAKEBIN) --output=$@ --base=$(FLASH_ADDR) $(PROG)
TOPDIR=..
endif
+# Disable floating-point support in printf to save space
+
+PICOLIBC_PRINTF_CFLAGS = -DPICOLIBC_INTEGER_PRINTF_SCANF
+
include $(TOPDIR)/Makefile.defs
vpath % $(TOPDIR)/stmf0:$(AO_VPATH)
CC=$(ARM_CC)
STMF0_CFLAGS=-mlittle-endian -mcpu=cortex-m0 -mthumb\
- -I$(TOPDIR)/stmf0 $(AO_CFLAGS) $(NEWLIB_CFLAGS)
+ -I$(TOPDIR)/stmf0 $(AO_CFLAGS) $(PICOLIBC_CFLAGS)
-LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v6-m -lc -lm -lgcc
+LIBS=-lm
include $(TOPDIR)/stmf0/Makefile-stmf0.defs
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld -n
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stmf0 -Taltos.ld -n
LOADER=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf
MAKEBIN=$(TOPDIR)/../ao-tools/ao-makebin/ao-makebin
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-MEMORY {
- rom : ORIGIN = 0x08000000, LENGTH = 4K
- ram : ORIGIN = 0x20000000, LENGTH = 6K
-}
+__flash = 0x08000000;
+__flash_size = 4K;
+__ram = 0x20000000;
+__ram_size = 6k;
+__stack_size = 128;
INCLUDE registers.ld
-
-EXTERN (stm_interrupt_vector)
-
-SECTIONS {
- /*
- * Rom contents
- */
-
- .interrupt : {
- __text_start__ = .;
- *(.interrupt) /* Interrupt vectors */
- } > rom
-
- .text ORIGIN(rom) + 0x100 : {
- ao_romconfig.o(.romconfig*)
- ao_product.o(.romconfig*)
-
- *(.text*) /* Executable code */
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- *(.rodata*) /* Constants */
- } > rom
- __text_end__ = .;
-
- /* Boot data which must live at the start of ram so that
- * the application and bootloader share the same addresses.
- * This must be all uninitialized data
- */
- .boot ORIGIN(ram) + SIZEOF(.interrupt) (NOLOAD) : {
- __boot_start__ = .;
- *(.boot)
- __boot_end__ = .;
- } >ram
-
- /* Functions placed in RAM (required for flashing)
- *
- * Align to 8 bytes as that's what the ARM likes text
- * segment alignments to be, and if we don't, then
- * we end up with a mismatch between the location in
- * ROM and the desired location in RAM. I don't
- * entirely understand this, but at least this appears
- * to work...
- */
-
- .textram BLOCK(8): {
- _start__ = .;
- __text_ram_start__ = .;
- *(.ramtext)
- __text_ram_end = .;
- } >ram AT>rom
-
- /* Data -- relocated to RAM, but written to ROM.
- * also aligned to 8 bytes in case textram is empty
- */
- .data BLOCK(8): {
- *(.data) /* initialized data */
- _end__ = .;
- } >ram AT>rom
-
-
- .bss : {
- __bss_start__ = .;
- *(.bss)
- *(COMMON)
- __bss_end__ = .;
- } >ram
-
- PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram));
- PROVIDE(end = .);
-}
-
-ENTRY(start);
-
-
+INCLUDE picolibc.ld
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-MEMORY {
- rom (rx) : ORIGIN = 0x08001000, LENGTH = 28K
- ram (!w) : ORIGIN = 0x20000000, LENGTH = 6k - 128
- stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128
-}
+__flash = 0x08001000;
+__flash_size = 28K;
+__ram = 0x20000000;
+__ram_size = 6k;
+__stack_size = 128;
INCLUDE registers.ld
-
-EXTERN (stm_interrupt_vector)
-
-SECTIONS {
- /*
- * Rom contents
- */
-
- .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) {
- __interrupt_start__ = .;
- __interrupt_rom__ = ORIGIN(rom);
- *(.interrupt) /* Interrupt vectors */
- __interrupt_end__ = .;
- } > ram
-
- .text ORIGIN(rom) + 0x100 : {
- __text_start__ = .;
-
- /* Ick. What I want is to specify the
- * addresses of some global constants so
- * that I can find them across versions
- * of the application. I can't figure out
- * how to make gnu ld do that, so instead
- * we just load the two files that include
- * these defines in the right order here and
- * expect things to 'just work'. Don't change
- * the contents of those files, ok?
- */
- ao_romconfig.o(.romconfig*)
- ao_product.o(.romconfig*)
-
- *(.text*) /* Executable code */
- } > rom
-
- .ARM.exidx : {
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- } > rom
-
- .rodata : {
- *(.rodata*) /* Constants */
- } > rom
-
- __text_end__ = .;
-
- /* Boot data which must live at the start of ram so that
- * the application and bootloader share the same addresses.
- * This must be all uninitialized data
- */
- .boot (NOLOAD) : {
- __boot_start__ = .;
- *(.boot)
- . = ALIGN(4);
- __boot_end__ = .;
- } >ram
-
- /* Data -- relocated to RAM, but written to ROM
- */
- .data : {
- _start__ = .;
- *(.data) /* initialized data */
- . = ALIGN(4);
- _end__ = .;
- } >ram AT>rom
-
- .bss : {
- __bss_start__ = .;
- *(.bss)
- *(COMMON)
- . = ALIGN(4);
- __bss_end__ = .;
- } >ram
-
- PROVIDE(end = .);
-
- PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
-}
-
-ENTRY(start);
-
-
+INCLUDE picolibc.ld
* ao_romconfig.c
*/
-#define AO_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
+#define AO_ROMCONFIG_SYMBOL __attribute__((section(".init.1"))) const
+#define AO_USBCONFIG_SYMBOL __attribute__((section(".init.2"))) const
extern const uint16_t ao_romconfig_version;
extern const uint16_t ao_romconfig_check;
uint32_t check;
};
-static struct ao_boot __attribute__ ((section(".boot"))) ao_boot;
+struct ao_boot ao_boot __attribute__((section(".preserve.2")));
int
ao_boot_check_chain(void)
#define ao_flash_wait_bsy() do { while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)); } while (0)
-static void __attribute__ ((section(".ramtext"),noinline))
+static void __attribute__ ((section(".sdata2.flash"), noinline))
_ao_flash_erase_page(uint32_t *page)
{
stm_flash.cr |= (1 << STM_FLASH_CR_PER);
ao_arch_release_interrupts();
}
-static void __attribute__ ((section(".ramtext"), noinline))
+static void __attribute__ ((section(".sdata2.flash"), noinline))
_ao_flash_page(uint16_t *dst, uint16_t *src)
{
uint8_t i;
#endif
#endif
-extern void main(void);
-extern char __stack__;
-extern char __text_start__, __text_end__;
-extern char _start__, _end__;
-extern char __bss_start__, __bss_end__;
-#if RELOCATE_INTERRUPT
-extern char __interrupt_rom__, __interrupt_start__, __interrupt_end__;
-#endif
-
/* Interrupt functions */
void stm_halt_isr(void)
{
}
-const void *stm_interrupt_vector[];
-
uint32_t
stm_flash_size(void) {
uint16_t dev_id = stm_dev_id();
return (uint32_t) kbytes * 1024;
}
-void start(void)
-{
-#if AO_BOOT_CHAIN
- if (ao_boot_check_chain()) {
-#if AO_BOOT_PIN
- if (ao_boot_check_pin())
-#endif
- {
- ao_boot_chain(AO_BOOT_APPLICATION_BASE);
- }
- }
-#endif
- /* Turn on syscfg */
- stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN);
-
-#if RELOCATE_INTERRUPT
- memcpy(&__interrupt_start__, &__interrupt_rom__, &__interrupt_end__ - &__interrupt_start__);
- stm_syscfg.cfgr1 = (stm_syscfg.cfgr1 & ~(STM_SYSCFG_CFGR1_MEM_MODE_MASK << STM_SYSCFG_CFGR1_MEM_MODE)) |
- (STM_SYSCFG_CFGR1_MEM_MODE_SRAM << STM_SYSCFG_CFGR1_MEM_MODE);
-#else
- /* Switch to Main Flash mode (DFU loader leaves us in System mode) */
- stm_syscfg.cfgr1 = (stm_syscfg.cfgr1 & ~(STM_SYSCFG_CFGR1_MEM_MODE_MASK << STM_SYSCFG_CFGR1_MEM_MODE)) |
- (STM_SYSCFG_CFGR1_MEM_MODE_MAIN_FLASH << STM_SYSCFG_CFGR1_MEM_MODE);
-#endif
- memcpy(&_start__, &__text_end__, &_end__ - &_start__);
- memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
- main();
-}
-
#define STRINGIFY(x) #x
#define isr(name) \
#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr
-__attribute__ ((section(".interrupt")))
-const void *stm_interrupt_vector[] = {
- [0] = &__stack__,
- [1] = start,
+extern char __stack[];
+void _start(void) __attribute__((__noreturn__));
+void main(void) __attribute__((__noreturn__));
+
+__attribute__ ((section(".init")))
+const void * const __interrupt_vector[0x30] = {
+ [0] = __stack,
+ [1] = _start,
i(0x08, nmi),
i(0x0c, hardfault),
i(0x2c, svc),
i(0xb8, cec_can),
i(0xbc, usb),
};
+
+/*
+ * Previous versions of this code had a 256 byte interupt vector. Add
+ * some padding to make sure the other low ROM variables land at the
+ * same address
+ */
+
+__attribute__ ((section(".init.0")))
+const void *const __interrupt_pad[0x10];
+
+void *__interrupt_ram[sizeof(__interrupt_vector)/sizeof(__interrupt_vector[0])] __attribute__((section(".preserve.1")));
+
+extern char __data_source[];
+extern char __data_start[];
+extern char __data_size[];
+extern char __bss_start[];
+extern char __bss_size[];
+
+void _start(void)
+{
+ memcpy(__data_start, __data_source, (uintptr_t) __data_size);
+ memset(__bss_start, '\0', (uintptr_t) __bss_size);
+
+#if AO_BOOT_CHAIN
+ if (ao_boot_check_chain()) {
+#if AO_BOOT_PIN
+ ao_boot_check_pin();
+#endif
+ }
+#endif
+ /* Turn on syscfg */
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN);
+
+#if RELOCATE_INTERRUPT
+ memcpy(__interrupt_ram, __interrupt_vector, sizeof(__interrupt_ram));
+ stm_syscfg.cfgr1 = (stm_syscfg.cfgr1 & ~(STM_SYSCFG_CFGR1_MEM_MODE_MASK << STM_SYSCFG_CFGR1_MEM_MODE)) |
+ (STM_SYSCFG_CFGR1_MEM_MODE_SRAM << STM_SYSCFG_CFGR1_MEM_MODE);
+#else
+ /* Switch to Main Flash mode (DFU loader leaves us in System mode) */
+ stm_syscfg.cfgr1 = (stm_syscfg.cfgr1 & ~(STM_SYSCFG_CFGR1_MEM_MODE_MASK << STM_SYSCFG_CFGR1_MEM_MODE)) |
+ (STM_SYSCFG_CFGR1_MEM_MODE_MAIN_FLASH << STM_SYSCFG_CFGR1_MEM_MODE);
+#endif
+ main();
+}
#define ao_flash_wait_bsy() do { while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)); } while (0)
-static void __attribute__ ((section(".ramtext"),noinline))
+static void __attribute__ ((section(".sdata2.flash"), noinline))
_ao_flash_erase_page(uint16_t *page)
{
stm_flash.cr |= (1 << STM_FLASH_CR_PER);
#define _ao_flash_addr(pos) ((uint16_t *) (void *) ((uint8_t *) __flash__ + (pos)))
-static void __attribute ((section(".ramtext"), noinline)) _ao_flash_byte(uint32_t pos, uint8_t b)
+static void __attribute__ ((section(".sdata2.flash"), noinline))
+_ao_flash_byte(uint32_t pos, uint8_t b)
{
uint16_t v;
uint16_t *a = _ao_flash_addr(pos & ~1);
ao_flash_wait_bsy();
}
-static void __attribute__ ((section(".ramtext"), noinline))
+static void __attribute__ ((section(".sdata2.flash"), noinline))
_ao_flash_write(uint32_t pos, void *sv, uint16_t len)
{
uint8_t *s = sv;
stm_flash.cr &= ~(1 << STM_FLASH_CR_PG);
}
-static bool
-ao_storage_is_erased(uint32_t pos)
-{
- uint16_t *flash = _ao_flash_addr(pos);
- uint32_t i = ao_storage_block >> 1;
-
- while (i--)
- if (*flash++ != 0xffff)
- return false;
- return true;
-}
-
uint8_t
-ao_storage_erase(uint32_t pos)
+ao_storage_device_erase(uint32_t pos)
{
- if (ao_storage_is_erased(pos))
- return 1;
-
ao_arch_block_interrupts();
ao_flash_unlock();
void
ao_storage_device_info(void)
{
- printf ("Using internal flash, page %d bytes, total %d bytes\n",
- ao_storage_block, ao_storage_total);
+ printf ("Using internal flash, page %ld bytes, total %ld bytes\n",
+ (long) ao_storage_block, (long) ao_storage_total);
}
void
PRODUCT_DEF=-DTELEFIREONE_V_2_0
IDPRODUCT=0x000f
-# Include floating-point enabled printf
-
-NEWLIB_PRINTF_CFLAGS =
-
CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME = telefireone-v2.0
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS) -Wl,-Map=$(PROGNAME)-$(VERSION).map
$(OBJ): $(INC)
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS) -Wl,-Map=$(PROGNAME)-$(VERSION).map
$(OBJ): $(INC)
ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
for (;;) {
- PRINTD("Drag monitor count %d delay %d\n", ao_lco_drag_beep_count, delay);
+ PRINTD("Drag monitor count %d delay %lu\n", ao_lco_drag_beep_count, (unsigned long) delay);
if (delay == (AO_TICK_TYPE) ~0)
ao_sleep(&ao_lco_drag_beep_count);
else
for (;;) {
ao_event_get(&event);
- PRINTD("event type %d unit %d value %d\n",
- event.type, event.unit, event.value);
+ PRINTD("event type %d unit %d value %ld\n",
+ event.type, event.unit, (long) event.value);
switch (event.type) {
case AO_EVENT_QUADRATURE:
switch (event.unit) {
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS) -Wl,-Map=$(PROGNAME)-$(VERSION).map
$(OBJ): $(INC)
PRODUCT_DEF=-DTELESTATIC_V_3_0
IDPRODUCT=0x000f
-# Include floating-point enabled printf
-
-NEWLIB_PRINTF_CFLAGS =
-
CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME = telestatic-v3.0
{ 0, NULL },
};
-void
+int
main(void)
{
ao_clock_init();
ao_flight_test_mm
ao_flight_test_noisy_accel
ao_flight_test_metrum
+ao_flight_test_mini
ao_micropeak_test
ao_aes_test
ao_lisp_test
JLabel aprs_interval_label;
JLabel aprs_ssid_label;
JLabel aprs_format_label;
+ JLabel aprs_offset_label;
JLabel flight_log_max_label;
JLabel callsign_label;
JLabel tracker_motion_label;
JComboBox<String> aprs_interval_value;
JComboBox<Integer> aprs_ssid_value;
JComboBox<String> aprs_format_value;
+ JComboBox<Integer> aprs_offset_value;
JComboBox<String> flight_log_max_value;
JTextField callsign_value;
JComboBox<String> tracker_motion_value;
0, 1, 2 ,3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
+ static Integer[] aprs_offset_values = {
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18
+ };
+
static String[] tracker_motion_values_m = {
"2",
"5",
aprs_format_value.setToolTipText("Hardware doesn't support APRS");
}
+ void set_aprs_offset_tool_tip() {
+ if (aprs_offset_value.isVisible())
+ aprs_offset_value.setToolTipText("Set the APRS offset from top of minute");
+ else if (aprs_offset_value.isVisible())
+ aprs_offset_value.setToolTipText("Software version doesn't support setting the APRS offset");
+ else
+ aprs_offset_value.setToolTipText("Hardware doesn't support APRS");
+ }
+
void set_flight_log_max_tool_tip() {
if (flight_log_max_value.isVisible())
flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)");
set_aprs_format_tool_tip();
row++;
+ /* APRS offset */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = row;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ aprs_offset_label = new JLabel("APRS offset:");
+ pane.add(aprs_offset_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = row;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ aprs_offset_value = new JComboBox<Integer>(aprs_offset_values);
+ aprs_offset_value.setEditable(false);
+ aprs_offset_value.addItemListener(this);
+ aprs_offset_value.setMaximumRowCount(aprs_offset_values.length);
+ pane.add(aprs_offset_value, c);
+ set_aprs_offset_tool_tip();
+ row++;
+
/* Callsign */
c = new GridBagConstraints();
c.gridx = 0; c.gridy = row;
return parse_int("flight log max", flight_log_max_value.getSelectedItem().toString(), true);
}
- public void set_flight_log_max_limit(int new_flight_log_max_limit) {
+ public void set_flight_log_max_limit(int new_flight_log_max_limit, int new_storage_erase_unit) {
flight_log_max_limit = new_flight_log_max_limit;
- flight_log_max_value.removeAllItems();
- for (int i = 8; i >= 1; i--) {
- int size = flight_log_max_limit / i;
- flight_log_max_value.addItem(String.format("%d (%d flights)", size, i));
+ if (new_flight_log_max_limit != AltosLib.MISSING) {
+ flight_log_max_value.removeAllItems();
+ for (int i = 8; i >= 1; i--) {
+ int size = flight_log_max_limit / i;
+ if (new_storage_erase_unit != 0)
+ size &= ~(new_storage_erase_unit - 1);
+ flight_log_max_value.addItem(String.format("%d (%d flights)", size, i));
+ }
}
- if (flight_log_max != 0)
+ if (flight_log_max != 0 && flight_log_max != AltosLib.MISSING)
set_flight_log_max(flight_log_max);
}
return aprs_format_value.getSelectedIndex();
return AltosLib.MISSING;
}
+ public void set_aprs_offset(int new_aprs_offset) {
+ if (new_aprs_offset != AltosLib.MISSING)
+ aprs_offset_value.setSelectedItem(new_aprs_offset);
+ aprs_offset_value.setVisible(new_aprs_offset != AltosLib.MISSING);
+ aprs_offset_label.setVisible(new_aprs_offset != AltosLib.MISSING);
+ set_aprs_offset_tool_tip();
+ }
+
+ public int aprs_offset() throws AltosConfigDataException {
+ if (aprs_offset_value.isVisible()) {
+ Integer i = (Integer) aprs_offset_value.getSelectedItem();
+ return i;
+ }
+ return AltosLib.MISSING;
+ }
}