Merge branch 'branch-1.8' into debian
authorBdale Garbee <bdale@gag.com>
Tue, 12 Dec 2017 04:39:38 +0000 (21:39 -0700)
committerBdale Garbee <bdale@gag.com>
Tue, 12 Dec 2017 04:39:38 +0000 (21:39 -0700)
230 files changed:
ChangeLog
Releasing
altoslib/AltosCSV.java
altoslib/AltosCalData.java
altoslib/AltosDataListener.java
altoslib/AltosEeprom.java
altoslib/AltosEepromDownload.java
altoslib/AltosEepromList.java
altoslib/AltosEepromLog.java
altoslib/AltosEepromMonitor.java
altoslib/AltosEepromRecord.java
altoslib/AltosEepromRecordFull.java
altoslib/AltosEepromRecordMega.java
altoslib/AltosEepromRecordMetrum.java
altoslib/AltosEepromRecordSet.java
altoslib/AltosFile.java
altoslib/AltosFilterListener.java [new file with mode: 0644]
altoslib/AltosFlightListener.java [deleted file]
altoslib/AltosFlightSeries.java
altoslib/AltosFlightStats.java
altoslib/AltosIMU.java
altoslib/AltosIdleMonitor.java
altoslib/AltosKML.java
altoslib/AltosLib.java
altoslib/AltosLink.java
altoslib/AltosReplayReader.java
altoslib/AltosState.java
altoslib/AltosTelemetry.java
altoslib/AltosTelemetryConfiguration.java
altoslib/AltosTelemetryFile.java
altoslib/AltosTelemetryLocation.java
altoslib/AltosTelemetryMegaData.java
altoslib/AltosTelemetryReader.java
altoslib/AltosTelemetrySatellite.java
altoslib/AltosTimeSeries.java
altoslib/Makefile.am
altosui/AltosGraphUI.java
altosui/AltosIdleMonitorUI.java
altosui/AltosUI.java
altosuilib/AltosDisplayThread.java
altosuilib/AltosEepromDelete.java
altosuilib/AltosEepromGrapher.java [new file with mode: 0644]
altosuilib/AltosEepromManage.java
altosuilib/AltosEepromMonitorUI.java
altosuilib/AltosEepromSelect.java
altosuilib/AltosFlightStatsTable.java
altosuilib/AltosGraph.java
altosuilib/AltosInfoTable.java
altosuilib/AltosShapeListener.java [new file with mode: 0644]
altosuilib/AltosUIAxis.java
altosuilib/AltosUIEnable.java
altosuilib/AltosUIFlightSeries.java
altosuilib/AltosUIGraph.java
altosuilib/AltosUILineStyle.java [new file with mode: 0644]
altosuilib/AltosUITimeSeries.java
altosuilib/Makefile.am
ao-bringup/test-telemega
ao-bringup/test-telemega-v2.0 [new file with mode: 0755]
ao-bringup/turnon_telebt
ao-bringup/turnon_telegps
ao-bringup/turnon_telemega
ao-bringup/turnon_telemega_v2.0 [new file with mode: 0755]
configure.ac
doc/Makefile
doc/altosui.inc
doc/altusmetrum-docinfo.xml
doc/easymini-release-notes.inc
doc/graph-configure.png
doc/graph-map.png
doc/graph-stats.png
doc/graph.png
doc/release-notes-1.6.3-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.6.4-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.6.5-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.6.8-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.7-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.8-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.8.1-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.8.2-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.8.3-docinfo.xml [new file with mode: 0644]
doc/release-notes-1.8.3.inc [new file with mode: 0644]
doc/release-notes.inc
doc/telegps-docinfo.xml
doc/telegps-release-notes.inc
micropeak/MicroPeak.java
src/Makefile
src/cc1111/Makefile.cc1111
src/cc1111/ao_arch.h
src/cc1111/ao_pins.h
src/cortexelf-v1/.gitignore [new file with mode: 0644]
src/cortexelf-v1/Makefile
src/cortexelf-v1/ao_cortexelf.c
src/cortexelf-v1/ao_lisp_os.h [deleted file]
src/cortexelf-v1/ao_lisp_os_save.c [deleted file]
src/cortexelf-v1/ao_pins.h
src/cortexelf-v1/ao_scheme_os.h [new file with mode: 0644]
src/cortexelf-v1/ao_scheme_os_save.c [new file with mode: 0644]
src/drivers/ao_mpu9250.c [new file with mode: 0644]
src/drivers/ao_mpu9250.h [new file with mode: 0644]
src/easymega-v1.0/ao_pins.h
src/kernel/ao.h
src/kernel/ao_cmd.c
src/kernel/ao_data.h
src/kernel/ao_flight.c
src/kernel/ao_gps_report.c
src/kernel/ao_gps_report_mega.c
src/kernel/ao_gps_report_metrum.c
src/kernel/ao_host.h
src/kernel/ao_log.c
src/kernel/ao_log.h
src/kernel/ao_log_big.c
src/kernel/ao_log_gps.c
src/kernel/ao_log_mega.c
src/kernel/ao_log_metrum.c
src/kernel/ao_log_mini.c
src/kernel/ao_log_tiny.c
src/kernel/ao_pyro.c
src/kernel/ao_pyro.h
src/kernel/ao_sample.c
src/kernel/ao_stdio.c
src/kernel/ao_storage.c
src/kernel/ao_task.h
src/kernel/ao_telemetry.c
src/lambdakey-v1.0/Makefile
src/lambdakey-v1.0/ao_lambdakey.c
src/lambdakey-v1.0/ao_lisp_os.h [deleted file]
src/lambdakey-v1.0/ao_lisp_os_save.c [deleted file]
src/lambdakey-v1.0/ao_scheme_os.h [new file with mode: 0644]
src/lambdakey-v1.0/ao_scheme_os_save.c [new file with mode: 0644]
src/lisp/.gitignore [deleted file]
src/lisp/Makefile [deleted file]
src/lisp/Makefile-inc [deleted file]
src/lisp/Makefile-lisp [deleted file]
src/lisp/ao_lisp.h [deleted file]
src/lisp/ao_lisp_atom.c [deleted file]
src/lisp/ao_lisp_builtin.c [deleted file]
src/lisp/ao_lisp_cons.c [deleted file]
src/lisp/ao_lisp_const.lisp [deleted file]
src/lisp/ao_lisp_error.c [deleted file]
src/lisp/ao_lisp_eval.c [deleted file]
src/lisp/ao_lisp_frame.c [deleted file]
src/lisp/ao_lisp_int.c [deleted file]
src/lisp/ao_lisp_lambda.c [deleted file]
src/lisp/ao_lisp_lex.c [deleted file]
src/lisp/ao_lisp_make_const.c [deleted file]
src/lisp/ao_lisp_mem.c [deleted file]
src/lisp/ao_lisp_os.h [deleted file]
src/lisp/ao_lisp_poly.c [deleted file]
src/lisp/ao_lisp_read.c [deleted file]
src/lisp/ao_lisp_read.h [deleted file]
src/lisp/ao_lisp_rep.c [deleted file]
src/lisp/ao_lisp_save.c [deleted file]
src/lisp/ao_lisp_stack.c [deleted file]
src/lisp/ao_lisp_string.c [deleted file]
src/math/kf_rem_pio2.c
src/math/sf_cos.c
src/scheme/.gitignore [new file with mode: 0644]
src/scheme/Makefile [new file with mode: 0644]
src/scheme/Makefile-inc [new file with mode: 0644]
src/scheme/Makefile-scheme [new file with mode: 0644]
src/scheme/README [new file with mode: 0644]
src/scheme/ao_scheme.h [new file with mode: 0644]
src/scheme/ao_scheme_atom.c [new file with mode: 0644]
src/scheme/ao_scheme_bool.c [new file with mode: 0644]
src/scheme/ao_scheme_builtin.c [new file with mode: 0644]
src/scheme/ao_scheme_builtin.txt [new file with mode: 0644]
src/scheme/ao_scheme_cons.c [new file with mode: 0644]
src/scheme/ao_scheme_const.scheme [new file with mode: 0644]
src/scheme/ao_scheme_error.c [new file with mode: 0644]
src/scheme/ao_scheme_eval.c [new file with mode: 0644]
src/scheme/ao_scheme_float.c [new file with mode: 0644]
src/scheme/ao_scheme_frame.c [new file with mode: 0644]
src/scheme/ao_scheme_int.c [new file with mode: 0644]
src/scheme/ao_scheme_lambda.c [new file with mode: 0644]
src/scheme/ao_scheme_lex.c [new file with mode: 0644]
src/scheme/ao_scheme_make_builtin [new file with mode: 0644]
src/scheme/ao_scheme_make_const.c [new file with mode: 0644]
src/scheme/ao_scheme_mem.c [new file with mode: 0644]
src/scheme/ao_scheme_poly.c [new file with mode: 0644]
src/scheme/ao_scheme_read.c [new file with mode: 0644]
src/scheme/ao_scheme_read.h [new file with mode: 0644]
src/scheme/ao_scheme_rep.c [new file with mode: 0644]
src/scheme/ao_scheme_save.c [new file with mode: 0644]
src/scheme/ao_scheme_stack.c [new file with mode: 0644]
src/scheme/ao_scheme_string.c [new file with mode: 0644]
src/scheme/make-const/.gitignore [new file with mode: 0644]
src/scheme/make-const/Makefile [new file with mode: 0644]
src/scheme/make-const/ao_scheme_os.h [new file with mode: 0644]
src/scheme/test/.gitignore [new file with mode: 0644]
src/scheme/test/Makefile [new file with mode: 0644]
src/scheme/test/ao_scheme_os.h [new file with mode: 0644]
src/scheme/test/ao_scheme_test.c [new file with mode: 0644]
src/scheme/test/hanoi.scheme [new file with mode: 0644]
src/stm-scheme-newlib/.gitignore [new file with mode: 0644]
src/stm-scheme-newlib/Makefile [new file with mode: 0644]
src/stm-scheme-newlib/ao_demo.c [new file with mode: 0644]
src/stm-scheme-newlib/ao_pins.h [new file with mode: 0644]
src/stm-scheme-newlib/ao_scheme_os.h [new file with mode: 0644]
src/stm-scheme-newlib/ao_scheme_os_save.c [new file with mode: 0644]
src/stm-scheme-newlib/flash-loader/Makefile [new file with mode: 0644]
src/stm-scheme-newlib/flash-loader/ao_pins.h [new file with mode: 0644]
src/stm/Makefile.defs
src/stm/ao_adc_stm.c
src/stm/ao_exti.h
src/stm/ao_serial_stm.c
src/stmf0/Makefile-stmf0.defs
src/teleballoon-v2.0/ao_pins.h
src/telegps-v0.3/ao_pins.h
src/telegps-v1.0/ao_pins.h
src/telegps-v2.0/ao_pins.h
src/telemega-v0.1/ao_pins.h
src/telemega-v1.0/ao_pins.h
src/telemega-v2.0/ao_pins.h
src/telemega-v3.0/.gitignore [new file with mode: 0644]
src/telemega-v3.0/Makefile [new file with mode: 0644]
src/telemega-v3.0/ao_pins.h [new file with mode: 0644]
src/telemega-v3.0/ao_telemega.c [new file with mode: 0644]
src/telemega-v3.0/flash-loader/Makefile [new file with mode: 0644]
src/telemega-v3.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/telemetrum-v2.0/ao_pins.h
src/telemetrum-v3.0/ao_pins.h
src/telescience-v0.2/ao_pins.h
src/teleterra-v0.2/ao_pins.h
src/test/Makefile
src/test/ao_flight_test.c
src/test/ao_lisp_os.h [deleted file]
src/test/ao_lisp_test.c [deleted file]
src/test/hanoi.lisp [deleted file]
telegps/TeleGPS.java
telegps/TeleGPSGraphUI.java

index 9c73f88d6ea572ba53fbee2d0ccfa20d7b0e2d62..d6379754ab941e6cf643bd06584776422ce43a76 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+commit ea0aa97fb93e669868a6f2c49c5d4b46e7615b1f
+Merge: 216ea638 9adf8b23
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Dec 11 21:37:48 2017 -0700
+
+    Merge branch 'master' into branch-1.8
+
+commit 9adf8b23aac8256f230b10adcab9dd323266caaa
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Dec 11 21:33:21 2017 -0700
+
+    TeleMega default is now v3.0
+
+commit b4d78ad85e8f5b1bee78746d63bb4b069e087e5a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 11 16:30:46 2017 -0800
+
+    doc: Update release notes and docinfo for 1.8.3
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2efb997865ee46bf0e8d5145c95d051a7656222a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 11 14:42:45 2017 -0800
+
+    altoslib: Keep old GPS values when updating data
+    
+    This way, updating satellite information doesn't drop all of the
+    regular GPS data on the floor.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fa3ff3a089e4af88dd0cc9a9e92511a0ba4a8e0f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 11 14:08:32 2017 -0800
+
+    altos: Actually store current MPU9250 data in data ring
+    
+    The ring is updated when the ADC finishes; all of the other sensor
+    data needs to be copied in at that point.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 962df1f8c7f7ffbebe9b32d6ac363b333af606b3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 11 13:47:54 2017 -0800
+
+    altos: Remove more software for hardware prototypes
+    
+    These never saw the light of day.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 05efe58cb13b58292527668ca51639eaebe1112b
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Dec 11 14:44:15 2017 -0700
+
+    take telescience out of the routine builds
+
+commit 713e8ca6b6cfb29555d8d847e0bb2652cfe011ae
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 11 12:23:29 2017 -0800
+
+    Bump to version 1.8.3
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 992797db2158b23d46c496e5e223deeca28bf4c9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 11 12:23:00 2017 -0800
+
+    doc: Note TeleMega v3.0 support in 1.8.3 relnotes
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8d65e7b367712075a42d26c6d4bbff474dc1ae14
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 5 12:22:34 2017 -0800
+
+    altos/drivers: Hook up mag sensor for MPU9250
+    
+    Set mag sensor to provide data at 100Hz.
+    Set i2c master to pull mag data at sample rate (200Hz).
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ec638405045d33d48476ab85edf09a2e1756e3e3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 18:35:53 2017 -0800
+
+    altos/scheme: Allow ao_scheme_read_eval_print to be restarted
+    
+    Reset exceptions at the top so that we can call it more than once.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8ebecd364fd328e9c649c11729bddf58731aaafb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 18:34:49 2017 -0800
+
+    altos: Allow building with newlib + avr stdio on ARM
+    
+    Redefines some stdio bits so that we can build with either pdclib or
+    newlib + avr stdio.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b0de72d942eb87c5acd190878dd57ca4f812e8a1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 18:32:18 2017 -0800
+
+    altos: Add scheme for stm discovery board demo
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 655576011e9cc648c7c4bbf51179744a427ff237
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 18:21:01 2017 -0800
+
+    altos/lambdakey-v1.0: Switch to newlib, get things compiling again
+    
+    scheme is now way too large to fit on this device; some subsetting is
+    clearly indicated.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7d77071f5b45632937f262600ca95c7b71f4d3da
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 16:55:57 2017 -0800
+
+    altos/scheme: Add Makefile for scheme test app
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dd2ed58fcdffaff7b5a9ef898affa3e1ec01ef44
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 16:54:50 2017 -0800
+
+    altos/scheme: Make test scheme app heap maximum size
+    
+    It's only 32kB.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3e7a703bb2e70a0568b44159b993386f7ec46e04
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 16:53:25 2017 -0800
+
+    altos/scheme: Make eqv? work for numbers and strings
+    
+    Large numbers, floats and strings need a value check, not just a
+    comparison between ao_polys
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bdafb4dfad89d92efec37ed826d5f22e9167e717
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 16:52:26 2017 -0800
+
+    altos/scheme: Stash cons across value allocation in compare
+    
+    Large ints, strings and floats can cause allocation, requiring that
+    the 'cons' pointer be stashed and retrieved in case it moved.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b72638e60b6636b479b79bbf0047cf7409f58820
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 16:51:25 2017 -0800
+
+    altos/scheme: add list-copy
+    
+    A lot easier as a built-in; the obvious scheme version is recursive.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7517da1646fc30faaa9ee1c969cfa35ae1a17423
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 16:50:06 2017 -0800
+
+    altos/scheme: Use 64-bit ints to track memory allocation stats
+    
+    These are only collected for debug purposes, but can get quite large
+    if the interpreter runs for a while.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7e14e243565e814ddd524c8d09454719dc89c6d8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 13:13:27 2017 -0800
+
+    altos/scheme: Add a bunch of string and vector builtins
+    
+    Just make the language closer to r7rs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6d14f809b54b99725447a934047167c2e7febe82
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Dec 11 10:17:40 2017 -0700
+
+    TeleMega v3.0 turnon scripts
+
+commit d1d98e408311c5ba18138a18f4c88448e4254626
+Merge: 2f8fce1c abb856cd
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Dec 11 10:16:24 2017 -0700
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit abb856cd66e00d739e4efb1930b5c168eaf48029
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 00:02:34 2017 -0800
+
+    altos/scheme: Avoid crashing with non-list in length
+    
+    Use ao_scheme_cons_cdr to fetch the next list element as that returns
+    NULL for non-cons elements.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 17fe6de833cccb6d43d0ac0ed84a4faaa3463a09
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 00:02:00 2017 -0800
+
+    altos/scheme: Add vectors
+    
+    Constant time and smaller can be a feature.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0d3365e2c04793cd8432c30a66881f53385a2e60
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 10 00:00:23 2017 -0800
+
+    altos/scheme: Fix name of constant scheme file
+    
+    .lisp -> .scheme
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 111622dbcd56c225a9d5ace9f0ef745e62f8a94c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 9 16:57:35 2017 -0800
+
+    altoslib: Fix 8 to 12 bit conversion for Mega pyro voltage data
+    
+    The conversion was losing the replicated top four bits by shifting by
+    the wrong amount.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1133130986a78628ea297ce1f6a023baf4382d8f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 9 16:56:20 2017 -0800
+
+    altos/scheme: Let readline know if there's a list in progress
+    
+    This lets the interactive prompt change based on what state the lexer
+    is in
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2f8fce1cf6ce4bd12a836cc8ee15f4edbc95c95e
+Merge: d314a565 185b1136
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Dec 5 13:23:09 2017 -0700
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 185b11367cd85948885fceafb5d46303b6f1356d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 5 12:22:34 2017 -0800
+
+    altos/drivers: Start adding defines to get mag data out of MPU9250
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d314a5654fafa5eac86d8293f1197a2f2c2eac72
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Dec 5 13:18:45 2017 -0700
+
+    moving to TeleMega v3.0 by default
+
+commit 1bf219209c8d9e31a9c3726dad169ff5d17ed4b2
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Dec 5 13:17:18 2017 -0700
+
+    handle repeated invocations without failing as often
+
+commit 2aa02234b1ac2b1701b44fcec9e9bd82bea526b7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 5 10:48:04 2017 -0800
+
+    altos/cortexelf-v1: Adapt to lisp->scheme name change
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 038581bd212e66bcf017c7ace28c80a3ae0d0f50
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 5 10:42:02 2017 -0800
+
+    altos/scheme: Add explicit dependency on ao_scheme_builtin.h for ao_scheme_make_const
+    
+    This ensures that a parallel build will wait for ao_scheme_builtin.h
+    to be complete before attempting to compile ao_scheme_make_const
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bd7a19a86f6d4fe19c7e72904e9b8ac0f2081ff7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 5 10:38:14 2017 -0800
+
+    altos/scheme: Move scheme test program to scheme sub-directory
+    
+    Keeps it away from the usual test setup
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 195cbeec19a6a44f309a9040d727d37fe4e2ec97
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 5 10:29:13 2017 -0800
+
+    altos/scheme: Rename to 'scheme', clean up build
+    
+    Constant block is now built in a subdir to avoid messing up source
+    directory.
+    
+    Renamed to ao_scheme to reflect language target.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9dbc686ad7d3289dc0f9bcf4a973f71100e02ded
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 3 19:54:18 2017 -0800
+
+    altos/lisp: Switch to scheme formal syntax for varargs
+    
+    Scheme uses bare symbols to indicate a varargs parameter; any bare
+    (i.e., not wrapped in a cons cell) parameter will get the 'rest' of
+    the parameter list. This works for lambdas, nlambdas and macros. As a
+    result, the 'lexpr' form has been removed as it is equivalent to a
+    lambda with a varargs formal.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a1d013ab8cc508d4e17ae8876bc5465d1a2dfc1e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 3 19:52:11 2017 -0800
+
+    altos/lisp: Fix stash usage across frame allocation
+    
+    Must un-stash before allocation failure check.
+    Use frame_stash instead of poly_stash for frames.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 32ab76c3049b913283caafbaef873754d76dc9d4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 3 19:49:20 2017 -0800
+
+    altos/lisp: Check only cdr base type when moving cons cells
+    
+    The cdr may have moved, so we can't look at the target object
+    type. Fortunately, the base type encoded in the reference itself is
+    sufficient to check for a non-cons cdr.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ed6967cef5d82baacafe1c23229f44d58c838326
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 3 19:47:03 2017 -0800
+
+    altos/lisp: Split out read debug, add memory validation
+    
+    Split read debug into a separate #define to reduce debug noise
+    Add some memory validation -- validate stash API, and validate
+    cons_free calls.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b9009b3916956db00b7b78bd06fb0df704690eb1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 2 23:21:55 2017 -0600
+
+    altos/lisp: use strtof instead of atof
+    
+    atof returns double, strtof returns float.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 880c35363a2596202c8a3d980bf4ac41eceead66
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 2 23:21:01 2017 -0600
+
+    altos/lisp: Convert more builtin lisp code to scheme format
+    
+    Use defines where possible, use (define (name args ...)) form for lambdas
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 577911241db454bc3129fc47566c6a55752c4182
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 2 23:19:44 2017 -0600
+
+    altos/lisp: Overflow int computations to float
+    
+    When an int computation overflows, switch to float.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b986a12b478a6d4ff550786d24aa8628dc0abe32
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 2 15:59:17 2017 -0600
+
+    altoslib: Add support for TeleMega v3.0 log files
+    
+    These look much like TeleMega v2.0 log files, except that the mag
+    sensor data now comes from the mpu9250 instead of an external
+    hmc5883. The gyro and 3-axis accel data from the mpu9250 are the same
+    as the mpu6000.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8c19778d8b56aafa048ddf9654c40b32bd8c64b0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 2 15:53:05 2017 -0600
+
+    altos: Build TeleMega v3.0 by default
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ecc075596d6cd2b9c0a3107036d5368ebc3a77bd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 2 15:31:06 2017 -0600
+
+    altos: Add TeleMega v3.0
+    
+    Adds files to build telemega v3.0 flash loader and firmware
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f0068719b17019c5cd7ed318364a0581caf64e1a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 2 15:32:38 2017 -0600
+
+    altos/kernel: MPU9250 support
+    
+    Use MPU9250 for accel, gyro and mag data in logging, telemetry and
+    flight status computations.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c31744299e5a4342bbe26d3735ee2d8f09192ae9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Dec 1 15:40:23 2017 -0600
+
+    altos/lisp: split set/def. Add def support to lambdas
+    
+    In scheme, set can only re-define existing variables while def cannot
+    redefine existing variables in lambda context. Def within lambda
+    creates a new variable at the nearest enclosing scope.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 98923ae1189f062b8b94120d47a56892db25493f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Dec 1 18:28:16 2017 +0100
+
+    altos/lisp: Split out frame vals from frame struct
+    
+    This lets the frame be resized without moving the base structure. The
+    plan is to allow all frames to be resized, not just the global frame.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 835bf4131f9e20575bfdf2179462ebdf54a14761
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Dec 1 12:06:04 2017 +0100
+
+    altos/lisp: Make let distinct from let*
+    
+    let is supposed to define the values all at once, evaluating the
+    initializers in the enclosing context. let* defines the new names and
+    then initializes them one at a time.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5d0b85f25fa1e5cc816a8256afb38cf9552f6d9d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Dec 1 11:32:27 2017 +0100
+
+    altos/lisp: return from unmatched cond is #f, not nil
+    
+    Fix the return value when we fall off the end of a cond expression to
+    be #f
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 796017262cd433af5d143cc7168c944e1e05f4e2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Dec 1 11:31:29 2017 +0100
+
+    altos/lisp: Fix pairp builtin
+    
+    Pairs are non-nil cons values; add an explicit check for nil here
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cd0bd9791a77868c226d285bf4d57e8c321755d5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Dec 1 10:12:38 2017 +0100
+
+    altos/lisp: Add quasiquote
+    
+    This adds read support for quasiquote syntax, and then adds a
+    quasiquote implementation in lisp
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 00bf2ca86b60e6501880011897cea073865c5a03
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 25 17:29:10 2017 -0800
+
+    altos/lisp: Rename progn to begin
+    
+    Match scheme name.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5f9f97cc2d43936d1941da3a9a130c279bc70b99
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 19 21:07:23 2017 -0800
+
+    altos/test: Update to build altos lisp test app
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6d2f271a45759bd792d299f04a424d3382ef4798
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 19 21:07:00 2017 -0800
+
+    altos/lisp: Add floats
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 12a1f6ad48f2b924f71239effeb90afca75a090f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 18 22:00:44 2017 -0800
+
+    altos/lisp: Fix some scheme compat issues
+    
+    flush -> flush-output
+    nth -> list-ref (oh, and add list-tail)
+    add let* (same as let for now)
+    write control chars in octal
+    make hanoi example work
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5f8f0ed5cd5d4b4f793c602ed09f9b4bdb98f7e8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 18 20:38:15 2017 -0800
+
+    altos/lisp: Add 'big' ints -- 24 bits wide
+    
+    With the default ints being only 14 bits, having a larger type with
+    more precision seems useful. This is not exposed to the application.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e745229311366a792110d78d8480a2bf83eef9a0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 17 23:28:08 2017 -0800
+
+    altos/cortexelf-v1: Make lisp compile again
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 65fb0ad8693407cc9bd114424c1f51b6aa6befc3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 17 23:27:36 2017 -0800
+
+    altos/test: Add jiffy funcs to lisp test
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cf5729a0bae51172f12fc9ec4339d4e975a45fcc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 17 23:23:50 2017 -0800
+
+    altos/lisp: Finish first pass through r7rs
+    
+    * print -> write, patom -> display
+    * Add read-char, write-char
+    * Add exit, current-jiffy, current-second, jiffies-per-second
+    * Add for-each and string-for-each
+    * Avoid duplicate builtins with different atoms
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e1acf5eb12aceda7aa838df031c1da1129d0fa5d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 17 22:14:19 2017 -0800
+
+    altos/lisp: Add apply
+    
+    And all of the library routines that use it, map, string-map and friends.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a4e18a13029cc7b16b2ed9da84d6e606bc725ac3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 17 08:50:50 2017 -0800
+
+    altos/lisp: Character consts. String and assoc builtins.
+    
+    Also add back escaped characters in strings.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5b6f4b5de89a2bb0d63442e2651cf8d2ee0f4b10
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 17 08:04:28 2017 -0800
+
+    altos/lisp: Generate built-in lambda atoms for const creation
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cd9152973f29f4e775569f5acbbe8fab2d93d170
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 16 22:15:06 2017 -0800
+
+    altos/test: More lisp test Makefile fixes
+    
+    Depend on ao_lisp_const.h
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 435a91ae3889cd361b543f4555a78488905e0bbb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 16 22:13:46 2017 -0800
+
+    altos/lisp: Lots more scheme bits
+    
+    * Arithmetic functions and tests
+    * append, reverse and list-tail
+    * set-car! and set-cdr!
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cc76030d669600051fbb42a8cf85701aaaf5f5b7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 16 18:47:34 2017 -0800
+
+    altos/test: Get lisp test building using Makefile-inc
+    
+    Instead of re-defining all of the lisp sources and headers
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2e58b6c380bc6440490c47650fbf11d45b3f2e72
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 16 18:46:03 2017 -0800
+
+    altos/lisp: More schemisms
+    
+    Add 'if'.
+    setq -> set!, but doesn't define new variables
+    def -> define
+    Add pair? and list?
+    Add eq? and eqv? as aliases for =
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0ced351c8f4449f7086b04e42c822d649f040d1f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 16 18:41:18 2017 -0800
+
+    altos/lisp: Add 'else' sematics to cond
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b3b4731fcb89cb404433f37a7704a503567c43bd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 16 17:49:47 2017 -0800
+
+    altos/lisp: Add scheme-style bools (#t and #f)
+    
+    Cond and while compare against #f, just like scheme says to.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bd881a5b85d7cd4fb82127f92f32e089499b50cb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 16 13:02:07 2017 -0800
+
+    altos/lisp: Add non-cons cdr support
+    
+    The cdr of a cons can be any value; add support for lexing and
+    printing them.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 50a095fbe828b6ec3159d27930712df6b1b519b4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 21:29:11 2017 -0800
+
+    doc: Update for 1.8.3
+    
+    Also added a pile of docinfo files for older release notes files.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 23cf8fb4d5745ad76d9517c9702d03d10c58144a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 20:52:01 2017 -0800
+
+    altos: Fix new GCC warnings
+    
+    * Duplicate 'const' in test code.
+    * Mis-formatted loop in kf_rem_pio2
+    * Unused 'one' in sf_cos
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f3b279141cd30ad6a212ce75f5a7c2b8e3d33870
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 20:50:45 2017 -0800
+
+    altos: Fix inverted test for corrupt flight log
+    
+    Was reporting correct flight log as corrupted. Oops.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9a7b4f02ad32ca43a45ed9fe446b8db96e60b5e5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 20:49:20 2017 -0800
+
+    altoslib: Improve EEprom download
+    
+    * Catch and report CRC errors
+    * Deal with corrupted flight records
+    * Add ability to immediately graph new data
+    * Check before overwriting existing files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 10834eb60f7a44fee159d9e9ad5ffb2e013fe9cf
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 20:46:45 2017 -0800
+
+    altoslib: Remove spurious semicolon in AltosReplayReader.java
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e80005ea63bb9b1eee33a8876ad74ed5d50478ed
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 20:44:27 2017 -0800
+
+    altoslib: Don't write KML record when height data is missing
+    
+    This avoids a crash dealing with corrupted flight data
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a2097545dec62cd0970725bf690128dad6baf22e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 16:38:40 2017 -0800
+
+    altos/test: Adapt flight test to int16_t flight number type
+    
+    Flight numbers are now limited to 32767 to allow for negative values
+    for corrupted slots.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5b6805d1a6a91a26a1892f414a99f0184871ac1a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 11 16:08:32 2017 -0800
+
+    altosuilib: New line styles and colors for graphs. Selectable line width
+    
+    Improve the readability of graphs by offering a better selection of
+    colors and adding line styles. Let the user configure the line width
+    as desired.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82e552d194216b41d27d805bee2947127c2d555b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 2 09:12:18 2017 -0700
+
+    altos/stm: Add AO_EXTI_MODE_PULL_NONE
+    
+    This is clearer than using '0'.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5460d7ff46116901bceacd43282b406c446dded5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 2 09:11:39 2017 -0700
+
+    altos: whitespace cleanup in ao_adc_stm.c
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 83929cd290279963b01b2ccd52c70d61bdeff6b0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 22 15:44:32 2017 -0500
+
+    altos: Share common logging code. Deal with corrupt initial flight records
+    
+    Move common logging APIs from per-format files into ao_log.c. Then,
+    change that code to check the first log record in a slot (containing
+    the flight number) to see if it's invalid and deal with it. That
+    involves not re-using that slot, and allowing it to be erased.
+    
+    Corrupted log blocks are reported with a negative flight number.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 256ddea8c430b4b5dcb8bb95c19ad26032129e1b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 22 15:43:07 2017 -0500
+
+    altos: Define AO_LOG_FORMAT in */ao_pins.h. Use in ao_cmd.c
+    
+    Instead of having a global variable define the log format, use a macro
+    instead to save data space.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 15af16ad21f67019065763a93d52cea6097a69d1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 22 15:39:25 2017 -0500
+
+    altos: Remove cross-block storage I/O on cc1111
+    
+    We don't ever need to be able to do storage read/write across chunks
+    of flash on the old cc1111 products, so remove the loops that support
+    it to save space.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 749400fd244eba38806c623d2a35722642230698
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 22 14:04:09 2017 -0500
+
+    altoslib: Move temp GPS API from cal_data to data_listener
+    
+    This makes the API more consistent, and means that the listener is
+    responsible for mangaing the temp gps state. In particular, the
+    AltosDataListener set_gps API now calls the cal_data function.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e98235e314ac764509af26c93da9e6d1de8184ea
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Oct 14 12:18:26 2017 -0700
+
+    altoslib: Save separate config for local and remote. Use in idle
+    
+    When using the remote link, there are two separate configuration data
+    blocks, that for the local device and for remote. Make the link report
+    both versions, depending on whether it is in remote mode or not.
+    
+    Request config data in remote mode when running idle monitoring so
+    that the presented data is for the remote device, not the local one.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 964a14568b73296194f84c728cc7e01d6f0e2f64
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Oct 14 12:05:07 2017 -0700
+
+    altoslib: Report un-adjusted ground accel in idle IMU monitor
+    
+    The ground accel is the basis of the accel adjustment, so it needs to
+    be delivered in un-adjusted form.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4431f70044f4e1120d606f0ded1845349295d68e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 12 00:31:26 2017 -0700
+
+    altos: Add MPU9250 support to self test and data
+    
+    The remaining hooks to make the MPU9250 work in flight.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77d1aee917306ad59492c4c8352fe2125b430d0c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 12 00:30:23 2017 -0700
+
+    altoslib: Fix time series filter window computation
+    
+    Small floating point rounding errors could lead to NaNs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e04679ba52761d5531037117a21ab1f1896358b0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 12 00:29:07 2017 -0700
+
+    altoslib: Don't crash if there's no GPS coord to write KML
+    
+    Just check for null before writing as a precaution.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a69d5773a63dbe5d6d758cea8eca2bf724e9d672
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 12 00:26:31 2017 -0700
+
+    altoslib: Allow gps time later than requested if it's first
+    
+    When generating a KML file, we want to position markers near the start
+    of the flight section. This is done by looking for a GPS coordinate
+    'before' the starting point of the flight, which doesn't work well
+    when the first GPS coordinate is later than that. Pick the first point
+    after the chosen time if there isn't an earlier one.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d7bb706918fd7d6db77eab21931b4fc74cb9105
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 12 00:14:30 2017 -0700
+
+    altos: Add MPU9250 driver (accel/gyro only for now)
+    
+    This is almost an exact copy of the MPU6000 driver, just a few minor
+    register changes.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c8dbfff65dd61e42d0a02158dcb520e7710ef87e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 8 18:50:59 2017 -0700
+
+    altos: Stop storing pyro fired status in config block
+    
+    We already have the fired status saved in the ao_pyro_fired variable,
+    so just use that to detect whether a channel has already been fired.
+    
+    Fixes possible cases where the pyro config data gets written back to
+    eeprom with the fired bit set, which then inhibits the channel during
+    flight.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5d82209122e3b797a7345f6ad5b6710832fcdd4a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 5 16:46:08 2017 -0700
+
+    Set version to 1.8.2.1
+    
+    Testing KML export changes at TRA
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7e971b45f22aa77421061ff2925e0458835014b2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Oct 4 13:44:31 2017 -0700
+
+    altoslib: Missing file for filter additions.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2f779d318753b73463f7166977453ab5533e5921
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Oct 4 13:43:45 2017 -0700
+
+    altosuilib: Add 'show marker' button to graphs
+    
+    Provides a marker at each actual data point which can be useful for
+    sparse data sets like telemetry with poor reception.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 730ee7bf91f607ece42c010a10c53d0013492b96
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Oct 4 13:42:16 2017 -0700
+
+    altoslib: Adapt KML output to make TRA record people happier
+    
+    Provide two paths, one using GPS data the other baro. Replace separate
+    path segments for each state with markers so that the path is a single
+    unit, able to be displayed in the elevation profile widget.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 98dc29a7a964f8d653b73989c6751695d168844c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 2 19:33:37 2017 -0700
+
+    altoslib: Add user-selectable filter width for data smoothing
+    
+    Also switch smoothing window to Kaiser and change default accel filter
+    width to 1 second instead of 4 seconds.
+    
+    Now users can play with the filter and see what it does.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d75e8b9046295051c91696461e8d5f59c8260ccc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 2 17:02:18 2017 -0700
+
+    altosuilib: Show raw tick values in graph and info table
+    
+    Not terribly useful, but did help validate firmware handling of tick
+    wrapping, so we'll keep it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c6be13e8ef80e5afc836e04cbfe4cb17631540e4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 2 16:58:53 2017 -0700
+
+    altoslib: Allow early bail-out on bad telemetry CRC
+    
+    Check the CRC status in the packet before creating a new telemetry
+    object.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 770998be2c15dd41a63520d0c8747d7cf32ec447
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 2 16:57:15 2017 -0700
+
+    altos: Allow pyro config name to end with newline, not just space/tab
+    
+    A pyro config like 'Descending' has no value associated. When it is at
+    the end of the line, allow a newline to terminate the name instead of
+    just a space.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit de2b6ec1cdfd48c948bff7edbfe2540440429b1b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 2 16:55:18 2017 -0700
+
+    altoslib,altosuilib,altosui: log_format/device_type TeleGPS selects stateless
+    
+    When the device being analyzed has no flight state, we want to use the
+    'stateless' state so that the UI can display reasonable
+    information. This bit was lost in the recent AltosState shuffle and
+    this patch brings it back.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 322c1abead39cb398380dff384cd274c19dd81dd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 2 13:55:57 2017 -0700
+
+    altosuilib: Don't drain voice when terminating display
+    
+    If the voice thread is wedged (as with PulseAudio and un-patched
+    freetts 1.2.2), we'll get stuck here and the UI will freeze up.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cfc09e8f1f263595972cbb6af23f22e2d749c744
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 26 18:00:36 2017 -0700
+
+    altoslib: Add tilt and pyro data to CSV export
+    
+    It's now version 6. Also removed duplicate time values and made radio
+    values conditional on having radio data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit df39a30c762d57c7d04110e054f74d50fa8d85de
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Sep 19 11:56:52 2017 -0600
+
+    don't exit on dfu-util errors, it's not reliable about reporting success
+
+commit 8124109e0b455c9d8d583f4d985b93d23d7b1350
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Sep 18 21:24:52 2017 -0600
+
+    tweak Releasing based on 1.8.2 release experience
+
+commit 216ea6388a75c46891dc4687a2eb0c97dc63b136
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Sep 18 20:46:04 2017 -0600
+
+    releasing 1.8.2
+
+commit 60666630789b6925d7e16160ebdc88ccd23f51de
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Sep 18 20:43:14 2017 -0600
+
+    be more aggressive about removing and ignoring .mdwn files
+
 commit 1ece6e6fd3faaae3f6c6d434497eb04235939dc3
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Sep 18 20:43:14 2017 -0600
index 8af50a1e7b385637261c86a40baf3d010284698c..b8f8b75f54613c552dd348c26a656685fd0aecf8 100644 (file)
--- a/Releasing
+++ b/Releasing
@@ -126,6 +126,7 @@ These are Bdale's notes on how to do a release.
           src/telemini-v3.0/flash-loader/{*.elf,*.bin} \
           ~/altusmetrumllc/Binaries/loaders/
        (cd ~/altusmetrumllc ; git add Binaries ; git commit -a) 
+       - remove previous versions (only keep latest release)
        (cd ~/altusmetrumllc ; git push) 
 
        - Push new release to web site
index f55b47852a47a895e8fa829346a9594b5a17a6a9..a8de23f0cc828132bf4ce008dc38841dbe94350c 100644 (file)
@@ -29,9 +29,11 @@ public class AltosCSV implements AltosWriter {
        int                     boost_tick;
 
        boolean                 has_basic;
+       boolean                 has_radio;
        boolean                 has_battery;
        boolean                 has_flight_state;
        boolean                 has_advanced;
+       boolean                 has_igniter;
        boolean                 has_gps;
        boolean                 has_gps_sat;
        boolean                 has_companion;
@@ -39,7 +41,7 @@ public class AltosCSV implements AltosWriter {
        AltosFlightSeries       series;
        int[]                   indices;
 
-       static final int ALTOS_CSV_VERSION = 5;
+       static final int ALTOS_CSV_VERSION = 6;
 
        /* Version 4 format:
         *
@@ -49,7 +51,8 @@ public class AltosCSV implements AltosWriter {
         *      flight number
         *      callsign
         *      time (seconds since boost)
-        *      clock (tick count / 100)
+        *
+        * Radio info (if available)
         *      rssi
         *      link quality
         *
@@ -81,6 +84,14 @@ public class AltosCSV implements AltosWriter {
         *      mag_x (g)
         *      mag_y (g)
         *      mag_z (g)
+        *      tilt (d)
+        *
+        * Extra igniter voltages (if available)
+        *      pyro (V)
+        *      igniter_a (V)
+        *      igniter_b (V)
+        *      igniter_c (V)
+        *      igniter_d (V)
         *
         * GPS data (if available)
         *      connected (1/0)
@@ -115,13 +126,26 @@ public class AltosCSV implements AltosWriter {
         */
 
        void write_general_header() {
-               out.printf("version,serial,flight,call,time,clock,rssi,lqi");
+               out.printf("version,serial,flight,call,time");
        }
 
        double time() {
                return series.time(indices);
        }
 
+       void write_general() {
+               out.printf("%s, %d, %d, %s, %8.2f",
+                          ALTOS_CSV_VERSION,
+                          series.cal_data().serial,
+                          series.cal_data().flight,
+                          series.cal_data().callsign,
+                          time());
+       }
+
+       void write_radio_header() {
+               out.printf("rssi,lqi");
+       }
+
        int rssi() {
                return (int) series.value(AltosFlightSeries.rssi_name, indices);
        }
@@ -130,12 +154,8 @@ public class AltosCSV implements AltosWriter {
                return (int) series.value(AltosFlightSeries.status_name, indices);
        }
 
-       void write_general() {
-               double time = time();
-               out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d",
-                          ALTOS_CSV_VERSION, series.cal_data().serial,
-                          series.cal_data().flight, series.cal_data().callsign,
-                          time, time,
+       void write_radio() {
+               out.printf("%4d, %3d",
                           rssi(), status() & 0x7f);
        }
 
@@ -149,7 +169,7 @@ public class AltosCSV implements AltosWriter {
 
        void write_flight() {
                int state = state();
-               out.printf("%d,%8s", state, AltosLib.state_name(state));
+               out.printf("%2d,%8s", state, AltosLib.state_name(state));
        }
 
        void write_basic_header() {
@@ -189,7 +209,7 @@ public class AltosCSV implements AltosWriter {
        }
 
        void write_advanced_header() {
-               out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z");
+               out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z,tilt");
        }
 
        double accel_along() { return series.value(AltosFlightSeries.accel_along_name, indices); }
@@ -204,11 +224,30 @@ public class AltosCSV implements AltosWriter {
        double mag_across() { return series.value(AltosFlightSeries.mag_across_name, indices); }
        double mag_through() { return series.value(AltosFlightSeries.mag_through_name, indices); }
 
+       double tilt() { return series.value(AltosFlightSeries.orient_name, indices); }
+
        void write_advanced() {
-               out.printf("%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f",
+               out.printf("%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f",
                           accel_along(), accel_across(), accel_through(),
                           gyro_roll(), gyro_pitch(), gyro_yaw(),
-                          mag_along(), mag_across(), mag_through());
+                          mag_along(), mag_across(), mag_through(),
+                          tilt());
+       }
+
+       void write_igniter_header() {
+               out.printf("pyro");
+               for (int i = 0; i < series.igniter_voltage.length; i++)
+                       out.printf(",%s", AltosLib.igniter_short_name(i));
+       }
+
+       double pyro() { return series.value(AltosFlightSeries.pyro_voltage_name, indices); }
+
+       double igniter_value(int channel) { return series.value(series.igniter_voltage_name(channel), indices); }
+
+       void write_igniter() {
+               out.printf("%5.2f", pyro());
+               for (int i = 0; i < series.igniter_voltage.length; i++)
+                       out.printf(",%5.2f", igniter_value(i));
        }
 
        void write_gps_header() {
@@ -306,6 +345,10 @@ public class AltosCSV implements AltosWriter {
 
        void write_header() {
                out.printf("#"); write_general_header();
+               if (has_radio) {
+                       out.printf(",");
+                       write_radio_header();
+               }
                if (has_flight_state) {
                        out.printf(",");
                        write_flight_header();
@@ -322,6 +365,10 @@ public class AltosCSV implements AltosWriter {
                        out.printf(",");
                        write_advanced_header();
                }
+               if (has_igniter) {
+                       out.printf(",");
+                       write_igniter_header();
+               }
                if (has_gps) {
                        out.printf(",");
                        write_gps_header();
@@ -339,6 +386,10 @@ public class AltosCSV implements AltosWriter {
 
        void write_one() {
                write_general();
+               if (has_radio) {
+                       out.printf(",");
+                       write_radio();
+               }
                if (has_flight_state) {
                        out.printf(",");
                        write_flight();
@@ -355,6 +406,10 @@ public class AltosCSV implements AltosWriter {
                        out.printf(",");
                        write_advanced();
                }
+               if (has_igniter) {
+                       out.printf(",");
+                       write_igniter();
+               }
                if (has_gps) {
                        out.printf(",");
                        write_gps();
@@ -395,14 +450,18 @@ public class AltosCSV implements AltosWriter {
 
                series.finish();
 
+               has_radio = false;
                has_flight_state = false;
                has_basic = false;
                has_battery = false;
                has_advanced = false;
+               has_igniter = false;
                has_gps = false;
                has_gps_sat = false;
                has_companion = false;
 
+               if (series.has_series(AltosFlightSeries.rssi_name))
+                       has_radio = true;
                if (series.has_series(AltosFlightSeries.state_name))
                        has_flight_state = true;
                if (series.has_series(AltosFlightSeries.accel_name) || series.has_series(AltosFlightSeries.pressure_name))
@@ -411,6 +470,8 @@ public class AltosCSV implements AltosWriter {
                        has_battery = true;
                if (series.has_series(AltosFlightSeries.accel_across_name))
                        has_advanced = true;
+               if (series.has_series(AltosFlightSeries.pyro_voltage_name))
+                       has_igniter = true;
 
                if (series.gps_series != null)
                        has_gps = true;
index 6258c1a8448175d8e532c918d62fa506655fdcd3..03e2cbd72e17793aabf277fbc408188940b73fae 100644 (file)
@@ -72,6 +72,13 @@ public class AltosCalData {
                }
        }
 
+       public int              log_format = AltosLib.MISSING;
+
+       public void set_log_format(int log_format) {
+               if (log_format != AltosLib.MISSING)
+                       this.log_format = log_format;
+       }
+
        public int              config_major = AltosLib.MISSING;
        public int              config_minor = AltosLib.MISSING;
        public int              flight_log_max = AltosLib.MISSING;
@@ -192,7 +199,6 @@ public class AltosCalData {
                tick = AltosLib.MISSING;
                prev_tick = AltosLib.MISSING;
                temp_gps = null;
-               prev_gps = null;
                temp_gps_sat_tick = AltosLib.MISSING;
                accel = AltosLib.MISSING;
        }
@@ -235,13 +241,19 @@ public class AltosCalData {
 
        public AltosGPS         gps_pad = null;
 
+       public AltosGPS         prev_gps = null;
+
        public double           gps_pad_altitude = AltosLib.MISSING;
 
-       public void set_gps(AltosGPS gps) {
-               if ((state != AltosLib.MISSING && state < AltosLib.ao_flight_boost) || gps_pad == null)
-                       gps_pad = gps;
-               if (gps_pad_altitude == AltosLib.MISSING && gps.alt != AltosLib.MISSING)
-                       gps_pad_altitude = gps.alt;
+       public void set_cal_gps(AltosGPS gps) {
+               if (gps.locked && gps.nsat >= 4) {
+                       if ((state != AltosLib.MISSING && state < AltosLib.ao_flight_boost) || gps_pad == null)
+                               gps_pad = gps;
+                       if (gps_pad_altitude == AltosLib.MISSING && gps.alt != AltosLib.MISSING)
+                               gps_pad_altitude = gps.alt;
+               }
+               temp_gps = null;
+               prev_gps = gps;
        }
 
        /*
@@ -249,33 +261,24 @@ public class AltosCalData {
         * object and then deliver the result atomically to the listener
         */
        AltosGPS                temp_gps = null;
-       AltosGPS                prev_gps = null;
        int                     temp_gps_sat_tick = AltosLib.MISSING;
 
-       public AltosGPS temp_gps() {
+       public AltosGPS temp_cal_gps() {
                return temp_gps;
        }
 
-       public void reset_temp_gps() {
-               if (temp_gps != null) {
-                       if (temp_gps.locked && temp_gps.nsat >= 4)
-                               set_gps(temp_gps);
-                       prev_gps = temp_gps;
-                       temp_gps = null;
-               }
+       public void reset_temp_cal_gps() {
+               if (temp_gps != null)
+                       set_cal_gps(temp_gps);
        }
 
-       public boolean gps_pending() {
+       public boolean cal_gps_pending() {
                return temp_gps != null;
        }
 
-       public AltosGPS make_temp_gps(int tick, boolean sats) {
-               if (temp_gps == null) {
-                       if (prev_gps != null)
-                               temp_gps = prev_gps.clone();
-                       else
-                               temp_gps = new AltosGPS();
-               }
+       public AltosGPS make_temp_cal_gps(int tick, boolean sats) {
+               if (temp_gps == null)
+                       temp_gps = new AltosGPS(prev_gps);
                if (sats) {
                        if (tick != temp_gps_sat_tick)
                                temp_gps.cc_gps_sat = null;
index be6d840f0091e9b20d21589634ff63099272f5eb..9a1e1465fbb19aa39781f33904ce7f09ac65c1ed 100644 (file)
@@ -19,10 +19,16 @@ public abstract class AltosDataListener {
        private AltosCalData    cal_data = null;
 
        public double           time = AltosLib.MISSING;
-       public int              state = AltosLib.MISSING;
        public double           frequency = AltosLib.MISSING;
 
+       public int              raw_tick = AltosLib.MISSING;
+
+       public int tick() {
+               return raw_tick;
+       }
+
        public void set_tick(int tick) {
+               raw_tick = tick;
                cal_data.set_tick(tick);
                set_time(cal_data.time());
        }
@@ -42,14 +48,34 @@ public abstract class AltosDataListener {
                cal_data().set_serial(serial);
        }
 
+       public void set_device_type(int device_type) {
+               cal_data().set_device_type(device_type);
+               switch (device_type) {
+               case AltosLib.product_telegps:
+                       set_state(AltosLib.ao_flight_stateless);
+                       break;
+               }
+       }
+
+       public void set_log_format(int log_format) {
+               cal_data().set_log_format(log_format);
+               switch (log_format) {
+               case AltosLib.AO_LOG_FORMAT_TELEGPS:
+                       set_state(AltosLib.ao_flight_stateless);
+                       break;
+               }
+       }
+
        public double time() {
                return time;
        }
 
        public void set_state(int state) {
                cal_data().set_state(state);
-               if (state != AltosLib.MISSING)
-                       this.state = state;
+       }
+
+       public int state() {
+               return cal_data().state;
        }
 
        public void set_flight(int flight) {
@@ -64,6 +90,12 @@ public abstract class AltosDataListener {
        public void finish() {
        }
 
+       public void init() {
+               set_state(AltosLib.ao_flight_invalid);
+               time = AltosLib.MISSING;
+               frequency = AltosLib.MISSING;
+       }
+
        public abstract void set_rssi(int rssi, int status);
        public abstract void set_received_time(long received_time);
 
@@ -79,7 +111,18 @@ public abstract class AltosDataListener {
        public abstract void set_apogee_voltage(double volts);
        public abstract void set_main_voltage(double volts);
 
-       public abstract void set_gps(AltosGPS gps);
+       public void set_gps(AltosGPS gps) {
+               AltosCalData cal_data = cal_data();
+               cal_data.set_cal_gps(gps);
+       }
+
+       public AltosGPS make_temp_gps(boolean sats) {
+               return cal_data().make_temp_cal_gps(tick(), sats);
+       }
+
+       public AltosGPS temp_gps() {
+               return cal_data().temp_cal_gps();
+       }
 
        public abstract void set_orient(double orient);
        public abstract void set_gyro(double roll, double pitch, double yaw);
index ad7bf88104e8cb9ff106e02500b2737b8aa631a1..124bd478e0131fecb4dca900e4ee79c2c8b71e67 100644 (file)
@@ -22,6 +22,7 @@ public class AltosEeprom {
        private AltosJson       config;
        ArrayList<Byte>         data;
        private AltosConfigData config_data;
+       int                     errors = 0;
 
        /*
         * Public accessor APIs
index 33f0dd177997104e1bd1f8e8eabf0e2d8aff1fd2..547b523f362aea1532da2962fdf1644269af2e23 100644 (file)
@@ -40,6 +40,7 @@ class AltosEepromNameData extends AltosDataListener {
        public void set_main_voltage(double volts) { }
 
        public void set_gps(AltosGPS gps) {
+               super.set_gps(gps);
                if (gps != null &&
                    gps.year != AltosLib.MISSING &&
                    gps.month != AltosLib.MISSING &&
@@ -199,25 +200,47 @@ public class AltosEepromDownload implements Runnable {
 
                AltosFile f = MakeFile(flights.config_data.serial, log.flight, name_data);
 
-               monitor.set_filename(f.toString());
+               log.set_file(f);
 
-               FileWriter w = new FileWriter(f);
+               boolean do_write = true;
 
-               eeprom.write(w);
-               w.close();
+               if (f.exists())
+                       do_write = monitor.check_overwrite(f);
+
+               if (do_write) {
+                       FileWriter w = new FileWriter(f);
+
+                       eeprom.write(w);
+                       w.close();
+               }
+
+               if (eeprom.errors != 0)
+                       throw new ParseException(String.format("%d CRC Errors", eeprom.errors), 0);
+       }
+
+       static String label(int flight) {
+               if (flight < 0)
+                       return "Corrupt";
+               else
+                       return "Flight";
+       }
+
+       static int flight(int flight) {
+               if (flight < 0)
+                       return -flight;
+               return flight;
        }
 
        public void run () {
                boolean success = false;
 
                try {
-                       boolean failed = false;
                        if (remote)
                                link.start_remote();
 
                        for (AltosEepromLog log : flights) {
                                parse_errors = null;
-                               if (log.selected) {
+                               if (log.download_selected) {
                                        monitor.reset();
                                        try {
                                                CaptureLog(log);
@@ -225,16 +248,16 @@ public class AltosEepromDownload implements Runnable {
                                                LogError(e.getMessage());
                                        }
                                }
+                               success = true;
                                if (parse_errors != null) {
-                                       failed = true;
-                                       monitor.show_message(String.format("Flight %d download error. Valid log data saved\n%s",
-                                                                          log.flight,
+                                       monitor.show_message(String.format("%s %d download error. Valid log data saved\n%s",
+                                                                          label(log.flight),
+                                                                          flight(log.flight),
                                                                           parse_errors),
                                                             link.name,
                                                             AltosEepromMonitor.WARNING_MESSAGE);
                                }
                        }
-                       success = !failed;
                } catch (IOException ee) {
                        monitor.show_message(ee.getLocalizedMessage(),
                                             link.name,
index 55d47e20d345d217631e5490776dbd3496f24780..c55bcaaa2a3c6ef6b13feb32b3476eba76c877cd 100644 (file)
@@ -87,7 +87,7 @@ public class AltosEepromList extends ArrayList<AltosEepromLog> {
                                                        start = AltosParse.parse_hex(tokens[3]);
                                                if (tokens[4].equals("end"))
                                                        end = AltosParse.parse_hex(tokens[5]);
-                                               if (flight > 0 && start >= 0 && end > 0)
+                                               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()); }
                                }
@@ -115,4 +115,4 @@ public class AltosEepromList extends ArrayList<AltosEepromLog> {
                        link.flush_output();
                }
        }
-}
\ No newline at end of file
+}
index 8d1f3fc4e8cb603bd56bbda09aeebde9b38acf4e..ba722b89085abee35973977d6244d32669a03c62 100644 (file)
@@ -18,6 +18,7 @@
 
 package org.altusmetrum.altoslib_12;
 
+import java.io.*;
 import java.text.*;
 import java.util.concurrent.*;
 
@@ -32,7 +33,15 @@ public class AltosEepromLog {
        public int              start_block;
        public int              end_block;
 
-       public boolean          selected;
+       public boolean          download_selected;
+       public boolean          delete_selected;
+       public boolean          graph_selected;
+
+       public File             file;
+
+       public void set_file(File file) {
+               this.file = file;
+       }
 
        public AltosEepromLog(AltosConfigData config_data,
                              AltosLink link,
@@ -50,8 +59,11 @@ public class AltosEepromLog {
                serial = config_data.serial;
 
                /*
-                * Select all flights for download
+                * Select all flights for download and graph, but not
+                * for delete
                 */
-               selected = true;
+               download_selected = true;
+               delete_selected = false;
+               graph_selected = true;
        }
 }
index a99ec687b2b7efbb24c5db250ec1db12ee5f90f4..11144a3ada74497ea96b831eb011d6e26bad31c8 100644 (file)
@@ -18,6 +18,8 @@
 
 package org.altusmetrum.altoslib_12;
 
+import java.io.*;
+
 public interface AltosEepromMonitor {
 
        public void set_block(int in_block);
@@ -28,8 +30,6 @@ public interface AltosEepromMonitor {
 
        public void set_flight(int in_flight);
 
-       public void set_filename(String in_file);
-
        public void set_thread(Thread eeprom_thread);
 
        final static int INFO_MESSAGE = 0;
@@ -38,6 +38,8 @@ public interface AltosEepromMonitor {
 
        public void show_message(String message, String title, int message_type);
 
+       public Boolean check_overwrite(File file);
+
        public void start();
 
        public void done(boolean success);
index 094584fecf8176668b1f239daca1a1520d8ff3b2..43e8ea4dbeccefa323e7ad273f0029c1750e8313 100644 (file)
@@ -50,8 +50,22 @@ public abstract class AltosEepromRecord implements Comparable<AltosEepromRecord>
                return data8(i) | (data8(i+1) << 8) | (data8(i+2) << 16) | (data8(i+3) << 24);
        }
 
+       public boolean empty(int s) {
+               for (int i = 0; i < length; i++)
+                       if (eeprom.data8(s + i) != 0xff)
+                               return false;
+               return true;
+       }
+
        public boolean valid(int s) {
-               return AltosConvert.checksum(eeprom.data, s, length) == 0;
+               int     ck = AltosConvert.checksum(eeprom.data, s, length);
+
+               if (ck != 0) {
+                       ++eeprom.errors;
+                       System.out.printf("invalid checksum 0x%x at 0x%x\n", ck, s);
+                       return false;
+               }
+               return true;
        }
 
        public boolean valid() {
@@ -83,18 +97,16 @@ public abstract class AltosEepromRecord implements Comparable<AltosEepromRecord>
 
        /* AltosDataProvider */
        public void provide_data(AltosDataListener listener, AltosCalData cal_data) {
-               cal_data.set_tick(tick());
+               listener.set_tick(tick());
                if (cmd() == AltosLib.AO_LOG_FLIGHT)
                        cal_data.set_boost_tick();
                listener.set_time(cal_data.time());
 
                /* Flush any pending GPS changes */
                if (!AltosLib.is_gps_cmd(cmd())) {
-                       AltosGPS gps = cal_data.temp_gps();
-                       if (gps != null) {
+                       AltosGPS gps = listener.temp_gps();
+                       if (gps != null)
                                listener.set_gps(gps);
-                               cal_data.reset_temp_gps();
-                       }
                }
        }
 
@@ -102,25 +114,18 @@ public abstract class AltosEepromRecord implements Comparable<AltosEepromRecord>
                int     s = start + length;
 
                while (s + length <= eeprom.data.size()) {
-                       if (valid(s))
+                       if (!empty(s) && valid(s))
                                return s;
                        s += length;
                }
                return -1;
        }
 
-       public boolean hasNext() {
-               return next_start() >= 0;
-       }
-
        public abstract AltosEepromRecord next();
 
        public AltosEepromRecord(AltosEeprom eeprom, int start, int length) {
                this.eeprom = eeprom;
                this.start = start;
                this.length = length;
-
-               while (start + length < eeprom.data.size() && !valid())
-                       start += length;
        }
 }
index 32df957841e19e978cc8c2892b9bda7a856de535..7e92d35377bc1912d5a8363d80d82bc370dd838f 100644 (file)
@@ -53,7 +53,7 @@ public class AltosEepromRecordFull extends AltosEepromRecord {
                        listener.set_state(data16(0));
                        break;
                case AltosLib.AO_LOG_GPS_TIME:
-                       gps = cal_data.make_temp_gps(tick(),false);
+                       gps = listener.make_temp_gps(false);
 
                        gps.hour = data8(0);
                        gps.minute = data8(1);
@@ -67,29 +67,29 @@ public class AltosEepromRecordFull extends AltosEepromRecord {
                                AltosLib.AO_GPS_NUM_SAT_SHIFT;
                        break;
                case AltosLib.AO_LOG_GPS_LAT:
-                       gps = cal_data.make_temp_gps(tick(),false);
+                       gps = listener.make_temp_gps(false);
 
                        int lat32 = data32(0);
                        gps.lat = (double) lat32 / 1e7;
                        break;
                case AltosLib.AO_LOG_GPS_LON:
-                       gps = cal_data.make_temp_gps(tick(),false);
+                       gps = listener.make_temp_gps(false);
 
                        int lon32 = data32(0);
                        gps.lon = (double) lon32 / 1e7;
                        break;
                case AltosLib.AO_LOG_GPS_ALT:
-                       gps = cal_data.make_temp_gps(tick(),false);
+                       gps = listener.make_temp_gps(false);
                        gps.alt = data16(0);
                        break;
                case AltosLib.AO_LOG_GPS_SAT:
-                       gps = cal_data.make_temp_gps(tick(),true);
+                       gps = listener.make_temp_gps(true);
                        int svid = data16(0);
                        int c_n0 = data16(2);
                        gps.add_sat(svid, c_n0);
                        break;
                case AltosLib.AO_LOG_GPS_DATE:
-                       gps = cal_data.make_temp_gps(tick(),false);
+                       gps = listener.make_temp_gps(false);
                        gps.year = data8(0) + 2000;
                        gps.month = data8(1);
                        gps.day = data8(2);
index ad3e23fdfeeefcbc258354f5941dd6d5c35013b9..86343fe058c4f112d2f91bd9faf0446bac15722d 100644 (file)
@@ -31,6 +31,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {
        private int ground_roll() {
                switch (log_format) {
                case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+               case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
                        return data32(16);
                case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
                        return data16(14);
@@ -41,6 +42,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {
        private int ground_pitch() {
                switch (log_format) {
                case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+               case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
                        return data32(20);
                case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
                        return data16(16);
@@ -51,6 +53,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {
        private int ground_yaw() {
                switch (log_format) {
                case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+               case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
                        return data32(24);
                case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
                        return data16(18);
@@ -188,7 +191,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {
                        listener.set_pyro_fired(pyro());
                        break;
                case AltosLib.AO_LOG_GPS_TIME:
-                       gps = cal_data.make_temp_gps(tick(), false);
+                       gps = listener.make_temp_gps(false);
                        gps.lat = latitude() / 1e7;
                        gps.lon = longitude() / 1e7;
 
@@ -231,7 +234,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {
                        }
                        break;
                case AltosLib.AO_LOG_GPS_SAT:
-                       gps = cal_data.make_temp_gps(tick(), true);
+                       gps = listener.make_temp_gps(true);
 
                        int n = nsat();
                        if (n > max_sat)
index 3da50544b2a56db660c619faf16cde1156e1c728..888a06cca2fbe02316525f6a01f7e10428ee4168 100644 (file)
@@ -91,7 +91,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord {
                        listener.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m()));
                        break;
                case AltosLib.AO_LOG_GPS_POS:
-                       gps = cal_data.make_temp_gps(tick(), false);
+                       gps = listener.make_temp_gps(false);
                        gps.lat = latitude() / 1e7;
                        gps.lon = longitude() / 1e7;
                        if (config_data().altitude_32())
@@ -100,7 +100,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord {
                                gps.alt = altitude_low();
                        break;
                case AltosLib.AO_LOG_GPS_TIME:
-                       gps = cal_data.make_temp_gps(tick(), false);
+                       gps = listener.make_temp_gps(false);
 
                        gps.hour = hour();
                        gps.minute = minute();
@@ -119,7 +119,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord {
                        gps.pdop = pdop() / 10.0;
                        break;
                case AltosLib.AO_LOG_GPS_SAT:
-                       gps = cal_data.make_temp_gps(tick(), true);
+                       gps = listener.make_temp_gps(true);
 
                        int n = nsat();
                        for (int i = 0; i < n; i++)
index 48e90c055e0269be6136385ac50935e411d4505e..360759314d4bf9e123bf2e109271f66beb6375ff 100644 (file)
@@ -44,6 +44,8 @@ public class AltosEepromRecordSet implements AltosRecordSet {
                AltosCalData    cal_data = cal_data();
 
                cal_data.reset();
+               listener.set_log_format(config_data().log_format);
+
                for (AltosEepromRecord record : ordered) {
                        record.provide_data(listener, cal_data);
                }
@@ -67,6 +69,7 @@ public class AltosEepromRecordSet implements AltosRecordSet {
                case AltosLib.AO_LOG_FORMAT_TELEMETRY:
                case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
                case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+               case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:
                case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
                        record = new AltosEepromRecordMega(eeprom);
                        break;
@@ -95,7 +98,7 @@ public class AltosEepromRecordSet implements AltosRecordSet {
                int     tick = 0;
                boolean first = true;
 
-               for (;;) {
+               do {
                        int     t = record.tick();
 
                        if (first) {
@@ -108,10 +111,8 @@ public class AltosEepromRecordSet implements AltosRecordSet {
                        }
                        record.wide_tick = tick;
                        ordered.add(record);
-                       if (!record.hasNext())
-                               break;
                        record = record.next();
-               }
+               } while (record != null);
        }
 
        public AltosEepromRecordSet(InputStream input) throws IOException {
index 69f779c1d46f50e87e16c3617f17071109036ed7..6f98b87ac5fb033f748e855eb6019ba621fd53d1 100644 (file)
@@ -36,10 +36,23 @@ public class AltosFile extends File {
                return String.format("-via-%04d", receiver);
        }
 
+       static private String label(int flight) {
+               if (flight < 0)
+                       return "corrupt";
+               else
+                       return "flight";
+       }
+
+       static private int flight(int flight) {
+               if (flight < 0)
+                       return -flight;
+               return flight;
+       }
+
        public AltosFile(int year, int month, int day, int serial, int flight, int receiver, String extension) {
                super (AltosPreferences.logdir(),
-                      String.format("%04d-%02d-%02d-serial-%s-flight-%s%s.%s",
-                                    year, month, day, number(serial), number(flight), receiver(receiver), extension));
+                      String.format("%04d-%02d-%02d-serial-%s-%s-%s%s.%s",
+                                    year, month, day, number(serial), label(flight), number(flight(flight)), receiver(receiver), extension));
        }
 
        public AltosFile(int year, int month, int day, int serial, int flight, String extension) {
diff --git a/altoslib/AltosFilterListener.java b/altoslib/AltosFilterListener.java
new file mode 100644 (file)
index 0000000..fe91100
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+package org.altusmetrum.altoslib_12;
+
+public interface AltosFilterListener {
+       void filter_changed(double speed_filter, double accel_filter);
+
+       double speed_filter();
+       double accel_filter();
+}
diff --git a/altoslib/AltosFlightListener.java b/altoslib/AltosFlightListener.java
deleted file mode 100644 (file)
index d61831a..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright © 2017 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.
- */
-
-package org.altusmetrum.altoslib_12;
-
-public abstract class AltosFlightListener {
-
-       public int      flight;
-       public int      serial;
-       public int      tick;
-       public int      boost_tick;
-       public int      state;
-
-       public double   accel_plus_g;
-       public double   accel_minus_g;
-       public double   accel;
-
-       public double   ground_pressure;
-       public double   ground_altitude;
-
-       AltosGPS        temp_gps;
-       int             temp_gps_sat_tick;
-       int             gps_sequence;
-
-       /* AltosEepromRecord */
-       public void set_boost_tick(int boost_tick) {
-               if (boost_tick != AltosLib.MISSING)
-                       this.boost_tick = boost_tick;
-       }
-
-       public void set_tick(int tick) {
-               if (tick != AltosLib.MISSING)
-                       this.tick = tick;
-       }
-
-       public double time() {
-               if (tick == AltosLib.MISSING)
-                       return AltosLib.MISSING;
-               if (boost_tick != AltosLib.MISSING)
-                       return (tick - boost_tick) / 100.0;
-               else
-                       return tick / 100.0;
-       }
-
-       public double boost_time() {
-               if (boost_tick == AltosLib.MISSING)
-                       return AltosLib.MISSING;
-               return boost_tick / 100.0;
-       }
-
-       public abstract void set_rssi(int rssi, int status);
-       public abstract void set_received_time(long received_time);
-
-       /* AltosEepromRecordFull */
-
-       public void set_serial(int serial) {
-               if (serial != AltosLib.MISSING)
-                       this.serial = serial;
-       }
-
-       public void set_state(int state) {
-               if (state != AltosLib.MISSING)
-                       this.state = state;
-       }
-
-       public int state() { return state; }
-
-       public abstract void set_ground_accel(double ground_accel);
-       public void set_flight(int flight) {
-               if (flight != AltosLib.MISSING)
-                       this.flight = flight;
-       }
-       public int flight() {
-               return flight;
-       }
-
-       public abstract void set_accel(double accel);
-       public abstract void set_acceleration(double accel);
-       public abstract void set_accel_g(double accel_plus_g, double accel_minus_g);
-       public abstract void set_pressure(double pa);
-       public abstract void set_thrust(double N);
-
-       public abstract void set_temperature(double deg_c);
-       public abstract void set_battery_voltage(double volts);
-
-       public abstract void set_apogee_voltage(double volts);
-       public abstract void set_main_voltage(double volts);
-
-       public void set_temp_gps() {
-               temp_gps = null;
-       }
-
-       public boolean gps_pending() {
-               return temp_gps != null;
-       }
-
-       public AltosGPS make_temp_gps(boolean sats) {
-               if (temp_gps == null) {
-                       temp_gps = new AltosGPS();
-               }
-               if (sats) {
-                       if (tick != temp_gps_sat_tick)
-                               temp_gps.cc_gps_sat = null;
-                       temp_gps_sat_tick = tick;
-               }
-               return temp_gps;
-       }
-
-       public void set_ground_pressure(double ground_pressure) {
-               if (ground_pressure != AltosLib.MISSING) {
-                       this.ground_pressure = ground_pressure;
-                       this.ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure);
-               }
-       }
-
-       public abstract void set_accel_ground(double along, double across, double through);
-       public abstract void set_gyro_zero(double roll, double pitch, double yaw);
-       public abstract void check_imu_wrap(AltosIMU imu);
-       public abstract void set_imu(AltosIMU imu);
-       public abstract void set_mag(AltosMag mag);
-       public abstract void set_pyro_voltage(double volts);
-       public abstract void set_igniter_voltage(double[] voltage);
-       public abstract void set_pyro_fired(int pyro_mask);
-
-       public void copy(AltosFlightListener old) {
-               flight = old.flight;
-               serial = old.serial;
-               tick = old.tick;
-               boost_tick = old.boost_tick;
-               accel_plus_g = old.accel_plus_g;
-               accel_minus_g = old.accel_minus_g;
-               ground_pressure = old.ground_pressure;
-               ground_altitude = old.ground_altitude;
-               temp_gps = old.temp_gps;
-               temp_gps_sat_tick = old.temp_gps_sat_tick;
-       }
-
-       public void init() {
-               flight = AltosLib.MISSING;
-               serial = AltosLib.MISSING;
-               tick = AltosLib.MISSING;
-               boost_tick = AltosLib.MISSING;
-               accel_plus_g = AltosLib.MISSING;
-               accel_minus_g = AltosLib.MISSING;
-               accel = AltosLib.MISSING;
-               ground_pressure = AltosLib.MISSING;
-               ground_altitude = AltosLib.MISSING;
-               temp_gps = null;
-               temp_gps_sat_tick = AltosLib.MISSING;
-       }
-}
index 57f1a49163f639879c6d2ce65f7b03d429aecab4..d130d3adcfa6ae6ca41f38da645c060fbf046b41 100644 (file)
@@ -21,7 +21,7 @@ public class AltosFlightSeries extends AltosDataListener {
        public ArrayList<AltosTimeSeries> series = new ArrayList<AltosTimeSeries>();
 
        public double   speed_filter_width = 4.0;
-       public double   accel_filter_width = 4.0;
+       public double   accel_filter_width = 1.0;
 
        public int[] indices() {
                int[] indices = new int[series.size()];
@@ -150,18 +150,17 @@ public class AltosFlightSeries extends AltosDataListener {
 
        public void set_state(int state) {
 
-               if (state == AltosLib.ao_flight_pad)
-                       return;
-
-               if (state_series == null)
-                       state_series = add_series(state_name, AltosConvert.state_name);
-               else if (this.state == state)
-                       return;
-               this.state = state;
-               state_series.add(time(), state);
+               if (state != AltosLib.ao_flight_pad && state != AltosLib.MISSING && state != AltosLib.ao_flight_stateless) {
+                       if (state_series == null)
+                               state_series = add_series(state_name, AltosConvert.state_name);
+                       if (this.state() != state)
+                               state_series.add(time(), state);
+               }
+               super.set_state(state);
        }
 
        public AltosTimeSeries  accel_series;
+       public boolean          accel_computed;
 
        public static final String accel_name = "Accel";
 
@@ -176,23 +175,61 @@ public class AltosFlightSeries extends AltosDataListener {
                        accel_series = add_series(accel_name, AltosConvert.accel);
 
                accel_series.add(time(), acceleration);
+               accel_computed = false;
        }
 
-       private void compute_accel() {
-               if (accel_series != null)
-                       return;
+       private AltosTimeSeries compute_accel() {
+               AltosTimeSeries new_accel_series = null;
 
                if (speed_series != null) {
-                       AltosTimeSeries temp_series = make_series(speed_name, AltosConvert.speed);
-                       speed_series.filter(temp_series, accel_filter_width);
-                       accel_series = add_series(accel_name, AltosConvert.accel);
-                       temp_series.differentiate(accel_series);
+                       AltosTimeSeries temp_series;
+                       if (accel_filter_width > 0) {
+                               temp_series = make_series(speed_name, AltosConvert.speed);
+                               speed_series.filter(temp_series, accel_filter_width);
+                       } else
+                               temp_series = speed_series;
+
+                       new_accel_series = make_series(accel_name, AltosConvert.accel);
+                       temp_series.differentiate(new_accel_series);
+               }
+               return new_accel_series;
+       }
+
+       public void set_filter(double speed_filter, double accel_filter) {
+               this.speed_filter_width = speed_filter;
+               this.accel_filter_width = accel_filter;
+
+               AltosTimeSeries new_speed_series = compute_speed();
+
+               if (new_speed_series != null) {
+                       speed_series.erase_values();
+                       for (AltosTimeValue tv : new_speed_series)
+                               speed_series.add(tv);
+               }
+               if (accel_computed) {
+                       AltosTimeSeries new_accel_series = compute_accel();
+                       if (new_accel_series != null) {
+                               accel_series.erase_values();
+                               for (AltosTimeValue tv : new_accel_series)
+                                       accel_series.add(tv);
+                       }
                }
        }
 
        public void set_received_time(long received_time) {
        }
 
+       public AltosTimeSeries tick_series;
+
+       public static final String tick_name = "Tick";
+
+       public void set_tick(int tick) {
+               super.set_tick(tick);
+               if (tick_series == null)
+                       tick_series = add_series(tick_name, null);
+               tick_series.add(time(), tick);
+       }
+
        public AltosTimeSeries rssi_series;
 
        public static final String rssi_name = "RSSI";
@@ -259,21 +296,24 @@ public class AltosFlightSeries extends AltosDataListener {
 
        public static final String speed_name = "Speed";
 
-       private void compute_speed() {
-               if (speed_series != null)
-                       return;
-
+       private AltosTimeSeries compute_speed() {
+               AltosTimeSeries new_speed_series = null;
                AltosTimeSeries alt_speed_series = null;
                AltosTimeSeries accel_speed_series = null;
 
                if (altitude_series != null) {
-                       AltosTimeSeries temp_series = make_series(altitude_name, AltosConvert.height);
-                       altitude_series.filter(temp_series, speed_filter_width);
+                       AltosTimeSeries temp_series;
+
+                       if (speed_filter_width > 0) {
+                               temp_series = make_series(speed_name, AltosConvert.height);
+                               altitude_series.filter(temp_series, speed_filter_width);
+                       } else
+                               temp_series = altitude_series;
 
                        alt_speed_series = make_series(speed_name, AltosConvert.speed);
                        temp_series.differentiate(alt_speed_series);
                }
-               if (accel_series != null) {
+               if (accel_series != null && !accel_computed) {
 
                        if (orient_series != null) {
                                vert_accel_series = add_series(vert_accel_name, AltosConvert.accel);
@@ -309,26 +349,25 @@ public class AltosFlightSeries extends AltosDataListener {
                                }
                        }
                        if (apogee_time == AltosLib.MISSING) {
-                               speed_series = alt_speed_series;
+                               new_speed_series = alt_speed_series;
                        } else {
-                               speed_series = make_series(speed_name, AltosConvert.speed);
+                               new_speed_series = make_series(speed_name, AltosConvert.speed);
                                for (AltosTimeValue d : accel_speed_series) {
                                        if (d.time <= apogee_time)
-                                               speed_series.add(d);
+                                               new_speed_series.add(d);
                                }
                                for (AltosTimeValue d : alt_speed_series) {
                                        if (d.time > apogee_time)
-                                               speed_series.add(d);
+                                               new_speed_series.add(d);
                                }
 
                        }
                } else if (alt_speed_series != null) {
-                       speed_series = alt_speed_series;
+                       new_speed_series = alt_speed_series;
                } else if (accel_speed_series != null) {
-                       speed_series = accel_speed_series;
+                       new_speed_series = accel_speed_series;
                }
-               if (speed_series != null)
-                       add_series(speed_series);
+               return new_speed_series;
        }
 
        public AltosTimeSeries orient_series;
@@ -450,13 +489,24 @@ public class AltosFlightSeries extends AltosDataListener {
        public ArrayList<AltosGPSTimeValue> gps_series;
 
        public AltosGPS gps_before(double time) {
-               AltosGPS gps = null;
-               for (AltosGPSTimeValue gtv : gps_series)
-                       if (gtv.time <= time)
-                               gps = gtv.gps;
-                       else
-                               break;
-               return gps;
+               AltosGPSTimeValue nearest = null;
+               for (AltosGPSTimeValue gtv : gps_series) {
+                       if (nearest == null)
+                               nearest = gtv;
+                       else {
+                               if (gtv.time <= time) {
+                                       if (nearest.time <= time && gtv.time > nearest.time)
+                                               nearest = gtv;
+                               } else {
+                                       if (nearest.time > time && gtv.time < nearest.time)
+                                               nearest = gtv;
+                               }
+                       }
+               }
+               if (nearest != null)
+                       return nearest.gps;
+               else
+                       return null;
        }
 
        public AltosTimeSeries  sats_in_view;
@@ -482,6 +532,7 @@ public class AltosFlightSeries extends AltosDataListener {
        public static final String gps_hdop_name = "GPS Horizontal Dilution of Precision";
 
        public void set_gps(AltosGPS gps) {
+               super.set_gps(gps);
                if (gps_series == null)
                        gps_series = new ArrayList<AltosGPSTimeValue>();
                gps_series.add(new AltosGPSTimeValue(time(), gps));
@@ -643,7 +694,7 @@ public class AltosFlightSeries extends AltosDataListener {
        public  void set_igniter_voltage(double[] voltage) {
                int channels = voltage.length;
                if (igniter_voltage == null || igniter_voltage.length <= channels) {
-                       AltosTimeSeries[]       new_igniter_voltage = new AltosTimeSeries[channels + 1];
+                       AltosTimeSeries[]       new_igniter_voltage = new AltosTimeSeries[channels];
                        int                     i = 0;
 
                        if (igniter_voltage != null) {
@@ -681,8 +732,18 @@ public class AltosFlightSeries extends AltosDataListener {
 
        public void finish() {
                compute_orient();
-               compute_speed();
-               compute_accel();
+               if (speed_series == null) {
+                       speed_series = compute_speed();
+                       if (speed_series != null)
+                               add_series(speed_series);
+               }
+               if (accel_series == null) {
+                       accel_series = compute_accel();
+                       if (accel_series != null) {
+                               add_series(accel_series);
+                               accel_computed = true;
+                       }
+               }
                compute_height();
        }
 
index ea1a9675aba8c818c814481bb45e6e545568cae0..6bb835810b6183b8d885d95629e782b6ce8c10c8 100644 (file)
@@ -27,6 +27,8 @@ public class AltosFlightStats {
        public double           max_acceleration;
        public double[]         state_speed = new double[AltosLib.ao_flight_invalid + 1];
        public double[]         state_enter_speed = new double[AltosLib.ao_flight_invalid + 1];
+       public double[]         state_enter_height = new double[AltosLib.ao_flight_invalid + 1];
+       public double[]         state_enter_gps_height = new double[AltosLib.ao_flight_invalid + 1];
        public double[]         state_accel = new double[AltosLib.ao_flight_invalid + 1];
        public double[]         state_time = new double[AltosLib.ao_flight_invalid + 1];
        public String           product;
@@ -134,6 +136,11 @@ public class AltosFlightStats {
                if (0 <= state && state <= AltosLib.ao_flight_invalid && delta_time > 0) {
                        if (state_enter_speed[state] == AltosLib.MISSING)
                                state_enter_speed[state] = series.speed_series.value(start_time);
+                       if (state_enter_height[state] == AltosLib.MISSING)
+                               state_enter_height[state] = series.height_series.value(start_time);
+                       if (state_enter_gps_height[state] == AltosLib.MISSING)
+                               if (series.gps_height != null)
+                                       state_enter_gps_height[state] = series.gps_height.value(start_time);
                        speeds[state].value += series.speed_series.average(start_time, end_time) * delta_time;
                        speeds[state].time += delta_time;
                        accels[state].value += series.accel_series.average(start_time, end_time) * delta_time;
index dee28a92319eb8532d5d2556180ae51fa827509d..ba6f1a82584089c46a643d4e67d03af691ce39aa 100644 (file)
@@ -83,9 +83,9 @@ public class AltosIMU implements Cloneable {
                                listener.set_gyro(cal_data.gyro_roll(imu.gyro_y),
                                                  cal_data.gyro_pitch(imu.gyro_x),
                                                  cal_data.gyro_yaw(imu.gyro_z));
-                               listener.set_accel_ground(cal_data.accel_along(imu.accel_y),
-                                                         cal_data.accel_across(imu.accel_x),
-                                                         cal_data.accel_through(imu.accel_z));
+                               listener.set_accel_ground(imu.accel_y,
+                                                         imu.accel_x,
+                                                         imu.accel_z);
                        }
                } catch (TimeoutException te) {
                }
index fc5d4cc889ef51bbe52227bb93d53b2409a9723e..834d9aa54055a981ab209c008811f603266668ed 100644 (file)
@@ -33,6 +33,7 @@ public class AltosIdleMonitor extends Thread {
        double                  frequency;
        String                  callsign;
 
+       AltosState              state;
        AltosListenerState      listener_state;
        AltosConfigData         config_data;
        AltosGPS                gps;
@@ -52,20 +53,23 @@ public class AltosIdleMonitor extends Thread {
                return link.reply_abort;
        }
 
-       boolean provide_data(AltosDataListener listener) throws InterruptedException, TimeoutException, AltosUnknownProduct {
+       boolean provide_data() throws InterruptedException, TimeoutException, AltosUnknownProduct {
                boolean         worked = false;
                boolean         aborted = false;
 
                try {
                        start_link();
-                       fetch.provide_data(listener);
+                       link.config_data();
+                       if (state == null)
+                               state = new AltosState(new AltosCalData(link.config_data()));
+                       fetch.provide_data(state);
                        if (!link.has_error && !link.reply_abort)
                                worked = true;
                } finally {
                        aborted = stop_link();
                        if (worked) {
                                if (remote)
-                                       listener.set_rssi(link.rssi(), 0);
+                                       state.set_rssi(link.rssi(), 0);
                                listener_state.battery = link.monitor_battery();
                        }
                }
@@ -92,14 +96,11 @@ public class AltosIdleMonitor extends Thread {
        }
 
        public void run() {
-               AltosState state = null;
+               state = null;
                try {
                        for (;;) {
                                try {
-                                       link.config_data();
-                                       if (state == null)
-                                               state = new AltosState(new AltosCalData(link.config_data()));
-                                       provide_data(state);
+                                       provide_data();
                                        listener.update(state, listener_state);
                                } catch (TimeoutException te) {
                                } catch (AltosUnknownProduct ae) {
index 587b845bb7ac68cef04bd1c7b024e2ef63a22486..d5248a17377be645fab9164c40b5ebaa1ea05cc9 100644 (file)
@@ -38,16 +38,18 @@ public class AltosKML implements AltosWriter {
        int                     flight_state = -1;
        AltosGPS                prev = null;
        double                  gps_start_altitude = AltosLib.MISSING;
+       AltosFlightSeries       series;
        AltosFlightStats        stats;
+       AltosCalData            cal_data;
 
        static final String[] kml_state_colors = {
                "FF000000",     // startup
                "FF000000",     // idle
                "FF000000",     // pad
                "FF0000FF",     // boost
+               "FF8040FF",     // coast
                "FF4080FF",     // fast
-               "FF00FFFF",     // coast
-               "FFFF0000",     // drogue
+               "FF00FFFF",     // drogue
                "FF00FF00",     // main
                "FF000000",     // landed
                "FFFFFFFF",     // invalid
@@ -60,85 +62,169 @@ public class AltosKML implements AltosWriter {
                return kml_state_colors[state];
        }
 
+       static final String[] kml_style_colors = {
+               "FF0000FF",     // baro
+               "FFFF0000",     // gps
+       };
+
+       static String style_color(int style) {
+               if (style < 0 || kml_style_colors.length <= style)
+                       return kml_style_colors[0];
+               return kml_style_colors[style];
+       }
+
        static final String kml_header_start =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
                "<Document>\n" +
                "  <name>AO Flight#%d S/N: %03d</name>\n" +
-               "  <description>\n";
+               "  <Snippet maxLines=\"8\">\n";
+
        static final String kml_header_end =
-               "  </description>\n" +
-               "  <open>0</open>\n";
-
-       static final String kml_style_start =
-               "  <Style id=\"ao-flightstate-%s\">\n" +
-               "    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
-               "    <BalloonStyle>\n" +
-               "      <text>\n";
-
-       static final String kml_style_end =
-               "      </text>\n" +
-               "    </BalloonStyle>\n" +
-               "  </Style>\n";
-
-       static final String kml_placemark_start =
-               "  <Placemark>\n" +
-               "    <name>%s</name>\n" +
-               "    <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
-               "    <LineString>\n" +
-               "      <tessellate>1</tessellate>\n" +
-               "      <altitudeMode>absolute</altitudeMode>\n" +
-               "      <coordinates>\n";
+               "  </Snippet>\n" +
+               "  <open>1</open>\n";
+
+       static final String kml_folder_start =
+               "  <Folder>\n" +
+               "    <name>%s</name>\n";
+
+       static final String kml_path_style_start =
+               "    <Style id=\"ao-style-%s\">\n" +
+               "      <LineStyle><color>%s</color><width>8</width></LineStyle>\n" +
+               "      <BalloonStyle>\n" +
+               "        <text>\n";
+
+       static final String kml_path_style_end =
+               "        </text>\n" +
+               "      </BalloonStyle>\n" +
+               "    </Style>\n";
+
+       static final String kml_point_style_start =
+               "    <Style id=\"ao-style-%s\">\n" +
+               "      <LabelStyle><color>%s</color></LabelStyle>\n" +
+               "      <IconStyle><color>%s</color></IconStyle>\n" +
+               "      <BalloonStyle>\n" +
+               "        <text>\n";
+
+       static final String kml_point_style_end =
+               "        </text>\n" +
+               "      </BalloonStyle>\n" +
+               "    </Style>\n";
+
+       static final String kml_path_start =
+               "    <Placemark>\n" +
+               "      <name>%s</name>\n" +
+               "      <styleUrl>#ao-style-%s</styleUrl>\n" +
+               "      <LineString>\n" +
+               "        <tessellate>1</tessellate>\n" +
+               "        <altitudeMode>absolute</altitudeMode>\n" +
+               "        <coordinates>\n";
 
        static final String kml_coord_fmt =
-       "        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+       "          %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
 
-       static final String kml_placemark_end =
-               "      </coordinates>\n" +
-               "    </LineString>\n" +
-               "  </Placemark>\n";
+       static final String kml_path_end =
+               "        </coordinates>\n" +
+               "      </LineString>\n" +
+               "    </Placemark>\n";
+
+       static final String kml_point_start =
+               "    <Placemark>\n" +
+               "      <name>%s</name>\n" +
+               "      <styleUrl>#ao-style-%s</styleUrl>\n" +
+               "      <Point>\n" +
+               "        <tessellate>1</tessellate>\n" +
+               "        <altitudeMode>absolute</altitudeMode>\n" +
+               "        <coordinates>\n";
+
+       static final String kml_point_end =
+               "        </coordinates>\n" +
+               "      </Point>\n" +
+               "    </Placemark>\n";
+
+       static final String kml_folder_end =
+               "  </Folder>\n";
 
        static final String kml_footer =
                "</Document>\n" +
                "</kml>\n";
 
-       void start (AltosCalData cal_data) {
+       void start () {
                AltosGPS gps = cal_data.gps_pad;
 
                gps_start_altitude = cal_data.gps_pad_altitude;
                out.printf(kml_header_start, cal_data.flight, cal_data.serial);
-               out.printf("Date:   %04d-%02d-%02d\n",
+               out.printf("Product: %s\n", stats.product);
+               out.printf("Firmware: %s\n", stats.firmware_version);
+               out.printf("Date: %04d-%02d-%02d\n",
                           gps.year, gps.month, gps.day);
-               out.printf("Time:     %2d:%02d:%02d\n",
+               out.printf("Time: %2d:%02d:%02d\n",
                           gps.hour, gps.minute, gps.second);
+               if (stats.max_height != AltosLib.MISSING)
+                       out.printf("Max baro height: %s\n", AltosConvert.height.show(6, stats.max_height));
+               if (stats.max_gps_height != AltosLib.MISSING)
+                       out.printf("Max GPS Height: %s\n", AltosConvert.height.show(6, stats.max_gps_height));
+               if (stats.max_speed != AltosLib.MISSING)
+                       out.printf("Max speed: %s\n", AltosConvert.speed.show(6, stats.max_speed));
+               if (stats.max_acceleration != AltosLib.MISSING)
+                       out.printf("Max accel: %s\n", AltosConvert.accel.show(6, stats.max_acceleration));
                out.printf("%s", kml_header_end);
        }
 
-       boolean started = false;
+       void folder_start(String folder_name) {
+               out.printf(kml_folder_start, folder_name);
+       }
+
+       void folder_end() {
+               out.printf(kml_folder_end);
+       }
+
+       void path_style_start(String style, String color) {
+               out.printf(kml_path_style_start, style, color);
+       }
+
+       void path_style_end() {
+               out.printf(kml_path_style_end);
+       }
 
-       void state_start(int state) {
-               String  state_name = AltosLib.state_name(state);
-               String  state_color = state_color(state);
-               out.printf(kml_style_start, state_name, state_color);
-               out.printf("State: %s\n", state_name);
-               out.printf("Time: %6.2f s\n", stats.state_time[state]);
-               out.printf("Average speed: %s\n", AltosConvert.speed.show(6, stats.state_speed[state]));
-               out.printf("Average accel: %s\n", AltosConvert.accel.show(6, stats.state_accel[state]));
-               out.printf("%s", kml_style_end);
-               out.printf(kml_placemark_start, state_name, state_name);
+       void point_style_start(String style, String color) {
+               out.printf(kml_point_style_start, style, color, color);
        }
 
-       void state_end() {
-               out.printf("%s", kml_placemark_end);
+       void point_style_end() {
+               out.printf(kml_point_style_end);
        }
 
-       void coord(double time, AltosGPS gps, int state, double height) {
-               double          altitude;
+       void path_start(String name, String style) {
+               out.printf(kml_path_start, name, style);
+       }
+
+       void path_end() {
+               out.printf(kml_path_end);
+       }
+
+       void point_start(String name, String style) {
+               out.printf(kml_point_start, name, style);
+       }
+
+       void point_end() {
+               out.printf(kml_point_end);
+       }
+
+       boolean started = false;
+
+       private double baro_altitude(AltosFlightSeries series, double time) {
+               double height = series.value(AltosFlightSeries.height_name, time);
+
+               if (height == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               if (cal_data.gps_pad_altitude == AltosLib.MISSING)
+                       return AltosLib.MISSING;
 
-               if (height != AltosLib.MISSING)
-                       altitude = height + gps_start_altitude;
-               else
-                       altitude = gps.alt;
+               return height + cal_data.gps_pad_altitude;
+       }
+
+       void coord(double time, AltosGPS gps, double altitude) {
                out.printf(kml_coord_fmt,
                           gps.lon, gps.lat,
                           altitude, (double) gps.alt,
@@ -150,48 +236,111 @@ public class AltosKML implements AltosWriter {
        }
 
        public void close() {
-               if (prev != null) {
-                       state_end();
-                       end();
-                       prev = null;
-               }
                if (out != null) {
                        out.close();
                        out = null;
                }
        }
 
-       public void write(AltosGPSTimeValue gtv, AltosCalData cal_data, int state, double height) {
-               AltosGPS gps = gtv.gps;
+       public void write(AltosGPS gps, double alt)
+       {
+               if (gps == null)
+                       return;
                if (gps.lat == AltosLib.MISSING)
                        return;
                if (gps.lon == AltosLib.MISSING)
                        return;
-               if (state != flight_state) {
-                       flight_state = state;
-                       if (prev != null) {
-                               coord(gtv.time, gps, state, height);
-                               state_end();
-                       }
-                       state_start(state);
+               if (alt == AltosLib.MISSING) {
+                       alt = cal_data.gps_pad_altitude;
+                       if (alt == AltosLib.MISSING)
+                               return;
                }
-               coord(0, gps, state, height);
+               coord(0, gps, alt);
                prev = gps;
        }
 
-       private int state(AltosFlightSeries series, double time) {
-               return (int) series.value_before(AltosFlightSeries.state_name, time);
-       }
+       public void write_point(AltosTimeValue tv, boolean is_gps) {
+               int             state = (int) tv.value;
+               String          style_prefix = is_gps ? "gps-" : "baro-";
+               String          state_name = AltosLib.state_name(state);
+               String          state_label = AltosLib.state_name_capital(state);
+               String          style_name = style_prefix + state_name;
+               String          folder_name = is_gps ? "GPS" : "Baro";
+               String          full_name = state_label + " (" + folder_name + ")";
+               AltosGPS        gps = series.gps_before(tv.time);
+               double          altitude = is_gps ? gps.alt : baro_altitude(series, tv.time);
 
-       private double height(AltosFlightSeries series, double time) {
-               return series.value(AltosFlightSeries.height_name, time);
+               point_style_start(style_name, state_color(state));
+               out.printf("%s\n", full_name);
+               switch (state) {
+               case AltosLib.ao_flight_boost:
+                       out.printf("Max accel %s\n", AltosConvert.accel.show(6, stats.max_acceleration));
+                       out.printf("Max speed %s\n", AltosConvert.speed.show(6, stats.max_speed));
+                       break;
+               case AltosLib.ao_flight_coast:
+               case AltosLib.ao_flight_fast:
+                       out.printf("Entry speed %s\n", AltosConvert.speed.show(6, stats.state_enter_speed[state]));
+                       out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude));
+                       break;
+               case AltosLib.ao_flight_drogue:
+                       out.printf("Max height %s\n", AltosConvert.height.show(6, is_gps ? stats.max_gps_height : stats.max_height));
+                       out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state]));
+                       break;
+               case AltosLib.ao_flight_main:
+                       out.printf("Entry speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state]));
+                       out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude));
+                       out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state]));
+                       break;
+               case AltosLib.ao_flight_landed:
+                       out.printf("Landing speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state]));
+                       break;
+               }
+               point_style_end();
+               point_start(full_name, style_name);
+               gps = series.gps_before(tv.time);
+               write(gps, altitude);
+               point_end();
        }
 
        public void write(AltosFlightSeries series) {
+               this.series = series;
+               series.finish();
                stats = new AltosFlightStats(series);
-               start(series.cal_data());
+               cal_data = series.cal_data();
+               start();
+               if (series.height_series != null) {
+                       folder_start("Barometric Altitude");
+                       path_style_start("baro", style_color(0));
+                       out.printf("Barometric Altitude\n");
+                       out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height));
+                       path_style_end();
+                       path_start("Barometric Altitude", "baro");
+                       for (AltosGPSTimeValue gtv : series.gps_series)
+                               write(gtv.gps, baro_altitude(series, gtv.time));
+                       path_end();
+                       if (series.state_series != null) {
+                               for (AltosTimeValue tv : series.state_series) {
+                                       write_point(tv, false);
+                               }
+                       }
+                       folder_end();
+               }
+               folder_start("GPS Altitude");
+               path_style_start("gps", style_color(1));
+               out.printf("GPS Altitude");
+               out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_gps_height));
+               path_style_end();
+               path_start("GPS Altitude", "gps");
                for (AltosGPSTimeValue gtv : series.gps_series)
-                       write(gtv, series.cal_data(), state(series, gtv.time), height(series, gtv.time));
+                       write(gtv.gps, gtv.gps.alt);
+               path_end();
+               if (series.state_series != null) {
+                       for (AltosTimeValue tv : series.state_series) {
+                               write_point(tv, true);
+                       }
+               }
+               folder_end();
+               end();
        }
 
        public AltosKML(File in_name) throws FileNotFoundException {
index d1063509b2d4e1efda7ebfce2a1eca76032d6200..c25a6273136c095b5b945fe71946631a7d393b25 100644 (file)
@@ -363,6 +363,7 @@ public class AltosLib {
        public static final int AO_LOG_FORMAT_TELEMINI3 = 12;
        public static final int AO_LOG_FORMAT_TELEFIRETWO = 13;
        public static final int AO_LOG_FORMAT_EASYMINI2 = 14;
+       public static final int AO_LOG_FORMAT_TELEMEGA_3 = 15;
        public static final int AO_LOG_FORMAT_NONE = 127;
 
        public static boolean isspace(int c) {
@@ -587,7 +588,11 @@ public class AltosLib {
        }
 
        public static String igniter_name(int i) {
-               return String.format("Ignitor %c", 'A' + i);
+               return String.format("Igniter %c", 'A' + i);
+       }
+
+       public static String igniter_short_name(int i) {
+               return String.format("igniter_%c", 'a' + i);
        }
 
        public static AltosRecordSet record_set(File file) throws FileNotFoundException, IOException {
index 5413de9dea7740fcaf56dcc2a19450d416c54f41..829a1a63f90070d88baa4cb2659da0bb35f90825 100644 (file)
@@ -355,7 +355,8 @@ public abstract class AltosLink implements Runnable {
        public int telemetry_rate = -1;
        public double frequency;
        public String callsign;
-       AltosConfigData config_data;
+       private AltosConfigData config_data_local;
+       private AltosConfigData config_data_remote;
 
        private Object config_data_lock = new Object();
 
@@ -390,7 +391,7 @@ public abstract class AltosLink implements Runnable {
 
        public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException {
                frequency = in_frequency;
-               config_data();
+               AltosConfigData config_data = config_data();
                set_radio_frequency(frequency,
                                    config_data.radio_frequency > 0,
                                    config_data.radio_setting > 0,
@@ -446,11 +447,24 @@ public abstract class AltosLink implements Runnable {
 
        public AltosConfigData config_data() throws InterruptedException, TimeoutException {
                synchronized(config_data_lock) {
-                       if (config_data == null) {
-                               printf("m 0\n");
-                               config_data = new AltosConfigData(this);
-                               if (monitor_mode)
-                                       set_monitor(true);
+                       AltosConfigData config_data;
+
+                       if (remote) {
+                               if (config_data_remote == null) {
+                                       printf("m 0\n");
+                                       config_data_remote = new AltosConfigData(this);
+                                       if (monitor_mode)
+                                               set_monitor(true);
+                               }
+                               config_data = config_data_remote;
+                       } else {
+                               if (config_data_local == null) {
+                                       printf("m 0\n");
+                                       config_data_local = new AltosConfigData(this);
+                                       if (monitor_mode)
+                                               set_monitor(true);
+                               }
+                               config_data = config_data_local;
                        }
                        return config_data;
                }
@@ -551,14 +565,23 @@ public abstract class AltosLink implements Runnable {
        }
 
        public boolean has_monitor_battery() {
-               return config_data.has_monitor_battery();
+               try {
+                       return config_data().has_monitor_battery();
+               } catch (InterruptedException ie) {
+                       return false;
+               } catch (TimeoutException te) {
+                       return false;
+               }
        }
 
        public double monitor_battery() throws InterruptedException {
-               int monitor_batt = AltosLib.MISSING;
+               double  volts = AltosLib.MISSING;
 
-               if (config_data.has_monitor_battery()) {
-                       try {
+               try {
+                       AltosConfigData config_data = config_data();
+                       int monitor_batt = AltosLib.MISSING;
+
+                       if (config_data.has_monitor_battery()) {
                                String[] items = adc();
                                for (int i = 0; i < items.length;) {
                                        if (items[i].equals("batt")) {
@@ -568,19 +591,17 @@ public abstract class AltosLink implements Runnable {
                                        }
                                        i++;
                                }
-                       } catch (TimeoutException te) {
                        }
-               }
-               if (monitor_batt == AltosLib.MISSING)
-                       return AltosLib.MISSING;
+                       if (monitor_batt != AltosLib.MISSING) {
+                               if (config_data.product.startsWith("TeleBT-v3") || config_data.product.startsWith("TeleBT-v4")) {
+                                       volts = AltosConvert.tele_bt_3_battery(monitor_batt);
+                               } else {
+                                       volts = AltosConvert.cc_battery_to_voltage(monitor_batt);
+                               }
+                       }
 
-               double  volts = AltosLib.MISSING;
-               if (config_data.product.startsWith("TeleBT-v3") || config_data.product.startsWith("TeleBT-v4")) {
-                       volts = AltosConvert.tele_bt_3_battery(monitor_batt);
-               } else {
-                       volts = AltosConvert.cc_battery_to_voltage(monitor_batt);
+               } catch (TimeoutException te) {
                }
-
                return volts;
        }
 
index 24b425b78a2bc797f93cf77bdd6b405d1d318f58..fab28cac3cddeec78dde18ef1a6020ae39d10365 100644 (file)
@@ -31,7 +31,7 @@ class AltosReplay extends AltosDataListener implements Runnable {
        AltosState      state;
        AltosRecordSet  record_set;
        double          last_time = AltosLib.MISSING;
-       Semaphore       semaphore = new Semaphore(1);;
+       Semaphore       semaphore = new Semaphore(1);
        boolean         done = false;
 
        public void set_time(double time) {
@@ -70,7 +70,7 @@ class AltosReplay extends AltosDataListener implements Runnable {
        public void set_apogee_voltage(double volts) { state.set_apogee_voltage(volts); }
        public void set_main_voltage(double volts) { state.set_main_voltage(volts); }
 
-       public void set_gps(AltosGPS gps) { state.set_gps(gps); }
+       public void set_gps(AltosGPS gps) { super.set_gps(gps); state.set_gps(gps); }
 
        public void set_orient(double orient) { state.set_orient(orient); }
        public void set_gyro(double roll, double pitch, double yaw) { state.set_gyro(roll, pitch, yaw); }
index 39ab10da14c9c78bafee2156b7b3097b6ac80a71..68097faf8bb6b589d600b61adfd4d9e6ae0b4df3 100644 (file)
@@ -480,7 +480,7 @@ public class AltosState extends AltosDataListener {
        class AltosPressure extends AltosValue {
                void set(double p, double time) {
                        super.set(p, time);
-                       if (state == AltosLib.ao_flight_pad)
+                       if (state() == AltosLib.ao_flight_pad)
                                ground_pressure.set_filtered(p, time);
                        double a = pressure_to_altitude(p);
                        altitude.set_computed(a, time);
@@ -557,7 +557,7 @@ public class AltosState extends AltosDataListener {
        class AltosSpeed extends AltosCValue {
 
                boolean can_max() {
-                       return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless;
+                       return state() < AltosLib.ao_flight_fast || state() == AltosLib.ao_flight_stateless;
                }
 
                void set_accel() {
@@ -615,7 +615,7 @@ public class AltosState extends AltosDataListener {
        class AltosAccel extends AltosCValue {
 
                boolean can_max() {
-                       return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless;
+                       return state() < AltosLib.ao_flight_fast || state() == AltosLib.ao_flight_stateless;
                }
 
                void set_measured(double a, double time) {
@@ -712,11 +712,11 @@ public class AltosState extends AltosDataListener {
        }
 
        public void init() {
+               super.init();
+
                set = 0;
 
                received_time = System.currentTimeMillis();
-               time = AltosLib.MISSING;
-               state = AltosLib.ao_flight_invalid;
                landed = false;
                boost = false;
                rssi = AltosLib.MISSING;
@@ -819,9 +819,9 @@ public class AltosState extends AltosDataListener {
 
                if (gps.locked && gps.nsat >= 4) {
                        /* Track consecutive 'good' gps reports, waiting for 10 of them */
-                       if (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_stateless) {
+                       if (state() == AltosLib.ao_flight_pad || state() == AltosLib.ao_flight_stateless) {
                                set_npad(npad+1);
-                               if (pad_lat != AltosLib.MISSING && (npad < 10 || state == AltosLib.ao_flight_pad)) {
+                               if (pad_lat != AltosLib.MISSING && (npad < 10 || state() == AltosLib.ao_flight_pad)) {
                                        pad_lat = (pad_lat * 31 + gps.lat) / 32;
                                        pad_lon = (pad_lon * 31 + gps.lon) / 32;
                                        gps_ground_altitude.set_filtered(gps.alt, time);
@@ -859,24 +859,14 @@ public class AltosState extends AltosDataListener {
        }
 
        public String state_name() {
-               return AltosLib.state_name(state);
+               return AltosLib.state_name(state());
        }
 
        public void set_state(int state) {
-               if (state != AltosLib.ao_flight_invalid) {
-                       this.state = state;
-                       ascent = (AltosLib.ao_flight_boost <= state &&
-                                 state <= AltosLib.ao_flight_coast);
-                       boost = (AltosLib.ao_flight_boost == state);
-               }
-       }
-
-       public int state() {
-               return state;
-       }
-
-       private void re_init() {
-               init();
+               super.set_state(state);
+               ascent = (AltosLib.ao_flight_boost <= state() &&
+                         state() <= AltosLib.ao_flight_coast);
+               boost = (AltosLib.ao_flight_boost == state());
        }
 
        public int rssi() {
@@ -897,6 +887,7 @@ public class AltosState extends AltosDataListener {
        }
 
        public void set_gps(AltosGPS gps) {
+               super.set_gps(gps);
                if (gps != null) {
                        this.gps = gps;
                        update_gps();
index f17e11717c391410fd222148b4e6733165c45ed0..a374519d41c50d34508fb6dc1971ae37ba763b4c 100644 (file)
@@ -28,8 +28,11 @@ public abstract class AltosTelemetry implements AltosDataProvider {
        int[]   bytes;
 
        /* All telemetry packets have these fields */
-       public int rssi() { return AltosConvert.telem_to_rssi(AltosLib.int8(bytes, bytes.length - 3)); }
-       public int status() { return AltosLib.uint8(bytes, bytes.length - 2); }
+       static public int rssi(int[] bytes) { return AltosConvert.telem_to_rssi(AltosLib.int8(bytes, bytes.length - 3)); }
+       static public int status(int[] bytes) { return AltosLib.uint8(bytes, bytes.length - 2); }
+
+       public int rssi() { return rssi(bytes); }
+       public int status() { return status(bytes); }
 
        /* All telemetry packets report these fields in some form */
        public abstract int serial();
@@ -51,7 +54,7 @@ public abstract class AltosTelemetry implements AltosDataProvider {
 
        public void provide_data(AltosDataListener listener) {
                listener.set_serial(serial());
-               if (listener.state == AltosLib.ao_flight_invalid)
+               if (listener.state() == AltosLib.ao_flight_invalid)
                        listener.set_state(AltosLib.ao_flight_startup);
                if (frequency != AltosLib.MISSING)
                        listener.set_frequency(frequency);
@@ -96,6 +99,9 @@ public abstract class AltosTelemetry implements AltosDataProvider {
                if (!cksum(bytes))
                        throw new ParseException(String.format("invalid line \"%s\"", hex), 0);
 
+               if ((status(bytes) & PKT_APPEND_STATUS_1_CRC_OK) == 0)
+                       throw new AltosCRCException(rssi(bytes));
+
                /* length, data ..., rssi, status, checksum -- 4 bytes extra */
                switch (bytes.length) {
                case AltosLib.ao_telemetry_standard_len + 4:
index ea3074429c2cf4989e6e60e1668e90c255664a3a..c8026a8353923535b364e3d769944f5305f80926 100644 (file)
@@ -40,7 +40,7 @@ public class AltosTelemetryConfiguration extends AltosTelemetryStandard {
 
                AltosCalData cal_data = listener.cal_data();
 
-               cal_data.set_device_type(device_type());
+               listener.set_device_type(device_type());
                cal_data.set_flight(flight());
                cal_data.set_config(config_major(), config_minor(), flight_log_max());
                if (device_type() == AltosLib.product_telegps)
index 135b028447bb6ac49bf85ccbce1b6ea33cf27be4..e51455f8bb8c00cd4dabb62aa134276942e2e5f9 100644 (file)
@@ -128,7 +128,7 @@ public class AltosTelemetryFile implements AltosRecordSet {
                        /* Try to pick up at least one pre-boost value */
                        if (cal_data.time() >= -2)
                                telem.provide_data(listener);
-                       if (listener.state == AltosLib.ao_flight_landed)
+                       if (listener.state() == AltosLib.ao_flight_landed)
                                break;
                }
                listener.finish();
index f4366e33a3116ada1f71104dc4854dce701e1cad..e2925a58c165caf6e534b4c729b8996547e56ff0 100644 (file)
@@ -54,7 +54,7 @@ public class AltosTelemetryLocation extends AltosTelemetryStandard {
 
                AltosCalData    cal_data = listener.cal_data();
 
-               AltosGPS        gps = cal_data.make_temp_gps(tick(), false);
+               AltosGPS        gps = listener.make_temp_gps(false);
 
                int flags = flags();
                gps.nsat = flags & 0xf;
@@ -77,12 +77,7 @@ public class AltosTelemetryLocation extends AltosTelemetryStandard {
                        gps.ground_speed = ground_speed() * 1.0e-2;
                        gps.course = course() * 2;
                        gps.climb_rate = climb_rate() * 1.0e-2;
-
-                       if (gps.nsat >= 4)
-                               cal_data.set_gps(gps);
                }
                listener.set_gps(gps);
-               cal_data.set_gps(gps);
-               cal_data.reset_temp_gps();
        }
 }
index 7ef9c63759fd0e00ff70823903837c9e162973f0..f5961c8c03c87443c946fdf94615ba4b7e7cc701 100644 (file)
@@ -24,7 +24,9 @@ public class AltosTelemetryMegaData extends AltosTelemetryStandard {
 
        int     v_batt() { return int16(6); }
        int     v_pyro() { return int16(8); }
-       int     sense(int i) { int v = uint8(10+i); return v << 4 | v >> 8; }
+
+       /* pyro sense values are sent in 8 bits, expand to 12 bits */
+       int     sense(int i) { int v = uint8(10+i); return (v << 4) | (v >> 4); }
 
        int     ground_pres() { return int32(16); }
        int     ground_accel() { return int16(20); }
index 26fe4f26c38823584307d1b861637b7b0b105431..8fb61a4fe32490cbc4a31a6f16dbb71f33d0f643 100644 (file)
@@ -41,19 +41,15 @@ public class AltosTelemetryReader extends AltosFlightReader {
                                throw new IOException("IO error");
                } while (!link.get_monitor());
                AltosTelemetry  telem = AltosTelemetry.parse(l.line);
-               if (state == null) {
-                       System.out.printf("Make state\n");
+               if (state == null)
                        state = new AltosState(cal_data());
-               }
                telem.provide_data(state);
                return state;
        }
 
        public AltosCalData cal_data() {
-               if (cal_data == null) {
-                       System.out.printf("Make cal data\n");
+               if (cal_data == null)
                        cal_data = new AltosCalData();
-               }
                return cal_data;
        }
 
index 60bc4a51db41ba15cbb4ddcc1a1333094b6239bc..0965df9fec8df6c3c42a96267c1b9d0512fd2ff1 100644 (file)
@@ -49,10 +49,9 @@ public class AltosTelemetrySatellite extends AltosTelemetryStandard {
 
                AltosCalData    cal_data = listener.cal_data();
 
-               AltosGPS        gps = cal_data.make_temp_gps(tick(), true);
+               AltosGPS        gps = listener.make_temp_gps(true);
 
                gps.cc_gps_sat = sats();
                listener.set_gps(gps);
-               cal_data.reset_temp_gps();
        }
 }
index 9f3b4d807ef26bb36ae9a358515ac41c17f3bad5..c6a780a31a6e41023a8ceaccb5799b85ad287b71 100644 (file)
@@ -20,15 +20,30 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt
        public String                   label;
        public AltosUnits               units;
        ArrayList<AltosTimeValue>       values;
+       boolean                         data_changed;
 
        public int compareTo(AltosTimeSeries other) {
                return label.compareTo(other.label);
        }
 
        public void add(AltosTimeValue tv) {
+               data_changed = true;
                values.add(tv);
        }
 
+       public void erase_values() {
+               data_changed = true;
+               this.values = new ArrayList<AltosTimeValue>();
+       }
+
+       public void clear_changed() {
+               data_changed = false;
+       }
+
+//     public boolean changed() {
+//             return data_changed;
+//     }
+
        public void add(double time, double value) {
                add(new AltosTimeValue(time, value));
        }
@@ -264,14 +279,35 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt
 
        }
 
-       private double filter_coeff(double dist, double width) {
-               double ratio = dist / (width / 2);
+       private static double i0(double x) {
+               double  ds = 1, d = 0, s = 0;
 
-               return Math.cos(ratio * Math.PI / 2);
+               do {
+                       d += 2;
+                       ds = ds * (x * x) / (d * d);
+                       s += ds;
+               } while (ds - 0.2e-8 * s > 0);
+               return s;
+       }
+
+       private static double kaiser(double n, double m, double beta) {
+               double alpha = m / 2;
+               double t = (n - alpha) / alpha;
+
+               if (t > 1 || t < -1)
+                       t = 1;
+               double k = i0 (beta * Math.sqrt (1 - t*t)) / i0(beta);
+               return k;
+       }
+
+       private double filter_coeff(double dist, double width) {
+               return kaiser(dist + width/2.0, width, 2 * Math.PI);
        }
 
        public AltosTimeSeries filter(AltosTimeSeries f, double width) {
+
                double  half_width = width/2;
+               int half_point = values.size() / 2;
                for (int i = 0; i < values.size(); i++) {
                        double  center_time = values.get(i).time;
                        double  left_time = center_time - half_width;
index 08af9496e00199f32226024da1f35049142cef25..2a1cb8e4763810847382f799f32f5a17486a2144 100644 (file)
@@ -55,6 +55,7 @@ altoslib_JAVA = \
        AltosEepromList.java \
        AltosEepromLog.java \
        AltosFile.java \
+       AltosFilterListener.java \
        AltosFlash.java \
        AltosFlashListener.java \
        AltosDataListener.java \
index 042f9277c2cf40e8335d9b46d9f5bda727b7c9e1..f387ed9bcceab91f8fda37c78a24393104537b2f 100644 (file)
@@ -31,7 +31,7 @@ import org.jfree.chart.ChartPanel;
 import org.jfree.chart.JFreeChart;
 import org.jfree.ui.RefineryUtilities;
 
-public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener
+public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener
 {
        JTabbedPane             pane;
        AltosGraph              graph;
@@ -82,6 +82,23 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt
                        enable.units_changed(imperial_units);
        }
 
+       AltosUIFlightSeries flight_series;
+
+       public void filter_changed(double speed_filter, double accel_filter) {
+               flight_series.set_filter(speed_filter, accel_filter);
+               graph.filter_changed();
+               stats = new AltosFlightStats(flight_series);
+               statsTable.filter_changed(stats);
+       }
+
+       public double speed_filter() {
+               return flight_series.speed_filter_width;
+       }
+
+       public double accel_filter() {
+               return flight_series.accel_filter_width;
+       }
+
        AltosGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException {
                super(file.getName());
                AltosCalData    cal_data = set.cal_data();
@@ -89,9 +106,9 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt
 
                pane = new JTabbedPane();
 
-               enable = new AltosUIEnable();
+               flight_series = new AltosUIFlightSeries(cal_data);
 
-               AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data);
+               enable = new AltosUIEnable(this);
 
                set.capture_series(flight_series);
 
index a2696f1518433f57cb541620be94b8f52a3d1a40..584f143a9d112f17f6e6ea80b8b8d5b534feed92 100644 (file)
@@ -295,7 +295,7 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl
                pack();
                setVisible(true);
 
-               thread = new AltosIdleMonitor((AltosIdleMonitorListener) this, link, (boolean) remote);
+               thread = new AltosIdleMonitor(this, link, (boolean) remote);
 
                status_update = new AltosFlightStatusUpdate(flightStatus);
 
index bc8eaa7125ec5515ba0ae55fb564f9bac6b1c3a9..02e49a94a82954412d4212730776b3cdceab8362 100644 (file)
@@ -26,7 +26,7 @@ import java.util.concurrent.*;
 import org.altusmetrum.altoslib_12.*;
 import org.altusmetrum.altosuilib_12.*;
 
-public class AltosUI extends AltosUIFrame {
+public class AltosUI extends AltosUIFrame implements AltosEepromGrapher {
        public AltosVoice voice = new AltosVoice();
 
        public static boolean load_library(Frame frame) {
@@ -320,8 +320,17 @@ public class AltosUI extends AltosUIFrame {
        /* Connect to TeleMetrum, either directly or through
         * a TeleDongle over the packet link
         */
+
+       public void graph_flights(AltosEepromList flights) {
+               for (AltosEepromLog flight : flights) {
+                       if (flight.graph_selected && flight.file != null) {
+                               process_graph(flight.file);
+                       }
+               }
+       }
+
        private void SaveFlightData() {
-               new AltosEepromManage(AltosUI.this, AltosLib.product_any);
+               new AltosEepromManage(this, this, AltosLib.product_any);
        }
 
        private static AltosFlightSeries make_series(AltosRecordSet set) {
index 3fcc02dac353bba782fb15b85218c69d7b20fcd3..5e691ac4c47683bb603ac163f28c4665f2206b2e 100644 (file)
@@ -159,9 +159,6 @@ public class AltosDisplayThread extends Thread {
                                        report(false);
                                }
                        } catch (InterruptedException ie) {
-                               try {
-                                       voice.drain();
-                               } catch (InterruptedException iie) { }
                        }
                }
 
index 87e80a51a75001a90d4d137075d5b0a4a522c04e..d7dde6df42864709eacf4a61567457d2b21fd524 100644 (file)
@@ -84,7 +84,7 @@ public class AltosEepromDelete implements Runnable {
                                serial_line.start_remote();
 
                        for (AltosEepromLog log : flights) {
-                               if (log.selected) {
+                               if (log.delete_selected) {
                                        DeleteLog(log);
                                }
                        }
diff --git a/altosuilib/AltosEepromGrapher.java b/altosuilib/AltosEepromGrapher.java
new file mode 100644 (file)
index 0000000..a29f64e
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+package org.altusmetrum.altosuilib_12;
+
+import org.altusmetrum.altoslib_12.*;
+
+public interface AltosEepromGrapher {
+
+       public void graph_flights(AltosEepromList list);
+}
index 93827139d0af83507e23644cb20f266eaa0101f3..1adf1f0a98d97d570aee0721a9a724547bfe59b1 100644 (file)
@@ -33,6 +33,7 @@ public class AltosEepromManage implements ActionListener {
        AltosEepromList         flights;
        AltosEepromDownload     download;
        AltosEepromDelete       delete;
+       AltosEepromGrapher      grapher;
 
        public void finish() {
                if (serial_line != null) {
@@ -48,7 +49,7 @@ public class AltosEepromManage implements ActionListener {
        private int countDeletedFlights() {
                int count = 0;
                for (AltosEepromLog flight : flights) {
-                       if (flight.selected)
+                       if (flight.delete_selected)
                                count++;
                }
                return count;
@@ -58,7 +59,7 @@ public class AltosEepromManage implements ActionListener {
                String  result = "";
 
                for (AltosEepromLog flight : flights) {
-                       if (flight.selected) {
+                       if (flight.delete_selected) {
                                if (result.equals(""))
                                        result = String.format("%d", flight.flight);
                                else
@@ -68,38 +69,49 @@ public class AltosEepromManage implements ActionListener {
                return result;
        }
 
-       public boolean download_done() {
-               AltosEepromSelect       select = new AltosEepromSelect(frame, flights, "Delete");
-
-               if (select.run()) {
-                       boolean any_selected = false;
-                       for (AltosEepromLog flight : flights)
-                               any_selected = any_selected || flight.selected;
-                       if (any_selected) {
-                               delete = new AltosEepromDelete(frame,
-                                                              serial_line,
-                                                              remote,
-                                                              flights);
-                               delete.addActionListener(this);
-                               /*
-                                * Start flight log delete
-                                */
-
-                               delete.start();
-                               return true;
-                       }
+       public boolean delete_start() {
+
+               boolean any_selected = false;
+               for (AltosEepromLog flight : flights)
+                       any_selected = any_selected || flight.delete_selected;
+               if (any_selected) {
+                       delete = new AltosEepromDelete(frame,
+                                                      serial_line,
+                                                      remote,
+                                                      flights);
+                       delete.addActionListener(this);
+                       /*
+                        * Start flight log delete
+                        */
+
+                       delete.start();
+                       return true;
                }
                return false;
        }
 
+       public void graph_start() {
+               boolean any_selected = false;
+               for (AltosEepromLog flight : flights) {
+                       if (!flight.download_selected)
+                               flight.graph_selected = false;
+                       any_selected = any_selected || flight.graph_selected;
+               }
+               if (any_selected && grapher != null)
+                       grapher.graph_flights(flights);
+       }
+
        public void actionPerformed(ActionEvent e) {
                String  cmd = e.getActionCommand();
                boolean success = e.getID() != 0;
                boolean running = false;
 
                if (cmd.equals("download")) {
-                       if (success)
-                               running = download_done();
+                       if (success) {
+                               running = delete_start();
+                               if (!running)
+                                       graph_start();
+                       }
                } else if (cmd.equals("delete")) {
                        if (success) {
                                JOptionPane.showMessageDialog(frame,
@@ -108,6 +120,7 @@ public class AltosEepromManage implements ActionListener {
                                                                            showDeletedFlights()),
                                                              serial_line.device.toShortString(),
                                                              JOptionPane.INFORMATION_MESSAGE);
+                               graph_start();
                        }
                }
                if (!running)
@@ -126,12 +139,12 @@ public class AltosEepromManage implements ActionListener {
                                                              serial_line.device.toShortString(),
                                                              JOptionPane.INFORMATION_MESSAGE);
                        } else {
-                               AltosEepromSelect       select = new AltosEepromSelect(frame, flights, "Download");
+                               AltosEepromSelect       select = new AltosEepromSelect(frame, flights, grapher != null);
 
                                if (select.run()) {
                                        boolean any_selected = false;
                                        for (AltosEepromLog flight : flights)
-                                               any_selected = any_selected || flight.selected;
+                                               any_selected = any_selected || flight.download_selected;
                                        if (any_selected) {
                                                AltosEepromMonitorUI monitor = new AltosEepromMonitorUI(frame);
                                                monitor.addActionListener(this);
@@ -147,7 +160,9 @@ public class AltosEepromManage implements ActionListener {
                                                download.start();
                                                running = true;
                                        } else {
-                                               running = download_done();
+                                               running = delete_start();
+                                               if (!running)
+                                                       graph_start();
                                        }
                                }
                        }
@@ -205,11 +220,12 @@ public class AltosEepromManage implements ActionListener {
                }
        }
 
-       public AltosEepromManage(JFrame given_frame, int product) {
+       public AltosEepromManage(JFrame given_frame, AltosEepromGrapher grapher, int product) {
 
                //boolean       running = false;
 
                frame = given_frame;
+               this.grapher = grapher;
                device = AltosDeviceUIDialog.show(frame, product);
 
                remote = false;
index 3427fe0fac5f5a8e675f056a2c5c6e3df3295ffb..fc6c95c6e01b9b5b37057e74df9b8f31c955e736 100644 (file)
 
 package org.altusmetrum.altosuilib_12;
 
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import org.altusmetrum.altoslib_12.*;
 
+       class result_holder {
+               static int result;
+       }
+
 public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMonitor {
        JFrame          owner;
        Container       pane;
@@ -32,7 +39,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
        JLabel          file_label;
        JLabel          serial_value;
        JLabel          flight_value;
-       JLabel          file_value;
        JButton         cancel;
        JProgressBar    pbar;
        ActionListener  listener;
@@ -42,6 +48,8 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
        public AltosEepromMonitorUI(JFrame owner) {
                super (owner, "Download Flight Data", false);
 
+               setMinimumSize(new Dimension(600, 100));
+
                this.owner = owner;
 
                GridBagConstraints c;
@@ -85,30 +93,11 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
                flight_value = new JLabel("");
                pane.add(flight_value, c);
 
-               c = new GridBagConstraints();
-               c.fill = GridBagConstraints.NONE;
-               c.gridx = 0; c.gridy = 2;
-               c.anchor = GridBagConstraints.LINE_START;
-               c.insets = il;
-               file_label = new JLabel("File:");
-               pane.add(file_label, c);
-
-               c = new GridBagConstraints();
-               c.fill = GridBagConstraints.HORIZONTAL;
-               c.weightx = 1;
-               c.gridx = 1; c.gridy = 2;
-               c.anchor = GridBagConstraints.LINE_START;
-               c.insets = ir;
-               file_value = new JLabel("");
-               pane.add(file_value, c);
-
                pbar = new JProgressBar();
                pbar.setMinimum(0);
                pbar.setMaximum(progress_max);
-               pbar.setValue(0);
-               pbar.setString("startup");
                pbar.setStringPainted(true);
-               pbar.setPreferredSize(new Dimension(600, 20));
+               set_block_internal(0);
                c = new GridBagConstraints();
                c.fill = GridBagConstraints.HORIZONTAL;
                c.anchor = GridBagConstraints.CENTER;
@@ -118,7 +107,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
                c.insets = ib;
                pane.add(pbar, c);
 
-
                cancel = new JButton("Cancel");
                c = new GridBagConstraints();
                c.fill = GridBagConstraints.NONE;
@@ -141,8 +129,9 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
                final Thread eeprom_thread = in_eeprom_thread;
                cancel.addActionListener(new ActionListener() {
                                public void actionPerformed(ActionEvent e) {
-                                       if (eeprom_thread != null)
+                                       if (eeprom_thread != null) {
                                                eeprom_thread.interrupt();
+                                       }
                                }
                        });
        }
@@ -162,6 +151,7 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
                s = String.format("block %d of %d", block, max_block);
 
                pbar.setString(s);
+               pbar.setStringPainted(true);
                pbar.setValue((int) (pos * progress_max));
        }
 
@@ -216,23 +206,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
                SwingUtilities.invokeLater(r);
        }
 
-       private void set_filename_internal(String filename) {
-               file_value.setText(String.format("%s", filename));
-       }
-
-       public void set_filename(String in_filename) {
-               final String filename = in_filename;
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               set_filename_internal(filename);
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-
        private void done_internal(boolean success) {
                listener.actionPerformed(new ActionEvent(this,
                                                         success ? 1 : 0,
@@ -258,7 +231,6 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
                set_max(1);
                set_block_internal(0);
                set_flight_internal(0);
-               set_filename_internal("");
        }
 
        public void reset() {
@@ -293,6 +265,29 @@ public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMo
                                              joption_message_type);
        }
 
+       public Boolean check_overwrite(File in_file) {
+               final Semaphore check_overwrite_done = new Semaphore(0);
+               final File file = in_file;
+               final result_holder result = new result_holder();
+
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       result_holder.result = JOptionPane.showConfirmDialog(owner,
+                                                                                            String.format("\"%s\" already exists, overwrite?",
+                                                                                                          file.toString()),
+                                                                                            "Overwrite Existing File?",
+                                                                                            JOptionPane.YES_NO_OPTION);
+                                       check_overwrite_done.release();
+                               }
+                       };
+
+               SwingUtilities.invokeLater(r);
+               try {
+                       check_overwrite_done.acquire();
+               } catch (Exception e) {}
+               return result_holder.result == JOptionPane.YES_OPTION;
+       }
+
        public void show_message(String in_message, String in_title, int in_message_type) {
                final String message = in_message;
                final String title = in_title;
index 0c890c8b445846178b1a51af4e3013eb1cd0995d..f88f2bd6ad528713cc358bad57ac4a3d3092973a 100644 (file)
@@ -27,23 +27,35 @@ import org.altusmetrum.altoslib_12.*;
 class AltosEepromItem implements ActionListener {
        AltosEepromLog  log;
        JLabel          label;
-       JCheckBox       action;
+       JCheckBox       download;
        JCheckBox       delete;
+       JCheckBox       graph;
 
        public void actionPerformed(ActionEvent e) {
-               log.selected = action.isSelected();
+               log.download_selected = download.isSelected();
+               log.delete_selected = delete.isSelected();
+               log.graph_selected = graph.isSelected();
        }
 
        public AltosEepromItem(AltosEepromLog in_log) {
                log = in_log;
 
                String  text;
-               text = String.format("Flight #%02d", log.flight);
+               if (log.flight >= 0)
+                       text = String.format("Flight #%02d", log.flight);
+               else
+                       text = String.format("Corrupt #%02d", -log.flight);
 
                label = new JLabel(text);
 
-               action = new JCheckBox("", log.selected);
-               action.addActionListener(this);
+               download = new JCheckBox("", log.download_selected);
+               download.addActionListener(this);
+
+               delete = new JCheckBox("", log.delete_selected);
+               delete.addActionListener(this);
+
+               graph = new JCheckBox("", log.graph_selected);
+               graph.addActionListener(this);
        }
 }
 
@@ -72,7 +84,7 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener {
 
        public AltosEepromSelect (JFrame in_frame,
                                  AltosEepromList flights,
-                                 String action) {
+                                 boolean has_graph) {
 
                super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true);
                frame = in_frame;
@@ -81,7 +93,7 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener {
                Container contentPane = getContentPane();
 
                /* First, we create a pane containing the dialog's header/title */
-               JLabel  selectLabel = new JLabel(String.format ("Select flights to %s", action), SwingConstants.CENTER);
+               JLabel  selectLabel = new JLabel(String.format ("Select flights"), SwingConstants.CENTER);
 
                JPanel  labelPane = new JPanel();
                labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS));
@@ -118,9 +130,31 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener {
                c.weightx = 0.5;
                c.anchor = GridBagConstraints.CENTER;
                c.insets = i;
-               JLabel downloadHeaderLabel = new JLabel(action);
+               JLabel downloadHeaderLabel = new JLabel("Download");
                flightPane.add(downloadHeaderLabel, c);
 
+               /* Delete Header */
+               c = new GridBagConstraints();
+               c.gridx = 2; c.gridy = 0;
+               c.fill = GridBagConstraints.NONE;
+               c.weightx = 0.5;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               JLabel deleteHeaderLabel = new JLabel("Delete");
+               flightPane.add(deleteHeaderLabel, c);
+
+               if (has_graph) {
+                       /* Graph Header */
+                       c = new GridBagConstraints();
+                       c.gridx = 3; c.gridy = 0;
+                       c.fill = GridBagConstraints.NONE;
+                       c.weightx = 0.5;
+                       c.anchor = GridBagConstraints.CENTER;
+                       c.insets = i;
+                       JLabel graphHeaderLabel = new JLabel("Graph");
+                       flightPane.add(graphHeaderLabel, c);
+               }
+
                /* Add the flights to the GridBag */
                AltosEepromItem item;
                int itemNumber = 1;
@@ -139,14 +173,34 @@ public class AltosEepromSelect extends AltosUIDialog implements ActionListener {
                        c.insets = i;
                        flightPane.add(item.label, c);
 
-                       /* Add action checkbox for the flight */
+                       /* Add download checkbox for the flight */
                        c = new GridBagConstraints();
                        c.gridx = 1; c.gridy = itemNumber;
                        c.fill = GridBagConstraints.NONE;
                        c.weightx = 0.5;
                        c.anchor = GridBagConstraints.CENTER;
                        c.insets = i;
-                       flightPane.add(item.action, c);
+                       flightPane.add(item.download, c);
+
+                       /* Add delete checkbox for the flight */
+                       c = new GridBagConstraints();
+                       c.gridx = 2; c.gridy = itemNumber;
+                       c.fill = GridBagConstraints.NONE;
+                       c.weightx = 0.5;
+                       c.anchor = GridBagConstraints.CENTER;
+                       c.insets = i;
+                       flightPane.add(item.delete, c);
+
+                       if (has_graph) {
+                               /* Add graph checkbox for the flight */
+                               c = new GridBagConstraints();
+                               c.gridx = 3; c.gridy = itemNumber;
+                               c.fill = GridBagConstraints.NONE;
+                               c.weightx = 0.5;
+                               c.anchor = GridBagConstraints.CENTER;
+                               c.insets = i;
+                               flightPane.add(item.graph, c);
+                       }
 
                        itemNumber++;
                }
index 415c024484fac4895695c21e2c055034853c23c0..8f7e9bffff69f9786ccfbb44a070e44a8bd0822a 100644 (file)
@@ -38,6 +38,11 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                value[i].setFont(AltosUILib.value_font);
                }
 
+               public void set(String ... values) {
+                       for (int j = 0; j < values.length; j++)
+                               value[j].setText(values[j]);
+               }
+
                public FlightStat(GridBagLayout layout, int y, String label_text, String ... values) {
                        GridBagConstraints      c = new GridBagConstraints();
                        c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
@@ -87,6 +92,43 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                return String.format("%s %4d° %9.6f'", h, deg, min);
        }
 
+       private FlightStat      max_height_stat;
+       private FlightStat      max_speed_stat;
+       private FlightStat      max_accel_stat;
+       private FlightStat      boost_accel_stat;
+       private FlightStat      drogue_descent_stat;
+       private FlightStat      main_descent_stat;
+
+       public void set_values(AltosFlightStats stats) {
+               if (max_height_stat != null && stats.max_height != AltosLib.MISSING) {
+                       max_height_stat.set(String.format("%6.1f m", stats.max_height),
+                                           String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
+               }
+               if (max_speed_stat != null && stats.max_speed != AltosLib.MISSING) {
+                       max_speed_stat.set(String.format("%6.1f m/s", stats.max_speed),
+                                          String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)),
+                                          String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+               }
+               if (max_accel_stat != null && stats.max_acceleration != AltosLib.MISSING) {
+                       max_accel_stat.set(String.format("%6.1f m/s²", stats.max_acceleration),
+                                          String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
+                                          String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration)));
+               }
+               if (boost_accel_stat != null && stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING) {
+                       boost_accel_stat.set(String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]),
+                                            String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])),
+                                            String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost])));
+               }
+               if (drogue_descent_stat != null && stats.state_speed[AltosLib.ao_flight_drogue] != AltosLib.MISSING) {
+                       drogue_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]),
+                                               String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue])));
+               }
+               if (main_descent_stat != null && stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING) {
+                               main_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]),
+                                                     String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main])));
+               }
+       }
+
        public void set_stats(AltosFlightStats stats) {
                int y = 0;
                if (stats.serial != AltosLib.MISSING) {
@@ -113,9 +155,9 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                               String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
                }
                if (stats.max_height != AltosLib.MISSING) {
-                       new FlightStat(layout, y++, "Maximum height",
-                                      String.format("%6.1f m", stats.max_height),
-                                      String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
+                       max_height_stat = new FlightStat(layout, y++, "Maximum height",
+                                                        String.format("%6.1f m", stats.max_height),
+                                                        String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
                }
                if (stats.max_gps_height != AltosLib.MISSING) {
                        new FlightStat(layout, y++, "Maximum GPS height",
@@ -123,21 +165,21 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                       String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_gps_height)));
                }
                if (stats.max_speed != AltosLib.MISSING) {
-                       new FlightStat(layout, y++, "Maximum speed",
-                                      String.format("%6.1f m/s", stats.max_speed),
-                                      String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)),
-                                      String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+                       max_speed_stat = new FlightStat(layout, y++, "Maximum speed",
+                                                       String.format("%6.1f m/s", stats.max_speed),
+                                                       String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)),
+                                                       String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
                }
                if (stats.max_acceleration != AltosLib.MISSING)
-                       new FlightStat(layout, y++, "Maximum boost acceleration",
-                                      String.format("%6.1f m/s²", stats.max_acceleration),
-                                      String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
-                                      String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration)));
+                       max_accel_stat = new FlightStat(layout, y++, "Maximum boost acceleration",
+                                                       String.format("%6.1f m/s²", stats.max_acceleration),
+                                                       String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
+                                                       String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration)));
                if (stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING)
-                       new FlightStat(layout, y++, "Average boost acceleration",
-                                      String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]),
-                                      String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])),
-                                      String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost])));
+                       boost_accel_stat = new FlightStat(layout, y++, "Average boost acceleration",
+                                                         String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]),
+                                                         String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])),
+                                                         String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost])));
                if (stats.state_time[AltosLib.ao_flight_boost] != 0 || stats.state_time[AltosLib.ao_flight_fast] != 0 || stats.state_time[AltosLib.ao_flight_coast] != 0) {
 
                        double  boost_time = stats.state_time[AltosLib.ao_flight_boost];
@@ -167,14 +209,14 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                label = "Descent rate";
                        else
                                label = "Drogue descent rate";
-                       new FlightStat(layout, y++, label,
+                       drogue_descent_stat = new FlightStat(layout, y++, label,
                                       String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]),
                                       String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue])));
                }
                if (stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING)
-                       new FlightStat(layout, y++, "Main descent rate",
-                                      String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]),
-                                      String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main])));
+                       main_descent_stat = new FlightStat(layout, y++, "Main descent rate",
+                                                          String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]),
+                                                          String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main])));
                if (stats.state_time[AltosLib.ao_flight_drogue] != 0 || stats.state_time[AltosLib.ao_flight_main] != 0) {
                        double  drogue_duration = stats.state_time[AltosLib.ao_flight_drogue];
                        double  main_duration = stats.state_time[AltosLib.ao_flight_main];
@@ -210,6 +252,10 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                AltosUIPreferences.unregister_font_listener(this);
        }
 
+       public void filter_changed(AltosFlightStats stats) {
+               set_values(stats);
+       }
+
        public AltosFlightStatsTable() {
                layout = new GridBagLayout();
 
index 31042abb51e34ca1da41c1f0ff4df5809243280d..a758bcdecb284f70e37f6a647acf1617d3793ccd 100644 (file)
@@ -37,49 +37,56 @@ import org.jfree.data.*;
 
 public class AltosGraph extends AltosUIGraph {
 
-       static final private Color height_color = new Color(194,31,31);
-       static final private Color kalman_height_color = new Color(255,0,0);
-       static final private Color gps_height_color = new Color(150,31,31);
-       static final private Color pressure_color = new Color (225,31,31);
-       static final private Color range_color = new Color(100, 31, 31);
-       static final private Color distance_color = new Color(100, 31, 194);
-       static final private Color speed_color = new Color(31,194,31);
-       static final private Color kalman_speed_color = new Color(0,255,0);
-       static final private Color thrust_color = new Color(31,194,31);
-       static final private Color accel_color = new Color(31,31,194);
-       static final private Color vert_accel_color = new Color(64,164,164);
-       static final private Color kalman_accel_color = new Color(0,0,255);
-       static final private Color voltage_color = new Color(194, 194, 31);
-       static final private Color battery_voltage_color = new Color(194, 194, 31);
-       static final private Color drogue_voltage_color = new Color(150, 150, 31);
-       static final private Color main_voltage_color = new Color(100, 100, 31);
-       static final private Color igniter_voltage_color = new Color(80, 80, 31);
-       static final private Color igniter_marker_color = new Color(255, 0, 0);
-       static final private Color gps_nsat_color = new Color (194, 31, 194);
-       static final private Color gps_nsat_solution_color = new Color (194, 31, 194);
-       static final private Color gps_nsat_view_color = new Color (150, 31, 150);
-       static final private Color gps_course_color = new Color (100, 31, 112);
-       static final private Color gps_ground_speed_color = new Color (31, 112, 100);
-       static final private Color gps_speed_color = new Color (31, 112, 100);
-       static final private Color gps_climb_rate_color = new Color (31, 31, 112);
-       static final private Color gps_pdop_color = new Color(50, 194, 0);
-       static final private Color gps_hdop_color = new Color(50, 0, 194);
-       static final private Color gps_vdop_color = new Color(194, 0, 50);
-       static final private Color temperature_color = new Color (31, 194, 194);
-       static final private Color dbm_color = new Color(31, 100, 100);
-       static final private Color state_color = new Color(0,0,0);
-       static final private Color accel_along_color = new Color(255, 0, 0);
-       static final private Color accel_across_color = new Color(0, 255, 0);
-       static final private Color accel_through_color = new Color(0, 0, 255);
-       static final private Color gyro_roll_color = new Color(192, 0, 0);
-       static final private Color gyro_pitch_color = new Color(0, 192, 0);
-       static final private Color gyro_yaw_color = new Color(0, 0, 192);
-       static final private Color mag_along_color = new Color(128, 0, 0);
-       static final private Color mag_across_color = new Color(0, 128, 0);
-       static final private Color mag_through_color = new Color(0, 0, 128);
-       static final private Color orient_color = new Color(31, 31, 31);
+       /* These are in 'priority' order so that earlier ones get simpler line styles,
+        * then they are grouped so that adjacent ones get sequential colors
+        */
+       static final private AltosUILineStyle height_color = new AltosUILineStyle();
+       static final private AltosUILineStyle speed_color = new AltosUILineStyle();
+       static final private AltosUILineStyle accel_color = new AltosUILineStyle();
+       static final private AltosUILineStyle vert_accel_color = new AltosUILineStyle();
+       static final private AltosUILineStyle orient_color = new AltosUILineStyle();
+
+       static final private AltosUILineStyle gps_height_color = new AltosUILineStyle();
+       static final private AltosUILineStyle altitude_color = new AltosUILineStyle();
+
+       static final private AltosUILineStyle battery_voltage_color = new AltosUILineStyle();
+       static final private AltosUILineStyle pyro_voltage_color = new AltosUILineStyle();
+       static final private AltosUILineStyle drogue_voltage_color = new AltosUILineStyle();
+       static final private AltosUILineStyle main_voltage_color = new AltosUILineStyle();
+       static final private AltosUILineStyle igniter_marker_color = new AltosUILineStyle(1);
+
+       static final private AltosUILineStyle kalman_height_color = new AltosUILineStyle();
+       static final private AltosUILineStyle kalman_speed_color = new AltosUILineStyle();
+       static final private AltosUILineStyle kalman_accel_color = new AltosUILineStyle();
+
+       static final private AltosUILineStyle gps_nsat_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle gps_nsat_solution_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle gps_nsat_view_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle gps_course_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle gps_ground_speed_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle gps_speed_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle gps_climb_rate_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle gps_pdop_color = new AltosUILineStyle();
+       static final private AltosUILineStyle gps_hdop_color = new AltosUILineStyle();
+       static final private AltosUILineStyle gps_vdop_color = new AltosUILineStyle();
+
+       static final private AltosUILineStyle temperature_color = new AltosUILineStyle ();
+       static final private AltosUILineStyle dbm_color = new AltosUILineStyle();
+       static final private AltosUILineStyle pressure_color = new AltosUILineStyle ();
+
+       static final private AltosUILineStyle state_color = new AltosUILineStyle(0);
+       static final private AltosUILineStyle accel_along_color = new AltosUILineStyle();
+       static final private AltosUILineStyle accel_across_color = new AltosUILineStyle();
+       static final private AltosUILineStyle accel_through_color = new AltosUILineStyle();
+       static final private AltosUILineStyle gyro_roll_color = new AltosUILineStyle();
+       static final private AltosUILineStyle gyro_pitch_color = new AltosUILineStyle();
+       static final private AltosUILineStyle gyro_yaw_color = new AltosUILineStyle();
+       static final private AltosUILineStyle mag_along_color = new AltosUILineStyle();
+       static final private AltosUILineStyle mag_across_color = new AltosUILineStyle();
+       static final private AltosUILineStyle mag_through_color = new AltosUILineStyle();
 
        static AltosUnits dop_units = null;
+       static AltosUnits tick_units = null;
 
        AltosUIFlightSeries flight_series;
 
@@ -87,24 +94,24 @@ public class AltosGraph extends AltosUIGraph {
                AltosCalData    cal_data = flight_series.cal_data();
 
                AltosUIAxis     height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis;
-               AltosUIAxis     distance_axis, pressure_axis, thrust_axis;
+               AltosUIAxis     pressure_axis, thrust_axis;
                AltosUIAxis     gyro_axis, orient_axis, mag_axis;
-               AltosUIAxis     course_axis, dop_axis;
+               AltosUIAxis     course_axis, dop_axis, tick_axis;
 
-               if (stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING)
+               if (stats != null && stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING)
                        setName(String.format("%s %d flight %d\n", stats.product, stats.serial, stats.flight));
 
                height_axis = newAxis("Height", AltosConvert.height, height_color);
                pressure_axis = newAxis("Pressure", AltosConvert.pressure, pressure_color, 0);
                speed_axis = newAxis("Speed", AltosConvert.speed, speed_color);
-               thrust_axis = newAxis("Thrust", AltosConvert.force, thrust_color);
+               thrust_axis = newAxis("Thrust", AltosConvert.force, accel_color);
+               tick_axis = newAxis("Tick", tick_units, accel_color, 0);
                accel_axis = newAxis("Acceleration", AltosConvert.accel, accel_color);
-               voltage_axis = newAxis("Voltage", AltosConvert.voltage, voltage_color);
+               voltage_axis = newAxis("Voltage", AltosConvert.voltage, battery_voltage_color);
                temperature_axis = newAxis("Temperature", AltosConvert.temperature, temperature_color, 0);
                nsat_axis = newAxis("Satellites", null, gps_nsat_color,
                                    AltosUIAxis.axis_include_zero | AltosUIAxis.axis_integer);
                dbm_axis = newAxis("Signal Strength", null, dbm_color, 0);
-               distance_axis = newAxis("Distance", AltosConvert.distance, range_color);
 
                gyro_axis = newAxis("Rotation Rate", AltosConvert.rotation_rate, gyro_roll_color, 0);
                orient_axis = newAxis("Tilt Angle", AltosConvert.orient, orient_color, 0);
@@ -129,6 +136,11 @@ public class AltosGraph extends AltosUIGraph {
                                              plot,
                                              false);
 
+               flight_series.register_axis(AltosUIFlightSeries.tick_name,
+                                           accel_color,
+                                           false,
+                                           tick_axis);
+
                flight_series.register_axis(AltosUIFlightSeries.accel_name,
                                            accel_color,
                                            true,
@@ -170,7 +182,7 @@ public class AltosGraph extends AltosUIGraph {
                                            height_axis);
 
                flight_series.register_axis(AltosUIFlightSeries.altitude_name,
-                                           height_color,
+                                           altitude_color,
                                            false,
                                            height_axis);
 
@@ -190,6 +202,11 @@ public class AltosGraph extends AltosUIGraph {
                                            false,
                                            voltage_axis);
 
+               flight_series.register_axis(AltosUIFlightSeries.pyro_voltage_name,
+                                           pyro_voltage_color,
+                                           false,
+                                           voltage_axis);
+
                flight_series.register_axis(AltosUIFlightSeries.apogee_voltage_name,
                                            drogue_voltage_color,
                                            false,
@@ -305,17 +322,19 @@ public class AltosGraph extends AltosUIGraph {
                                            false,
                                            orient_axis);
 
-               for (int channel = 0; channel < 26; channel++) {
+               flight_series.register_axis(AltosUIFlightSeries.thrust_name,
+                                           accel_color,
+                                           true,
+                                           thrust_axis);
+
+               for (int channel = 0; channel < 8; channel++) {
                        flight_series.register_axis(flight_series.igniter_voltage_name(channel),
-                                                   igniter_voltage_color,
+                                                   new AltosUILineStyle(),
                                                    false,
                                                    voltage_axis);
                }
 
-               flight_series.register_axis(AltosUIFlightSeries.thrust_name,
-                                           thrust_color,
-                                           true,
-                                           thrust_axis);
+               flight_series.check_axes();
 
                return flight_series.series(cal_data);
        }
@@ -330,6 +349,7 @@ public class AltosGraph extends AltosUIGraph {
 
        public AltosGraph(AltosUIEnable enable, AltosFlightStats stats, AltosUIFlightSeries flight_series) {
                this(enable);
+               this.flight_series = flight_series;
                set_series(setup(stats, flight_series));
        }
 }
index 9e528b1fd27f6ae4295bb7bdc013a53c3a74ab0c..e759394bb4645e0f304bad9017641630248d5849 100644 (file)
@@ -142,6 +142,8 @@ public class AltosInfoTable extends JTable implements AltosFlightDisplay, Hierar
                                info_add_row(0, "Device", "%s", AltosLib.product_name(cal_data.device_type));
                        else if (cal_data.product != null)
                                info_add_row(0, "Device", "%s", cal_data.product);
+                       if (state.tick() != AltosLib.MISSING)
+                               info_add_row(0, "Tick", "%6d", state.tick());
                        if (state.altitude() != AltosLib.MISSING)
                                info_add_row(0, "Altitude", "%6.0f    m", state.altitude());
                        if (cal_data.ground_altitude != AltosLib.MISSING)
diff --git a/altosuilib/AltosShapeListener.java b/altosuilib/AltosShapeListener.java
new file mode 100644 (file)
index 0000000..6bf52fd
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+package org.altusmetrum.altosuilib_12;
+
+public interface AltosShapeListener {
+       void set_shapes_visible(boolean visible);
+       void set_line_width(float width);
+}
index fe94f161f5543beb81494080757e0af0bc4be76e..528733638a0e9cb4c4cfa7e70ecca9efd1fa6644 100644 (file)
@@ -36,12 +36,12 @@ import org.jfree.data.xy.*;
 import org.jfree.data.*;
 
 public class AltosUIAxis extends NumberAxis {
-       String          label;
-       AltosUnits      units;
-       Color           color;
-       int             ref;
-       int             visible;
-       int             index;
+       String                  label;
+       AltosUnits              units;
+       AltosUILineStyle        line_style;
+       int                     ref;
+       int                     visible;
+       int                     index;
 
        public final static int axis_integer = 1;
        public final static int axis_include_zero = 2;
@@ -82,21 +82,22 @@ public class AltosUIAxis extends NumberAxis {
                }
        }
 
-       public AltosUIAxis(String label, AltosUnits units, Color color, int index, int flags) {
+       public AltosUIAxis(String label, AltosUnits units, AltosUILineStyle line_style, int index, int flags) {
                this.label = label;
                this.units = units;
+               this.line_style = line_style;
                this.index = index;
                this.visible = 0;
                this.ref = 0;
-               setLabelPaint(color);
-               setTickLabelPaint(color);
+               setLabelPaint(line_style.color);
+               setTickLabelPaint(line_style.color);
                setVisible(false);
                if ((flags & axis_integer) != 0)
                        setStandardTickUnits(NumberAxis.createIntegerTickUnits());
                setAutoRangeIncludesZero((flags & axis_include_zero) != 0);
        }
 
-       public AltosUIAxis(String label, AltosUnits units, Color color, int index) {
-               this(label, units, color, index, axis_default);
+       public AltosUIAxis(String label, AltosUnits units, AltosUILineStyle line_style, int index) {
+               this(label, units, line_style, index, axis_default);
        }
 }
index 0c23fa8d3279bd23f26e9b8249a98ccd4953b045..851e831f43c8cd952d5df755c6e4b00853afab0d 100644 (file)
@@ -21,6 +21,7 @@ package org.altusmetrum.altosuilib_12;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
+import javax.swing.event.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
@@ -36,12 +37,21 @@ import org.jfree.chart.labels.*;
 import org.jfree.data.xy.*;
 import org.jfree.data.*;
 
-public class AltosUIEnable extends Container {
+public class AltosUIEnable extends Container implements ChangeListener {
 
        Insets          il, ir;
        int             y;
        int             x;
        JCheckBox       imperial_units;
+       JCheckBox       show_shapes;
+       JLabel          line_width_label;
+       JSpinner        line_width;
+       JLabel          speed_filter_label;
+       JSlider         speed_filter;
+       JLabel          accel_filter_label;
+       JSlider         accel_filter;
+       AltosFilterListener     filter_listener;
+       AltosShapeListener      shape_listener;
 
        static final int max_rows = 14;
 
@@ -69,11 +79,15 @@ public class AltosUIEnable extends Container {
                }
        }
 
+       LinkedList<GraphElement> elements = new LinkedList<GraphElement>();
+
        public void add(String name, AltosUIGrapher grapher, boolean enabled) {
 
                GraphElement    e = new GraphElement(name, grapher, enabled);
                GridBagConstraints c = new GridBagConstraints();
 
+               elements.add(e);
+
                /* Add element */
                c = new GridBagConstraints();
                c.gridx = x; c.gridy = y;
@@ -90,6 +104,31 @@ public class AltosUIEnable extends Container {
                }
        }
 
+       public void stateChanged(ChangeEvent e) {
+               JSlider filter = (JSlider) e.getSource();
+               if (!filter.getValueIsAdjusting()) {
+                       double  speed_value = (int) speed_filter.getValue() / 1000.0;
+                       double  accel_value = (int) accel_filter.getValue() / 1000.0;
+                       if (filter_listener != null) {
+                               filter_listener.filter_changed(speed_value, accel_value);
+                       }
+               }
+       }
+
+       public void set_shapes_visible(boolean visible) {
+               if (shape_listener != null)
+                       shape_listener.set_shapes_visible(visible);
+       }
+
+       public void set_line_width(float width) {
+               if (shape_listener != null)
+                       shape_listener.set_line_width(width);
+       }
+
+       public void register_shape_listener(AltosShapeListener shape_listener) {
+               this.shape_listener = shape_listener;
+       }
+
        public void add_units() {
                /* Imperial units setting */
 
@@ -109,9 +148,111 @@ public class AltosUIEnable extends Container {
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
                add(imperial_units, c);
+
+               show_shapes = new JCheckBox("Show Markers", false);
+               show_shapes.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       JCheckBox item = (JCheckBox) e.getSource();
+                                       boolean enabled = item.isSelected();
+                                       set_shapes_visible(enabled);
+                               }
+                       });
+               show_shapes.setToolTipText("Show marker Use Imperial units instead of metric");
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 1001;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(show_shapes, c);
+
+
+               line_width_label = new JLabel("Line Width");
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 1001;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(line_width_label, c);
+
+               line_width = new JSpinner();
+               line_width.setValue(new Integer(1));
+               line_width.addChangeListener(new ChangeListener() {
+                               public void stateChanged(ChangeEvent e) {
+                                       int w = (Integer) line_width.getValue();
+                                       if (w < 1) {
+                                               w = 1;
+                                               line_width.setValue(new Integer(w));
+                                       }
+                                       System.out.printf("line width set to %d\n", w);
+                                       set_line_width(w);
+                               }
+                       });
+               c = new GridBagConstraints();
+               c.gridx = 2; c.gridy = 1001;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(line_width, c);
+
+               speed_filter_label = new JLabel("Speed Filter(ms)");
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 1002;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(speed_filter_label, c);
+
+               speed_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.speed_filter() * 1000.0));
+               Hashtable<Integer,JLabel> label_table = new Hashtable<Integer,JLabel>();
+               for (int i = 0; i <= 10000; i += 5000) {
+                       label_table.put(new Integer(i), new JLabel(String.format("%d", i)));
+               }
+               speed_filter.setPaintTicks(true);
+               speed_filter.setMajorTickSpacing(1000);
+               speed_filter.setMinorTickSpacing(250);
+               speed_filter.setLabelTable(label_table);
+               speed_filter.setPaintTrack(false);
+               speed_filter.setSnapToTicks(true);
+               speed_filter.setPaintLabels(true);
+               speed_filter.addChangeListener(this);
+
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 1002;
+               c.gridwidth = 1000; c.gridheight = 1;
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(speed_filter, c);
+
+               accel_filter_label = new JLabel("Acceleration Filter(ms)");
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 1003;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(accel_filter_label, c);
+
+               accel_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.accel_filter() * 1000.0));
+               accel_filter.setPaintTicks(true);
+               accel_filter.setMajorTickSpacing(1000);
+               accel_filter.setMinorTickSpacing(250);
+               accel_filter.setLabelTable(label_table);
+               accel_filter.setPaintTrack(false);
+               accel_filter.setSnapToTicks(true);
+               accel_filter.setPaintLabels(true);
+               accel_filter.addChangeListener(this);
+
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 1003;
+               c.gridwidth = 1000; c.gridheight = 1;
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(accel_filter, c);
        }
 
-       public AltosUIEnable() {
+       public AltosUIEnable(AltosFilterListener filter_listener) {
+               this.filter_listener = filter_listener;
                il = new Insets(4,4,4,4);
                ir = new Insets(4,4,4,4);
                x = 0;
index 19bed6097a1c4326504ec0a17d79e3757e691ab9..407e5ab4c27d00559f59cc3647d910608ce98120 100644 (file)
@@ -30,15 +30,16 @@ import org.jfree.data.xy.*;
 import org.jfree.data.*;
 
 class AltosUITimeSeriesAxis {
-       Color           color;
-       boolean         enabled;
-       boolean         marker;
-       boolean         marker_top;
-       AltosUIAxis     axis;
-       XYPlot          plot;
-
-       public AltosUITimeSeriesAxis(Color color, boolean enabled, AltosUIAxis axis, XYPlot plot, boolean marker, boolean marker_top) {
-               this.color = color;
+       AltosUILineStyle        line_style;
+       boolean                 enabled;
+       boolean                 marker;
+       boolean                 marker_top;
+       AltosUIAxis             axis;
+       XYPlot                  plot;
+
+       public AltosUITimeSeriesAxis(AltosUILineStyle line_style, boolean enabled,
+                                    AltosUIAxis axis, XYPlot plot, boolean marker, boolean marker_top) {
+               this.line_style = line_style;
                this.enabled = enabled;
                this.axis = axis;
                this.plot = plot;
@@ -51,26 +52,34 @@ public class AltosUIFlightSeries extends AltosFlightSeries {
 
        Hashtable<String,AltosUITimeSeriesAxis> axes;
 
-       AltosUIFlightSeries flight_series;
-
        void fill_axes(String label, AltosUITimeSeriesAxis axis) {
                for (AltosTimeSeries ts : series) {
                        AltosUITimeSeries uts = (AltosUITimeSeries) ts;
 
-                       if (label.equals(ts.label) || (label.equals("default") && uts.color == null)) {
+                       if (label.equals(ts.label) || (label.equals("default") && uts.line_style == null)) {
+                               uts.custom_axis_set = true;
                                if (axis.marker)
-                                       uts.set_marker(axis.color, axis.enabled, axis.plot, axis.marker_top);
+                                       uts.set_marker(axis.line_style, axis.enabled, axis.plot, axis.marker_top);
                                else
-                                       uts.set_axis(axis.color, axis.enabled, axis.axis);
+                                       uts.set_axis(axis.line_style, axis.enabled, axis.axis);
                        }
                }
        }
 
+       void check_axes() {
+               for (AltosTimeSeries ts : series) {
+                       AltosUITimeSeries uts = (AltosUITimeSeries) ts;
+
+                       if (!uts.custom_axis_set)
+                               System.out.printf("%s using default axis\n", ts.label);
+               }
+       }
+
        public void register_axis(String label,
-                                 Color color,
+                                 AltosUILineStyle line_style,
                                  boolean enabled,
                                  AltosUIAxis axis) {
-               AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(color,
+               AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(line_style,
                                                                      enabled,
                                                                      axis,
                                                                      null,
@@ -81,11 +90,11 @@ public class AltosUIFlightSeries extends AltosFlightSeries {
        }
 
        public void register_marker(String label,
-                                   Color color,
+                                   AltosUILineStyle line_style,
                                    boolean enabled,
                                    XYPlot plot,
                                    boolean marker_top) {
-               AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(color,
+               AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(line_style,
                                                                      enabled,
                                                                      null,
                                                                      plot,
@@ -97,17 +106,18 @@ public class AltosUIFlightSeries extends AltosFlightSeries {
 
        public AltosTimeSeries make_series(String label, AltosUnits units) {
 
-
                AltosUITimeSeries time_series = new AltosUITimeSeries(label, units);
 
                AltosUITimeSeriesAxis tsa = axes.get(label);
                if (tsa == null)
                        tsa = axes.get("default");
+               else
+                       time_series.custom_axis_set = true;
                if (tsa != null) {
                        if (tsa.marker)
-                               time_series.set_marker(tsa.color, tsa.enabled, tsa.plot, tsa.marker_top);
+                               time_series.set_marker(tsa.line_style, tsa.enabled, tsa.plot, tsa.marker_top);
                        else
-                               time_series.set_axis(tsa.color, tsa.enabled, tsa.axis);
+                               time_series.set_axis(tsa.line_style, tsa.enabled, tsa.axis);
                }
                return time_series;
        }
index 0caabcfa4a009829b59a5ae55ddf0ae1d597307e..40f415f1b6c26518bd735e8a8840dd53f4a7eb2d 100644 (file)
@@ -36,7 +36,7 @@ import org.jfree.chart.labels.*;
 import org.jfree.data.xy.*;
 import org.jfree.data.*;
 
-public class AltosUIGraph implements AltosUnitsListener {
+public class AltosUIGraph implements AltosUnitsListener, AltosShapeListener {
 
        XYPlot                          plot;
        JFreeChart                      chart;
@@ -56,14 +56,14 @@ public class AltosUIGraph implements AltosUnitsListener {
                return panel;
        }
 
-       public AltosUIAxis newAxis(String label, AltosUnits units, Color color, int flags) {
-               AltosUIAxis axis = new AltosUIAxis(label, units, color, axis_index++, flags);
+       public AltosUIAxis newAxis(String label, AltosUnits units, AltosUILineStyle line_style, int flags) {
+               AltosUIAxis axis = new AltosUIAxis(label, units, line_style, axis_index++, flags);
                plot.setRangeAxis(axis.index, axis);
                return axis;
        }
 
-       public AltosUIAxis newAxis(String label, AltosUnits units, Color color) {
-               return newAxis(label, units, color, AltosUIAxis.axis_default);
+       public AltosUIAxis newAxis(String label, AltosUnits units, AltosUILineStyle line_style) {
+               return newAxis(label, units, line_style, AltosUIAxis.axis_default);
        }
 
        void addAxis(AltosUIAxis axis) {
@@ -95,6 +95,20 @@ public class AltosUIGraph implements AltosUnitsListener {
                        s.set_units();
        }
 
+       public void filter_changed() {
+               units_changed(false);
+       }
+
+       public void set_shapes_visible(boolean visible) {
+               for (AltosUITimeSeries s : series)
+                       s.set_shapes_visible(visible);
+       }
+
+       public void set_line_width(float width) {
+               for (AltosUITimeSeries s : series)
+                       s.set_line_width(width);
+       }
+
        public void setName (String name) {
                chart.setTitle(name);
        }
@@ -123,6 +137,8 @@ public class AltosUIGraph implements AltosUnitsListener {
                this.series = null;
                this.axis_index = 0;
 
+               enable.register_shape_listener(this);
+
                axes_added = new Hashtable<Integer,Boolean>();
 
                xAxis = new NumberAxis("Time (s)");
diff --git a/altosuilib/AltosUILineStyle.java b/altosuilib/AltosUILineStyle.java
new file mode 100644 (file)
index 0000000..387281a
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+package org.altusmetrum.altosuilib_12;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_12.*;
+
+import org.jfree.ui.*;
+import org.jfree.chart.*;
+import org.jfree.chart.plot.*;
+import org.jfree.chart.axis.*;
+import org.jfree.chart.renderer.*;
+import org.jfree.chart.renderer.xy.*;
+import org.jfree.chart.labels.*;
+import org.jfree.data.xy.*;
+import org.jfree.data.*;
+
+public class AltosUILineStyle {
+       public Color    color;
+       public float[]  dash;
+
+       static private Color color(int r, int g, int b) {
+               return new Color(r,g,b);
+       }
+
+       static final private Color[] colors = {
+               new Color(0,0,0),
+               new Color(230,0,0),     // red
+               new Color(216,103,0),   // orange
+               new Color(200,200,0),   // yellow
+               new Color(0,180,0),     // green
+               new Color(0,140,140),   // cyan
+               new Color(130,0,0),     // dark red
+               new Color(0,100,0),     // dark green
+               new Color(0,0,255),     // blue
+               new Color(140,0,140),   // magenta
+               new Color(150,150,150), // gray
+       };
+
+       static final private float[][] dashes = {
+               { 0 },
+               { 2, 4 },
+               { 4, 4 },
+               { 6, 4 },
+               { 6, 4, 2, 4 }
+       };
+
+       static int color_index, dash_index;
+
+       public AltosUILineStyle () {
+               color = colors[color_index];
+               dash = dashes[dash_index];
+               color_index = (color_index + 1) % colors.length;
+               if (color_index == 0) {
+                       dash_index = (dash_index + 1) % dashes.length;
+                       if (dash_index == 0)
+                               System.out.printf("too many line styles\n");
+               }
+       }
+
+       public AltosUILineStyle(int index) {
+               index = index % (colors.length * dashes.length);
+               int c = index % colors.length;
+               int d = index / colors.length;
+               color = colors[c];
+               dash = dashes[d];
+       }
+}
index 08f95ca748740f5f26408e46d19919c238dcf5c7..e85e3c17774aadde406577d93e7a5cdd82cf0635 100644 (file)
@@ -61,16 +61,17 @@ class AltosXYSeries extends XYSeries {
 }
 
 public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher {
-       Color           color;
-       boolean         enable;
-       AltosUIAxis     axis;
-       boolean         marker;
-       boolean         marker_top;
-       XYItemRenderer  renderer;
-       XYPlot          plot;
-       AltosXYSeries   xy_series;
+       AltosUILineStyle        line_style;
+       boolean                 enable;
+       boolean                 custom_axis_set;
+       AltosUIAxis             axis;
+       boolean                 marker;
+       boolean                 marker_top;
+       XYLineAndShapeRenderer  renderer;
+       XYPlot                  plot;
+       AltosXYSeries           xy_series;
        ArrayList<ValueMarker>  markers;
-
+       float                   width;
 
        /* AltosUIGrapher interface */
        public boolean need_reset() {
@@ -89,7 +90,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher
        public void fireSeriesChanged() {
        }
 
-       void set_data() {
+       public void set_data() {
                if (marker) {
                        if (markers != null) {
                                for (ValueMarker marker : markers)
@@ -107,7 +108,8 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher
                                        marker.setLabelAnchor(RectangleAnchor.BOTTOM_RIGHT);
                                        marker.setLabelTextAnchor(TextAnchor.BOTTOM_LEFT);
                                }
-                               marker.setPaint(color);
+                               marker.setPaint(line_style.color);
+                               marker.setStroke(new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
                                if (enable)
                                        plot.addDomainMarker(marker);
                                markers.add(marker);
@@ -124,6 +126,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher
                        }
                        xy_series.setNotify(true);
                }
+               clear_changed();
        }
 
        public void set_units() {
@@ -164,37 +167,59 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher
                }
        }
 
-       public void set_axis(Color color, boolean enable, AltosUIAxis axis) {
-               this.color = color;
+       // public BasicStroke(float width, int cap, int join, float miterlimit,
+       // float dash[], float dash_phase)
+
+       public void set_line_width(float width) {
+               this.width = width;
+               if (markers != null) {
+                       for (ValueMarker marker : markers) {
+                               marker.setStroke(new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+                       }
+               } else {
+                       if (line_style.dash[0] == 0.0)
+                               renderer.setSeriesStroke(0, new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+                       else
+                               renderer.setSeriesStroke(0, new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, line_style.dash, 0.0f));
+               }
+       }
+
+       public void set_axis(AltosUILineStyle line_style, boolean enable, AltosUIAxis axis) {
+               this.line_style = line_style;
                this.enable = enable;
                this.axis = axis;
                this.marker = false;
+               this.width = 1.0f;
 
                axis.ref(this.enable);
 
                renderer = new XYLineAndShapeRenderer(true, false);
-               renderer.setSeriesPaint(0, color);
-               renderer.setSeriesStroke(0, new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+               renderer.setSeriesPaint(0, line_style.color);
+               set_line_width(this.width);
                renderer.setSeriesVisible(0, enable);
                xy_series = new AltosXYSeries(label);
        }
 
-       public void set_marker(Color color, boolean enable, XYPlot plot, boolean marker_top) {
-               this.color = color;
+       public void set_marker(AltosUILineStyle line_style, boolean enable, XYPlot plot, boolean marker_top) {
+               this.line_style = line_style;
                this.enable = enable;
                this.marker = true;
                this.plot = plot;
                this.marker_top = marker_top;
        }
 
+       public void set_shapes_visible(boolean shapes_visible) {
+               renderer.setSeriesShapesVisible(0, shapes_visible);
+       }
+
        public AltosUITimeSeries(String label, AltosUnits units) {
                super(label, units);
        }
 
        public AltosUITimeSeries(String label, AltosUnits units,
-                                Color color, boolean enable,
+                                AltosUILineStyle line_style, boolean enable,
                                 AltosUIAxis axis) {
                this(label, units);
-               set_axis(color, enable, axis);
+               set_axis(line_style, enable, axis);
        }
 }
index ce86d21e3a1405a4665cd86a04bb7b58f26a8774..c65a3d1516c5e80e8a1a24a4d3e4b5162f41d914 100644 (file)
@@ -31,6 +31,7 @@ altosuilib_JAVA = \
        AltosUIFlightSeries.java \
        AltosUIGraph.java \
        AltosGraph.java \
+       AltosShapeListener.java \
        AltosUSBDevice.java \
        AltosVoice.java \
        AltosDisplayThread.java \
@@ -40,6 +41,7 @@ altosuilib_JAVA = \
        AltosConfigFreqUI.java \
        AltosScanUI.java \
        AltosEepromDelete.java \
+       AltosEepromGrapher.java \
        AltosEepromManage.java \
        AltosEepromMonitorUI.java \
        AltosEepromSelect.java \
@@ -56,6 +58,7 @@ altosuilib_JAVA = \
        AltosBTDeviceIterator.java \
        AltosBTManage.java \
        AltosBTKnown.java \
+       AltosUILineStyle.java \
        AltosUIMap.java \
        AltosUIMapPreload.java \
        AltosUIFlightTab.java \
index 0ac475a30044eb25fc79b0dc8aa6007e71c951ee..ec024e32d4b3576b51b7bc2af583dac60a7ee1ee 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-VERSION=2.0
+VERSION=3.0
 PRODUCT=TeleMega
 BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
 
diff --git a/ao-bringup/test-telemega-v2.0 b/ao-bringup/test-telemega-v2.0
new file mode 100755 (executable)
index 0000000..0ac475a
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+VERSION=2.0
+PRODUCT=TeleMega
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+
+echo "$PRODUCT-v$VERSION Test Program"
+echo "Copyright 2014 by Keith Packard.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo
+
+ret=1
+ao-list | while read product serial dev; do
+    case "$product" in
+       "$PRODUCT-v$VERSION")
+
+           echo "Testing $product $serial $dev"
+
+           ./test-igniters $dev main drogue 3 0 1 2
+           echo""
+
+           echo "Testing baro sensor"
+           ../ao-tools/ao-test-baro/ao-test-baro --tty="$dev"
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+           echo""
+
+           FLASHSIZE=8388608
+
+           echo "Testing flash"
+           ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE"
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+           echo""
+
+           echo "Testing GPS"
+           ../ao-tools/ao-test-gps/ao-test-gps --tty="$dev"
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+           echo""
+
+           echo "$PRODUCT-v$VERSION" serial "$serial" is ready to ship
+           echo "\007"
+           ret=0
+           ;;
+    esac
+done
index fb8318b311c83d7ac28aa9adfbe392cf866ef1af..8bf9bcb56bb5429aa13e1849d258f2b1347bbe7e 100755 (executable)
@@ -44,7 +44,7 @@ esac
 FLASH_FILE=$REPO/loaders/telebt-v$VERSION-altos-flash-*.bin
 ALTOS_FILE=$REPO/telebt-v$VERSION-*.elf
 
-$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || exit 1
+$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE
 
 sleep 2
 
index fd879abdb175532ef84ea61328376a1fcd539e7d..48af692a2f9a02103f3a078105a63919ad144a77 100755 (executable)
@@ -49,7 +49,7 @@ esac
 FLASH_FILE=$REPO/loaders/telegps-v2.0-altos-flash-*.bin
 ALTOS_FILE=$REPO/telegps-v2.0-*.elf
 
-$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || exit 1
+$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE 
 
 sleep 2
 
index e2b539e1a2ef7356a341a4041010d43af162a76e..497767888c0b8b325bb76be87e5a59606123f138 100755 (executable)
@@ -14,12 +14,12 @@ else
        exit 1
 fi
 
-VERSION=2.0
+VERSION=3.0
 REPO=~/altusmetrumllc/Binaries
 PRODUCT=TeleMega
 
 echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
-echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2"
+echo "Copyright 2017 by Bdale Garbee.  Released under GPL v3"
 echo
 echo "Expectations:"
 echo "\t$PRODUCT v$VERSION powered from USB"
@@ -44,11 +44,11 @@ esac
 
 echo $FLASH_STM
 
-$FLASH_STM $REPO/loaders/telemega-v$VERSION*.elf || exit 1
+$FLASH_STM $REPO/loaders/telemega-v$VERSION*.elf 
 
 sleep 5
 
-$USBLOAD --serial=$SERIAL $REPO/telemega-v$VERSION*.elf || exit 1
+$USBLOAD --serial=$SERIAL --force $REPO/telemega-v$VERSION*.elf || exit 1
 
 sleep 5
 
diff --git a/ao-bringup/turnon_telemega_v2.0 b/ao-bringup/turnon_telemega_v2.0
new file mode 100755 (executable)
index 0000000..3c80dd9
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+if [ -x /usr/bin/ao-flash-stm ]; then
+       FLASH_STM=/usr/bin/ao-flash-stm
+else
+       echo "Can't find ao-flash-stm!  Aborting."
+       exit 1
+fi
+
+if [ -x /usr/bin/ao-usbload ]; then
+       USBLOAD=/usr/bin/ao-usbload
+else
+       echo "Can't find ao-usbload!  Aborting."
+       exit 1
+fi
+
+VERSION=2.0
+REPO=~/altusmetrumllc/Binaries
+PRODUCT=TeleMega
+
+echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo "\t\twith ST-Link-V2 cabled to debug header"
+echo "\t\twith coax from UHF to frequency counter"
+echo
+
+case $# in
+    1)
+       SERIAL="$1"
+       echo "$PRODUCT-$VERSION serial number: $SERIAL" 
+       ;;
+    0)
+       echo -n "$PRODUCT-$VERSION serial number: "
+       read SERIAL
+       ;;
+    *)
+       echo "Usage: $0 <serial-number>" 1>&2
+       exit 1;
+       ;;
+esac
+
+echo $FLASH_STM
+
+$FLASH_STM $REPO/loaders/telemega-v$VERSION*.elf 
+
+sleep 5
+
+$USBLOAD --serial=$SERIAL --force $REPO/telemega-v$VERSION*.elf || exit 1
+
+sleep 5
+
+dev=`ao-list | awk '/TeleMega-v'"$VERSION"'/ { print $3; exit(0); }'`
+
+case "$dev" in
+/dev/tty*)
+       echo "TeleMega found on $dev"
+       ;;
+*)
+       echo 'No TeleMega-v'"$VERSION"' found'
+       exit 1
+       ;;
+esac
+
+echo 'E 0' > $dev
+
+SERIAL=$SERIAL ./cal-freq $dev
+
+failed=1
+while [ $failed = 1 ]; do
+    ../ao-tools/ao-cal-accel/ao-cal-accel $dev
+    failed=$?
+done
+
+echo 'E 1' > $dev
+
+./test-telemega-v2.0
+
+exit $?
index 2bf6c7e330de9840b2f907ad4ca224cc9a691f3b..02fca439286630ae0d2ff749fbf0f6cad82d4348 100644 (file)
@@ -18,13 +18,13 @@ dnl
 dnl Process this file with autoconf to create configure.
 
 AC_PREREQ(2.57)
-AC_INIT([altos], 1.8.2)
+AC_INIT([altos], 1.8.3)
 ANDROID_VERSION=16
 AC_CONFIG_SRCDIR([src/kernel/ao.h])
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
 AM_MAINTAINER_MODE
 
-RELEASE_DATE=2017-09-18
+RELEASE_DATE=2017-12-11
 AC_SUBST(RELEASE_DATE)
 
 VERSION_DASH=`echo $VERSION | sed 's/\./-/g'`
index b1bff8482d94a99a2924821aa119dd1656089f6d..feb1de8f5cf574f9c7dd08eb6bde0bf1c51687ea 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 RELNOTES_INC=\
+       release-notes-1.8.3.inc \
        release-notes-1.8.2.inc \
        release-notes-1.8.1.inc \
        release-notes-1.8.inc \
index 88e7a03558dd75ad03a57ad0735f16c22f2279ff..adce6f27df10e027ce26b6fb9260689a635d3936 100644 (file)
                        image::graph-configure.png[width="5.5in"]
 
                        This selects which graph elements to show, and, at the
-                       very bottom, lets you switch between metric and
-                       imperial units
+                       very bottom. It also lets you configure how
+                       the graph is drawn:
+
+                       * Whether to use metric or imperial units
+
+                       * Whether to show a marker at each data
+                          point. When displaying a small section of
+                          the graph, these can be useful to know what
+                          data values were recorded.
+
+                       * How wide to draw the lines in the graph
+
+                       * How to filter speed and acceleration data
+                          computed from barometric data. Flight
+                          computers with accelerometers never display
+                          computed acceleration data, and only use
+                          barometric data to compute speed during
+                          descent. Flight computers without
+                          accelerometers always compute both speed and
+                          acceleration from barometric data. A larger
+                          value smooths the data more.
 
                ==== Flight Statistics
 
index c2bc14d19055d79276cc076272fdd0a70fec43ad..3b0793b8ed6932b6756203787495b99246177710 100644 (file)
 </legalnotice>
 <revhistory>
   <?dbhtml filename="altusmetrum-revhistory.html"?>
+  <revision>
+    <revnumber>1.8.3</revnumber>
+    <date>11 Dec 2017</date>
+    <revremark>
+      Support TeleMega v3.0 hardware. Fix one firmware bug affecting
+      all flight computers and another two affecting TeleMega and
+      EasyMega. Several new AltosUI graphing features.
+    </revremark>
+  </revision>
   <revision>
     <revnumber>1.8.2</revnumber>
     <date>18 Sep 2017</date>
index 7f578f71af87cc90c8983b576cc2f77cb07e9774..f4f45fd7e26ebd4ac76c183c0561b19af1df7028 100644 (file)
@@ -1,5 +1,35 @@
 [appendix]
 == Release Notes
+       :leveloffset: 2
+       include::release-notes-1.8.3.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.8.2.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.8.1.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.8.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.7.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.6.8.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.6.5.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.6.4.raw[]
 
        :leveloffset: 2
        include::release-notes-1.6.3.raw[]
index ed0d51124693a83a434ff43534cec68c569a8052..4f9a23c5cd3f7f8d324f8ab68908d3c9c648716e 100644 (file)
Binary files a/doc/graph-configure.png and b/doc/graph-configure.png differ
index bcea5ff845c147c987458d27fa33168ab7fd7112..2363d2511dee984cb41e76777eadbbb5ef0af679 100644 (file)
Binary files a/doc/graph-map.png and b/doc/graph-map.png differ
index 6f5c9791344635baaca8c838e3aa9f06b1543987..88d943b9812bd74009ec59f3b1c6bda5b6177551 100644 (file)
Binary files a/doc/graph-stats.png and b/doc/graph-stats.png differ
index c7c7b7d7226a6ebba3f5873a78d1ee1982ecfa5a..8c5d7d4b51c414b6b21bce3bf461c4868eba671e 100644 (file)
Binary files a/doc/graph.png and b/doc/graph.png differ
diff --git a/doc/release-notes-1.6.3-docinfo.xml b/doc/release-notes-1.6.3-docinfo.xml
new file mode 100644 (file)
index 0000000..ce22ebc
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>6 May 2016</date>
+<copyright>
+  <year>2016</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.6.4-docinfo.xml b/doc/release-notes-1.6.4-docinfo.xml
new file mode 100644 (file)
index 0000000..76af355
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>17 June 2016</date>
+<copyright>
+  <year>2016</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.6.5-docinfo.xml b/doc/release-notes-1.6.5-docinfo.xml
new file mode 100644 (file)
index 0000000..a07d6f0
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>4 July 2016</date>
+<copyright>
+  <year>2016</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.6.8-docinfo.xml b/doc/release-notes-1.6.8-docinfo.xml
new file mode 100644 (file)
index 0000000..776c244
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>5 September 2016</date>
+<copyright>
+  <year>2016</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.7-docinfo.xml b/doc/release-notes-1.7-docinfo.xml
new file mode 100644 (file)
index 0000000..61d77d9
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>24 April 2017</date>
+<copyright>
+  <year>2017</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.8-docinfo.xml b/doc/release-notes-1.8-docinfo.xml
new file mode 100644 (file)
index 0000000..3b40421
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>12 August 2017</date>
+<copyright>
+  <year>2017</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.8.1-docinfo.xml b/doc/release-notes-1.8.1-docinfo.xml
new file mode 100644 (file)
index 0000000..29a4fe7
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>28 August 2017</date>
+<copyright>
+  <year>2017</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.8.2-docinfo.xml b/doc/release-notes-1.8.2-docinfo.xml
new file mode 100644 (file)
index 0000000..a5fbc6e
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>18 September 2017</date>
+<copyright>
+  <year>2017</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.8.3-docinfo.xml b/doc/release-notes-1.8.3-docinfo.xml
new file mode 100644 (file)
index 0000000..e036658
--- /dev/null
@@ -0,0 +1,29 @@
+<author>
+  <firstname>Bdale</firstname>
+  <surname>Garbee</surname>
+  <email>bdale@gag.com</email>
+</author>
+<author>
+  <firstname>Keith</firstname>
+  <surname>Packard</surname>
+  <email>keithp@keithp.com</email>
+</author>
+<date>11 December 2017</date>
+<copyright>
+  <year>2017</year>
+  <holder>Bdale Garbee and Keith Packard</holder>
+</copyright>
+<mediaobject>
+  <imageobject>
+    <imagedata fileref="altusmetrum-oneline.svg" width="6.0in"/>
+  </imageobject>
+</mediaobject>
+<legalnotice>
+  <para>
+    This document is released under the terms of the
+    <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+      Creative Commons ShareAlike 3.0
+    </ulink>
+    license.
+  </para>
+</legalnotice>
diff --git a/doc/release-notes-1.8.3.inc b/doc/release-notes-1.8.3.inc
new file mode 100644 (file)
index 0000000..4bc879a
--- /dev/null
@@ -0,0 +1,59 @@
+= Release Notes for Version 1.8.3
+:toc!:
+:doctype: article
+
+       Version 1.8.3 includes support for TeleMega version 3.0 along
+       with two important flight computer fixes. This version also
+       changes KML export data to make Tripoli Record reporting
+       better and some updates to graph presentation and data
+       downloading.
+
+       == AltOS
+
+       === AltOS New Features
+
+       * Support for TeleMega version 3.0 hardware.
+
+       === AltOS Bug Fixes
+
+       * Ground testing EasyMega and TeleMega additional pyro
+          channels could result in a sticky 'fired' status which would
+          prevent these channels from firing on future flights.
+
+       * Corrupted flight log records could prevent future flights
+          from capturing log data.
+
+       * Fixed saving of pyro configuration that ended with
+          'Descending'.
+
+       == AltosUI and TeleGPS Applications
+
+       === AltosUI New Features
+
+       * Support for TeleMega version 3.0.
+
+       * Graph lines have improved appearance to make them easier to
+         distinguish. Markers may be placed at data points to show
+         captured recorded data values.
+
+       * Graphing offers the ability to adjust the smoothing of
+          computed speed and acceleration data.
+
+       * The download dialog now offers to graph new flights, checks
+          for existing files to avoid overwriting data and reports if
+          there are checksum errors in the downloaded data.
+
+       === AltosUI/TeleGPS Bug Fixes
+
+       * Restore TeleGPS tracking behavior.
+
+       * Display flight computer call sign and serial number in
+          Monitor Idle mode instead of ground station values.
+
+       === AltosUI and TeleGPS Changes
+
+       * KML export now reports both barometric and GPS altitude data
+          to make it more useful for Tripoli record reporting.
+
+       * CSV export now includes TeleMega/EasyMega pyro voltages and
+          tilt angle.
index a102b2dc060c97a78fa76ff4c5198e2c651d81da..1c177afa64e278a91853d33e5329fb3415f0fece 100644 (file)
@@ -1,6 +1,10 @@
 [appendix]
 == Release Notes
 
+       :leveloffset: 2
+       include::release-notes-1.8.3.raw[]
+
+       <<<<
        :leveloffset: 2
        include::release-notes-1.8.2.raw[]
 
@@ -13,7 +17,6 @@
        include::release-notes-1.8.raw[]
 
        <<<<
-
        :leveloffset: 2
        include::release-notes-1.7.raw[]
 
index 1ef088fe882332457ee15830bd4c79bf329605b6..5e347cfdeedc6eeb3aef767bfef797050b73e097 100644 (file)
 </legalnotice>
 <revhistory>
   <?dbhtml filename="telegps-revhistory.html"?>
+  <revision>
+    <revnumber>1.8.3</revnumber>
+    <date>11 Dec 2017</date>
+    <revremark>
+      New graphing features. Improve reliability of data
+      download. Update KML export to satisfy Tripoli Records board
+      requirements.
+    </revremark>
+  </revision>
   <revision>
     <revnumber>1.6.4</revnumber>
     <date>10 May 2016</date>
index 4123c783a2bafd192b63e60d350b02f3d879e51f..0c506c286709ab40761f91c61dcc7124c6ddbc0c 100644 (file)
@@ -1,6 +1,37 @@
 [appendix]
 == Release Notes
 
+       :leveloffset: 2
+       include::release-notes-1.8.3.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.8.2.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.8.1.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.8.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.7.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.6.8.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.6.5.raw[]
+
+       <<<<
+       :leveloffset: 2
+       include::release-notes-1.6.4.raw[]
+
        :leveloffset: 2
        include::release-notes-1.6.3.raw[]
 
index 749d0f64b8f18fbc76698d50dba7e68c97648d0d..c6a2a3c9d5decb678bd5d3b656102f97639815bb 100644 (file)
@@ -27,7 +27,7 @@ import java.util.*;
 import org.altusmetrum.altoslib_12.*;
 import org.altusmetrum.altosuilib_12.*;
 
-public class MicroPeak extends MicroFrame implements ActionListener, ItemListener {
+public class MicroPeak extends MicroFrame implements ActionListener, ItemListener, AltosFilterListener {
 
        File            filename;
        AltosGraph      graph;
@@ -206,6 +206,25 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
                Preferences();
        }
 
+       public void filter_changed(double speed_filter, double accel_filter) {
+               data.flight_series.set_filter(speed_filter, accel_filter);
+               graph.filter_changed();
+               data.flight_stats = new AltosFlightStats(data.flight_series);
+               statsTable.filter_changed(data.flight_stats);
+       }
+
+       public double speed_filter() {
+               if (data != null && data.flight_series != null)
+                       return data.flight_series.speed_filter_width;
+               return 4.0;
+       }
+
+       public double accel_filter() {
+               if (data != null && data.flight_series != null)
+                       return data.flight_series.accel_filter_width;
+               return 1.0;
+       }
+
        public MicroPeak() {
 
                ++number_of_windows;
@@ -267,7 +286,7 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
                        }
                });
 
-               enable = new AltosUIEnable();
+               enable = new AltosUIEnable(this);
 
                graph = new AltosGraph(enable);
                statsTable = new AltosFlightStatsTable();
index 661fd33301d4f8207e5e7d1a933dedceef9b462d..8420b37648c0ec0f6175396e3031f8f8549502f9 100644 (file)
@@ -21,7 +21,6 @@ SDCCDIRS=\
        teledongle-v0.2 \
        telemini-v1.0 \
        telebt-v1.0 \
-       teleterra-v0.2 teleshield-v0.1 \
        telefire-v0.1 telefire-v0.2 \
        telerepeat-v1.0
 
@@ -30,15 +29,14 @@ ARMM3DIRS=\
        telemega-v0.1 telemega-v0.1/flash-loader \
        telemega-v1.0 telemega-v1.0/flash-loader \
        telemega-v2.0 telemega-v2.0/flash-loader \
+       telemega-v3.0 telemega-v3.0/flash-loader \
        telemetrum-v2.0 telemetrum-v2.0/flash-loader \
        telemetrum-v3.0 telemetrum-v3.0/flash-loader \
-       megadongle-v0.1 megadongle-v0.1/flash-loader \
        telegps-v0.3 telegps-v0.3/flash-loader \
        telegps-v1.0 telegps-v1.0/flash-loader \
        telegps-v2.0 telegps-v2.0/flash-loader \
        telelco-v0.2 telelco-v0.2/flash-loader \
        telelco-v0.3 telelco-v0.3/flash-loader \
-       telescience-v0.2 telescience-v0.2/flash-loader \
        teledongle-v3.0 teledongle-v3.0/flash-loader \
        teleballoon-v2.0 \
        telebt-v3.0 telebt-v3.0/flash-loader \
@@ -48,14 +46,13 @@ ARMM3DIRS=\
 
 ARMM0DIRS=\
        easymini-v1.0 easymini-v1.0/flash-loader \
-       chaoskey-v0.1 chaoskey-v0.1/flash-loader \
        chaoskey-v1.0 chaoskey-v1.0/flash-loader \
        telemini-v3.0 telemini-v3.0/flash-loader \
        easymini-v2.0 easymini-v2.0/flash-loader \
        micropeak-v2.0 micropeak-v2.0/flash-loader
 
 AVRDIRS=\
-       telescience-v0.1 telescience-pwm micropeak nanopeak-v0.1 microkite
+       micropeak microkite
 
 SUBDIRS=
 
index 0ea30e1dbd4d762e3a44812b6700ccb071bd6cbb..cb2d3db48c03b3968cdca4ddf41fb6c804ce9eae 100644 (file)
@@ -1,7 +1,7 @@
 include ../Makedefs
 CC=$(SDCC)
 
-CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE)
+CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE) -DCC1111
 
 CFLAGS += $(PRODUCT_DEF) -I. -I.. -I../kernel -I../cc1111 -I../drivers -I../product
 
index bacfabb87f53852ba1f63b1803e15f178f76f120..937e6d0c615745695d7efa64cc18a8ca0b36ef5a 100644 (file)
@@ -234,6 +234,10 @@ ao_button_get(uint16_t timeout) __critical;
 void
 ao_button_clear(void) __critical;
 
+/* console I/O funcs */
+#define ao_getchar getchar
+#define ao_putchar putchar
+
 /* ao_string.c */
 
 void
index 10b1f802c645d3c0790b0e10b4c5a83d3f87b736..9d6e1c1d7681576360c2170abf25b1ba709a5700 100644 (file)
@@ -63,6 +63,7 @@
        #define HAS_RADIO_RATE          0       /* not enough space for this */
        #define HAS_MUTEX_TRY           0
        #define HAS_TASK_INFO           0       /* not enough space for this either */
+       #define AO_LOG_FORMAT           AO_LOG_FORMAT_FULL
 #endif
 
 #if defined(TELEMETRUM_V_1_1)
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
        #define HAS_MUTEX_TRY           0
+       #define AO_LOG_FORMAT           AO_LOG_FORMAT_FULL
 #endif
 
 #if defined(TELEMETRUM_V_1_2)
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
        #define HAS_MUTEX_TRY           0
+       #define AO_LOG_FORMAT           AO_LOG_FORMAT_FULL
 #endif
 
 #if defined(TELEDONGLE_V_0_2)
        #define HAS_MONITOR             0
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
+       #define AO_LOG_FORMAT           AO_LOG_FORMAT_TINY
 #endif
 
 #if defined(TELENANO_V_0_1)
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
        #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX        ((uint32_t) 127 * (uint32_t) 1024)
+       #define AO_LOG_FORMAT           AO_LOG_FORMAT_FULL
 #endif
 
 #if defined(TELEDONGLE_V_0_1)
diff --git a/src/cortexelf-v1/.gitignore b/src/cortexelf-v1/.gitignore
new file mode 100644 (file)
index 0000000..0189131
--- /dev/null
@@ -0,0 +1,3 @@
+cortexelf-v1*.elf
+cortexelf-v1*.hex
+ao_product.h
index 8cc6ce314e60d382e591840221cd37cb2b403888..12c658dc22be0ba2980b79a99232ab770e68316a 100644 (file)
@@ -4,7 +4,8 @@
 #
 
 include ../stm/Makefile.defs
-LDFLAGS=-L../stm -Wl,-Tcortexelf.ld
+include ../scheme/Makefile-inc
+
 
 INC = \
        ao.h \
@@ -19,15 +20,12 @@ INC = \
        math.h \
        ao_mpu.h \
        stm32l.h \
-       math.h \
        ao_vga.h \
        ao_draw.h \
        ao_draw_int.h \
        ao_font.h \
        ao_ps2.h \
-       ao_lisp.h \
-       ao_lisp_const.h \
-       ao_lisp_os.h \
+       $(SCHEME_HDRS) \
        ao_flip_bits.h \
        Makefile
 
@@ -46,6 +44,7 @@ ALTOS_SRC = \
        ao_cmd.c \
        ao_config.c \
        ao_task.c \
+       ao_errno.c \
        ao_stdio.c \
        ao_panic.c \
        ao_timer.c \
@@ -74,23 +73,8 @@ ALTOS_SRC = \
        ao_event.c \
        ao_1802.c \
        ao_hex.c \
-       ao_lisp_lex.c \
-       ao_lisp_mem.c \
-       ao_lisp_cons.c \
-       ao_lisp_eval.c \
-       ao_lisp_string.c \
-       ao_lisp_atom.c \
-       ao_lisp_int.c \
-       ao_lisp_poly.c \
-       ao_lisp_builtin.c \
-       ao_lisp_read.c \
-       ao_lisp_rep.c \
-       ao_lisp_frame.c \
-       ao_lisp_error.c \
-       ao_lisp_lambda.c \
-       ao_lisp_save.c \
-       ao_lisp_stack.c \
-       ao_lisp_os_save.c \
+       $(SCHEME_SRCS) \
+       ao_scheme_os_save.c \
        $(PROFILE) \
        $(SAMPLE_PROFILE) \
        $(STACK_GUARD)
@@ -99,12 +83,21 @@ PRODUCT=CortexELF-v1
 PRODUCT_DEF=-DCORTEXELF
 IDPRODUCT=0x000a
 
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
-
 PROGNAME=cortexelf-v1
 PROG=$(PROGNAME)-$(VERSION).elf
 HEX=$(PROGNAME)-$(VERSION).ihx
 
+MAP=$(PROG).map
+
+MAPFILE=-Wl,-M=$(MAP)
+
+LDFLAGS=-L../stm -L/local/newlib-mini/arm-none-eabi/lib/thumb/v7-m/ -Wl,-Tcortexelf.ld $(MAPFILE) -nostartfiles
+AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../draw -I../scheme -I.. -I/local/newlib-mini/arm-none-eabi/include
+LIBS=-lc -lm -lgcc
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+
 SRC=$(ALTOS_SRC) ao_cortexelf.c
 OBJ=$(SRC:.c=.o)
 
@@ -130,7 +123,7 @@ clean::
 ao_flip_bits.h: ao_flip_bits.5c
        nickle ao_flip_bits.5c > $@
 
-include ../lisp/Makefile-lisp
+include ../scheme/Makefile-scheme
 
 install:
 
index 61a9d2199be2fcff5c62b0ccc98f814643797382..5ed78bf09c65865041ef80a530403efd9e331d5e 100644 (file)
@@ -27,7 +27,7 @@
 #include <ao_console.h>
 #include <ao_sdcard.h>
 #include <ao_fat.h>
-#include <ao_lisp.h>
+#include <ao_scheme.h>
 #include <ao_button.h>
 #include <ao_event.h>
 #include <ao_as1107.h>
@@ -188,8 +188,8 @@ ao_console_send(void)
        }
 }
 
-static void lisp_cmd() {
-       ao_lisp_read_eval_print();
+static void scheme_cmd() {
+       ao_scheme_read_eval_print();
 }
 
 static void
@@ -224,7 +224,7 @@ __code struct ao_cmds ao_demo_cmds[] = {
        { ao_ps2_read_keys, "K\0Read keys from keyboard" },
        { ao_console_send, "C\0Send data to console, end with ~" },
        { ao_serial_blather, "S\0Blather on serial ports briefly" },
-       { lisp_cmd, "l\0Run lisp interpreter" },
+       { scheme_cmd, "l\0Run scheme interpreter" },
        { led_cmd, "L start value\0Show value (byte) at digit start" },
        { 0, NULL }
 };
diff --git a/src/cortexelf-v1/ao_lisp_os.h b/src/cortexelf-v1/ao_lisp_os.h
deleted file mode 100644 (file)
index d0c1f7b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright © 2016 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_LISP_OS_H_
-#define _AO_LISP_OS_H_
-
-#include "ao.h"
-
-#define AO_LISP_POOL_TOTAL             16384
-#define AO_LISP_SAVE                   1
-
-static inline int
-ao_lisp_getc() {
-       static uint8_t  at_eol;
-       int c;
-
-       if (at_eol) {
-               ao_cmd_readline();
-               at_eol = 0;
-       }
-       c = ao_cmd_lex();
-       if (c == '\n')
-               at_eol = 1;
-       return c;
-}
-
-static inline void
-ao_lisp_os_flush(void)
-{
-       flush();
-}
-
-static inline void
-ao_lisp_abort(void)
-{
-       ao_panic(1);
-}
-
-static inline void
-ao_lisp_os_led(int led)
-{
-       (void) led;
-}
-
-static inline void
-ao_lisp_os_delay(int delay)
-{
-       ao_delay(AO_MS_TO_TICKS(delay));
-}
-
-#endif
diff --git a/src/cortexelf-v1/ao_lisp_os_save.c b/src/cortexelf-v1/ao_lisp_os_save.c
deleted file mode 100644 (file)
index 7c85399..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-#include <ao.h>
-#include <ao_lisp.h>
-#include <ao_flash.h>
-
-extern uint8_t __flash__[];
-
-/* saved variables to rebuild the heap
-
-   ao_lisp_atoms
-   ao_lisp_frame_global
- */
-
-int
-ao_lisp_os_save(void)
-{
-       int i;
-
-       for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) {
-               uint32_t        *dst = (uint32_t *) (void *) &__flash__[i];
-               uint32_t        *src = (uint32_t *) (void *) &ao_lisp_pool[i];
-
-               ao_flash_page(dst, src);
-       }
-       return 1;
-}
-
-int
-ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset)
-{
-       memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save));
-       return 1;
-}
-
-int
-ao_lisp_os_restore(void)
-{
-       memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL);
-       return 1;
-}
index 258ffe31f79e43518cce3575086614777219eea8..c2bbf2d2f2a1b4dd00d9ba766e450a4f7a95f275 100644 (file)
@@ -62,6 +62,8 @@
 #define USE_SERIAL_2_STDIN     1
 #define SERIAL_2_PA2_PA3       0
 #define SERIAL_2_PD5_PD6       1
+#define USE_SERIAL_2_FLOW      0
+#define USE_SERIAL_2_SW_FLOW   0
 
 #define HAS_SERIAL_3           0
 #define USE_SERIAL_3_STDIN     0
diff --git a/src/cortexelf-v1/ao_scheme_os.h b/src/cortexelf-v1/ao_scheme_os.h
new file mode 100644 (file)
index 0000000..58e4f5b
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_SCHEME_OS_H_
+#define _AO_SCHEME_OS_H_
+
+#include "ao.h"
+
+#define AO_SCHEME_POOL_TOTAL           16384
+#define AO_SCHEME_SAVE                 1
+
+#ifndef __BYTE_ORDER
+#define        __LITTLE_ENDIAN 1234
+#define        __BIG_ENDIAN    4321
+#define __BYTE_ORDER   __LITTLE_ENDIAN
+#endif
+
+static inline int
+ao_scheme_getc() {
+       static uint8_t  at_eol;
+       int c;
+
+       if (at_eol) {
+               ao_cmd_readline();
+               at_eol = 0;
+       }
+       c = ao_cmd_lex();
+       if (c == '\n')
+               at_eol = 1;
+       return c;
+}
+
+static inline void
+ao_scheme_os_flush(void)
+{
+       flush();
+}
+
+static inline void
+ao_scheme_abort(void)
+{
+       ao_panic(1);
+}
+
+static inline void
+ao_scheme_os_led(int led)
+{
+       (void) led;
+}
+
+#define AO_SCHEME_JIFFIES_PER_SECOND   AO_HERTZ
+
+static inline void
+ao_scheme_os_delay(int delay)
+{
+       ao_delay(delay);
+}
+
+static inline int
+ao_scheme_os_jiffy(void)
+{
+       return ao_tick_count;
+}
+
+#endif
diff --git a/src/cortexelf-v1/ao_scheme_os_save.c b/src/cortexelf-v1/ao_scheme_os_save.c
new file mode 100644 (file)
index 0000000..4cec79c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include <ao_scheme.h>
+#include <ao_flash.h>
+
+extern uint8_t __flash__[];
+
+/* saved variables to rebuild the heap
+
+   ao_scheme_atoms
+   ao_scheme_frame_global
+ */
+
+int
+ao_scheme_os_save(void)
+{
+       int i;
+
+       for (i = 0; i < AO_SCHEME_POOL_TOTAL; i += 256) {
+               uint32_t        *dst = (uint32_t *) (void *) &__flash__[i];
+               uint32_t        *src = (uint32_t *) (void *) &ao_scheme_pool[i];
+
+               ao_flash_page(dst, src);
+       }
+       return 1;
+}
+
+int
+ao_scheme_os_restore_save(struct ao_scheme_os_save *save, int offset)
+{
+       memcpy(save, &__flash__[offset], sizeof (struct ao_scheme_os_save));
+       return 1;
+}
+
+int
+ao_scheme_os_restore(void)
+{
+       memcpy(ao_scheme_pool, __flash__, AO_SCHEME_POOL_TOTAL);
+       return 1;
+}
diff --git a/src/drivers/ao_mpu9250.c b/src/drivers/ao_mpu9250.c
new file mode 100644 (file)
index 0000000..ae8dacd
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include <ao_mpu9250.h>
+#include <ao_exti.h>
+
+#if HAS_MPU9250
+
+#define MPU9250_TEST   0
+
+static uint8_t ao_mpu9250_configured;
+
+extern uint8_t ao_sensor_errors;
+
+#ifndef AO_MPU9250_I2C_INDEX
+#define AO_MPU9250_SPI 1
+#else
+#define AO_MPU9250_SPI 0
+#endif
+
+#if AO_MPU9250_SPI
+
+#define ao_mpu9250_spi_get()   ao_spi_get(AO_MPU9250_SPI_BUS, AO_SPI_SPEED_1MHz)
+#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,   \
+                                             (1 << AO_MPU9250_SPI_CS_PIN))
+
+#define ao_mpu9250_spi_end()   ao_spi_clr_cs(AO_MPU9250_SPI_CS_PORT,   \
+                                             (1 << AO_MPU9250_SPI_CS_PIN))
+
+#else
+
+#define ao_mpu9250_spi_get()
+#define ao_mpu9250_spi_put()
+
+#endif
+
+static void
+_ao_mpu9250_reg_write(uint8_t addr, uint8_t value)
+{
+       uint8_t d[2] = { addr, value };
+#if AO_MPU9250_SPI
+       ao_mpu9250_spi_start();
+       ao_spi_send(d, 2, AO_MPU9250_SPI_BUS);
+       ao_mpu9250_spi_end();
+#else
+       ao_i2c_get(AO_MPU9250_I2C_INDEX);
+       ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_WRITE);
+       ao_i2c_send(d, 2, AO_MPU9250_I2C_INDEX, TRUE);
+       ao_i2c_put(AO_MPU9250_I2C_INDEX);
+#endif
+}
+
+static void
+_ao_mpu9250_read(uint8_t addr, void *data, uint8_t len)
+{
+#if AO_MPU9250_SPI
+       addr |= 0x80;
+       ao_mpu9250_spi_start();
+       ao_spi_send(&addr, 1, AO_MPU9250_SPI_BUS);
+       ao_spi_recv(data, len, AO_MPU9250_SPI_BUS);
+       ao_mpu9250_spi_end();
+#else
+       ao_i2c_get(AO_MPU9250_I2C_INDEX);
+       ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_WRITE);
+       ao_i2c_send(&addr, 1, AO_MPU9250_I2C_INDEX, FALSE);
+       ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_READ);
+       ao_i2c_recv(data, len, AO_MPU9250_I2C_INDEX, TRUE);
+       ao_i2c_put(AO_MPU9250_I2C_INDEX);
+#endif
+}
+
+static uint8_t
+_ao_mpu9250_reg_read(uint8_t addr)
+{
+       uint8_t value;
+#if AO_MPU9250_SPI
+       addr |= 0x80;
+       ao_mpu9250_spi_start();
+       ao_spi_send(&addr, 1, AO_MPU9250_SPI_BUS);
+       ao_spi_recv(&value, 1, AO_MPU9250_SPI_BUS);
+       ao_mpu9250_spi_end();
+#else
+       ao_i2c_get(AO_MPU9250_I2C_INDEX);
+       ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_WRITE);
+       ao_i2c_send(&addr, 1, AO_MPU9250_I2C_INDEX, FALSE);
+       ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_READ);
+       ao_i2c_recv(&value, 1, AO_MPU9250_I2C_INDEX, TRUE);
+       ao_i2c_put(AO_MPU9250_I2C_INDEX);
+#endif
+       return value;
+}
+
+static void
+_ao_mpu9250_slv4_setup(uint8_t addr, uint8_t reg)
+{
+       /* Set i2c slave address */
+       _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_ADDR,
+                             addr);
+
+       /* Set i2c register address */
+       _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_REG,
+                             reg);
+}
+
+static void
+_ao_mpu9250_slv4_run(void)
+{
+       uint8_t ctrl;
+
+       /* Start the transfer */
+       _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_CTRL,
+                             (1 << MPU9250_I2C_SLV4_CTRL_I2C_SLV4_EN) |
+                             (0 << MPU9250_I2C_SLV4_CTRL_SLV4_DONE_INT_EN) |
+                             (0 << MPU9250_I2C_SLV4_CTRL_I2C_SLV4_REG_DIS) |
+                             (0 << MPU9250_I2C_SLV4_CTRL_I2C_MST_DLY));
+
+       /* Poll for completion */
+       for (;;) {
+               ctrl = _ao_mpu9250_reg_read(MPU9250_I2C_SLV4_CTRL);
+               if ((ctrl & (1 << MPU9250_I2C_SLV4_CTRL_I2C_SLV4_EN)) == 0)
+                       break;
+               ao_delay(0);
+       }
+}
+
+static uint8_t
+_ao_mpu9250_mag_reg_read(uint8_t reg)
+{
+       _ao_mpu9250_slv4_setup((1 << 7) | MPU9250_MAG_ADDR, reg);
+
+       _ao_mpu9250_slv4_run();
+
+       return _ao_mpu9250_reg_read(MPU9250_I2C_SLV4_DI);
+}
+
+static void
+_ao_mpu9250_mag_reg_write(uint8_t reg, uint8_t value)
+{
+       _ao_mpu9250_slv4_setup((0 << 7) | MPU9250_MAG_ADDR, reg);
+
+       /* Set the data */
+       _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_DO,
+                             value);
+
+       _ao_mpu9250_slv4_run();
+}
+
+static void
+_ao_mpu9250_sample(struct ao_mpu9250_sample *sample)
+{
+       uint16_t        *d = (uint16_t *) sample;
+       int             i = sizeof (*sample) / 2;
+
+       _ao_mpu9250_read(MPU9250_ACCEL_XOUT_H, sample, sizeof (*sample));
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+       /* byte swap */
+       while (i--) {
+               uint16_t        t = *d;
+               *d++ = (t >> 8) | (t << 8);
+       }
+#endif
+}
+
+#define G      981     /* in cm/s² */
+
+#if 0
+static int16_t /* cm/s² */
+ao_mpu9250_accel(int16_t v)
+{
+       return (int16_t) ((v * (int32_t) (16.0 * 980.665 + 0.5)) / 32767);
+}
+
+static int16_t /* deg*10/s */
+ao_mpu9250_gyro(int16_t v)
+{
+       return (int16_t) ((v * (int32_t) 20000) / 32767);
+}
+#endif
+
+static uint8_t
+ao_mpu9250_accel_check(int16_t normal, int16_t test)
+{
+       int16_t diff = test - normal;
+
+       if (diff < MPU9250_ST_ACCEL(16) / 4) {
+               return 1;
+       }
+       if (diff > MPU9250_ST_ACCEL(16) * 4) {
+               return 1;
+       }
+       return 0;
+}
+
+static uint8_t
+ao_mpu9250_gyro_check(int16_t normal, int16_t test)
+{
+       int16_t diff = test - normal;
+
+       if (diff < 0)
+               diff = -diff;
+       if (diff < MPU9250_ST_GYRO(2000) / 4) {
+               return 1;
+       }
+       if (diff > MPU9250_ST_GYRO(2000) * 4) {
+               return 1;
+       }
+       return 0;
+}
+
+static void
+_ao_mpu9250_wait_alive(void)
+{
+       uint8_t i;
+
+       /* Wait for the chip to wake up */
+       for (i = 0; i < 30; i++) {
+               ao_delay(AO_MS_TO_TICKS(100));
+               if (_ao_mpu9250_reg_read(MPU9250_WHO_AM_I) == MPU9250_I_AM_9250)
+                       break;
+       }
+       if (i == 30)
+               ao_panic(AO_PANIC_SELF_TEST_MPU9250);
+}
+
+#define ST_TRIES       10
+#define MAG_TRIES      10
+
+static void
+_ao_mpu9250_setup(void)
+{
+       struct ao_mpu9250_sample        normal_mode, test_mode;
+       int                             errors;
+       int                             st_tries;
+       int                             mag_tries;
+
+       if (ao_mpu9250_configured)
+               return;
+
+       _ao_mpu9250_wait_alive();
+
+       /* Reset the whole chip */
+
+       _ao_mpu9250_reg_write(MPU9250_PWR_MGMT_1,
+                             (1 << MPU9250_PWR_MGMT_1_DEVICE_RESET));
+
+       /* Wait for it to reset. If we talk too quickly, it appears to get confused */
+
+       _ao_mpu9250_wait_alive();
+
+       /* Reset signal conditioning, disabling I2C on SPI systems */
+       _ao_mpu9250_reg_write(MPU9250_USER_CTRL,
+                             (0 << MPU9250_USER_CTRL_FIFO_EN) |
+                             (1 << MPU9250_USER_CTRL_I2C_MST_EN) |
+                             (AO_MPU9250_SPI << MPU9250_USER_CTRL_I2C_IF_DIS) |
+                             (0 << MPU9250_USER_CTRL_FIFO_RESET) |
+                             (0 << MPU9250_USER_CTRL_I2C_MST_RESET) |
+                             (1 << MPU9250_USER_CTRL_SIG_COND_RESET));
+
+       while (_ao_mpu9250_reg_read(MPU9250_USER_CTRL) & (1 << MPU9250_USER_CTRL_SIG_COND_RESET))
+               ao_delay(AO_MS_TO_TICKS(10));
+
+       /* Reset signal paths */
+       _ao_mpu9250_reg_write(MPU9250_SIGNAL_PATH_RESET,
+                             (1 << MPU9250_SIGNAL_PATH_RESET_GYRO_RESET) |
+                             (1 << MPU9250_SIGNAL_PATH_RESET_ACCEL_RESET) |
+                             (1 << MPU9250_SIGNAL_PATH_RESET_TEMP_RESET));
+
+       _ao_mpu9250_reg_write(MPU9250_SIGNAL_PATH_RESET,
+                             (0 << MPU9250_SIGNAL_PATH_RESET_GYRO_RESET) |
+                             (0 << MPU9250_SIGNAL_PATH_RESET_ACCEL_RESET) |
+                             (0 << MPU9250_SIGNAL_PATH_RESET_TEMP_RESET));
+
+       /* Select clocks, disable sleep */
+       _ao_mpu9250_reg_write(MPU9250_PWR_MGMT_1,
+                             (0 << MPU9250_PWR_MGMT_1_DEVICE_RESET) |
+                             (0 << MPU9250_PWR_MGMT_1_SLEEP) |
+                             (0 << MPU9250_PWR_MGMT_1_CYCLE) |
+                             (0 << MPU9250_PWR_MGMT_1_TEMP_DIS) |
+                             (MPU9250_PWR_MGMT_1_CLKSEL_PLL_X_AXIS << MPU9250_PWR_MGMT_1_CLKSEL));
+
+       /* Set I2C clock and options */
+       _ao_mpu9250_reg_write(MPU9250_MST_CTRL,
+                             (0 << MPU9250_MST_CTRL_MULT_MST_EN) |
+                             (0 << MPU9250_MST_CTRL_WAIT_FOR_ES) |
+                             (0 << MPU9250_MST_CTRL_SLV_3_FIFO_EN) |
+                             (0 << MPU9250_MST_CTRL_I2C_MST_P_NSR) |
+                             (MPU9250_MST_CTRL_I2C_MST_CLK_400 << MPU9250_MST_CTRL_I2C_MST_CLK));
+
+       /* Set sample rate divider to sample at full speed */
+       _ao_mpu9250_reg_write(MPU9250_SMPRT_DIV, 0);
+
+       /* Disable filtering */
+       _ao_mpu9250_reg_write(MPU9250_CONFIG,
+                             (MPU9250_CONFIG_EXT_SYNC_SET_DISABLED << MPU9250_CONFIG_EXT_SYNC_SET) |
+                             (MPU9250_CONFIG_DLPF_CFG_250 << MPU9250_CONFIG_DLPF_CFG));
+
+       for (st_tries = 0; st_tries < ST_TRIES; st_tries++) {
+               errors = 0;
+
+               /* Configure accelerometer to +/-16G in self-test mode */
+               _ao_mpu9250_reg_write(MPU9250_ACCEL_CONFIG,
+                                     (1 << MPU9250_ACCEL_CONFIG_XA_ST) |
+                                     (1 << MPU9250_ACCEL_CONFIG_YA_ST) |
+                                     (1 << MPU9250_ACCEL_CONFIG_ZA_ST) |
+                                     (MPU9250_ACCEL_CONFIG_AFS_SEL_16G << MPU9250_ACCEL_CONFIG_AFS_SEL));
+
+               /* Configure gyro to +/- 2000°/s in self-test mode */
+               _ao_mpu9250_reg_write(MPU9250_GYRO_CONFIG,
+                                     (1 << MPU9250_GYRO_CONFIG_XG_ST) |
+                                     (1 << MPU9250_GYRO_CONFIG_YG_ST) |
+                                     (1 << MPU9250_GYRO_CONFIG_ZG_ST) |
+                                     (MPU9250_GYRO_CONFIG_FS_SEL_2000 << MPU9250_GYRO_CONFIG_FS_SEL));
+
+               ao_delay(AO_MS_TO_TICKS(200));
+               _ao_mpu9250_sample(&test_mode);
+
+               /* Configure accelerometer to +/-16G */
+               _ao_mpu9250_reg_write(MPU9250_ACCEL_CONFIG,
+                                     (0 << MPU9250_ACCEL_CONFIG_XA_ST) |
+                                     (0 << MPU9250_ACCEL_CONFIG_YA_ST) |
+                                     (0 << MPU9250_ACCEL_CONFIG_ZA_ST) |
+                                     (MPU9250_ACCEL_CONFIG_AFS_SEL_16G << MPU9250_ACCEL_CONFIG_AFS_SEL));
+
+               /* Configure gyro to +/- 2000°/s */
+               _ao_mpu9250_reg_write(MPU9250_GYRO_CONFIG,
+                                     (0 << MPU9250_GYRO_CONFIG_XG_ST) |
+                                     (0 << MPU9250_GYRO_CONFIG_YG_ST) |
+                                     (0 << MPU9250_GYRO_CONFIG_ZG_ST) |
+                                     (MPU9250_GYRO_CONFIG_FS_SEL_2000 << MPU9250_GYRO_CONFIG_FS_SEL));
+
+               ao_delay(AO_MS_TO_TICKS(200));
+               _ao_mpu9250_sample(&normal_mode);
+
+               errors += ao_mpu9250_accel_check(normal_mode.accel_x, test_mode.accel_x);
+               errors += ao_mpu9250_accel_check(normal_mode.accel_y, test_mode.accel_y);
+               errors += ao_mpu9250_accel_check(normal_mode.accel_z, test_mode.accel_z);
+
+               errors += ao_mpu9250_gyro_check(normal_mode.gyro_x, test_mode.gyro_x);
+               errors += ao_mpu9250_gyro_check(normal_mode.gyro_y, test_mode.gyro_y);
+               errors += ao_mpu9250_gyro_check(normal_mode.gyro_z, test_mode.gyro_z);
+               if (!errors)
+                       break;
+       }
+
+       if (st_tries == ST_TRIES)
+               ao_sensor_errors = 1;
+
+       /* Set up the mag sensor */
+
+       /* make sure it's alive */
+       for (mag_tries = 0; mag_tries < MAG_TRIES; mag_tries++) {
+               if (_ao_mpu9250_mag_reg_read(MPU9250_MAG_WIA) == MPU9250_MAG_WIA_VALUE)
+                       break;
+       }
+
+       if (mag_tries == MAG_TRIES)
+               ao_sensor_errors = 1;
+
+       /* Select continuous mode 2 (100Hz), 16 bit samples */
+
+       _ao_mpu9250_mag_reg_write(MPU9250_MAG_CNTL1,
+                                 (MPU9250_MAG_CNTL1_BIT_16 << MPU9250_MAG_CNTL1_BIT) |
+                                 (MPU9250_MAG_CNTL1_MODE_CONT_2 << MPU9250_MAG_CNTL1_MODE));
+
+       /* Set i2c master to delay shadowing data until read is
+        * complete (avoids tearing the data) */
+
+       _ao_mpu9250_reg_write(MPU9250_I2C_MST_DELAY_CTRL,
+                             (1 << MPU9250_I2C_MST_DELAY_CTRL_DELAY_ES_SHADOW) |
+                             (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV4_DLY_EN) |
+                             (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV3_DLY_EN) |
+                             (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV2_DLY_EN) |
+                             (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV1_DLY_EN) |
+                             (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV0_DLY_EN));
+
+       /* Set up i2c slave 0 to read the mag registers starting at HXL (3) */
+
+       _ao_mpu9250_reg_write(MPU9250_I2C_SLV0_ADDR,
+                             (1 << 7) | MPU9250_MAG_ADDR);
+
+       _ao_mpu9250_reg_write(MPU9250_I2C_SLV0_REG,
+                             MPU9250_MAG_HXL);
+
+       /* Byte swap so the mag values match the gyro/accel. Read 7 bytes
+        * to include the status register
+        */
+
+       _ao_mpu9250_reg_write(MPU9250_I2C_SLV0_CTRL,
+                             (1 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_EN) |
+                             (1 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_BYTE_SW) |
+                             (0 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_REG_DIS) |
+                             (1 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_GRP) |
+                             (MPU9250_MAG_ST2 - MPU9250_MAG_HXL + 1) << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_LENG);
+
+       /* Filter to about 100Hz, which also sets the gyro rate to 1000Hz */
+       _ao_mpu9250_reg_write(MPU9250_CONFIG,
+                             (MPU9250_CONFIG_FIFO_MODE_REPLACE << MPU9250_CONFIG_FIFO_MODE) |
+                             (MPU9250_CONFIG_EXT_SYNC_SET_DISABLED << MPU9250_CONFIG_EXT_SYNC_SET) |
+                             (MPU9250_CONFIG_DLPF_CFG_92 << MPU9250_CONFIG_DLPF_CFG));
+
+       /* Set sample rate divider to sample at 200Hz (v = gyro/rate - 1) */
+       _ao_mpu9250_reg_write(MPU9250_SMPRT_DIV,
+                             1000 / 200 - 1);
+
+       ao_delay(AO_MS_TO_TICKS(100));
+       ao_mpu9250_configured = 1;
+}
+
+struct ao_mpu9250_sample       ao_mpu9250_current;
+
+static void
+ao_mpu9250(void)
+{
+       struct ao_mpu9250_sample        sample;
+
+       /* ao_mpu9250_init already grabbed the SPI bus and mutex */
+       _ao_mpu9250_setup();
+       ao_mpu9250_spi_put();
+       for (;;)
+       {
+               ao_mpu9250_spi_get();
+               _ao_mpu9250_sample(&sample);
+               ao_mpu9250_spi_put();
+               ao_arch_block_interrupts();
+               ao_mpu9250_current = sample;
+               AO_DATA_PRESENT(AO_DATA_MPU9250);
+               AO_DATA_WAIT();
+               ao_arch_release_interrupts();
+       }
+}
+
+static struct ao_task ao_mpu9250_task;
+
+static void
+ao_mpu9250_show(void)
+{
+       printf ("Accel: %7d %7d %7d Gyro: %7d %7d %7d Mag: %7d %7d %7d\n",
+               ao_mpu9250_current.accel_x,
+               ao_mpu9250_current.accel_y,
+               ao_mpu9250_current.accel_z,
+               ao_mpu9250_current.gyro_x,
+               ao_mpu9250_current.gyro_y,
+               ao_mpu9250_current.gyro_z,
+               ao_mpu9250_current.mag_x,
+               ao_mpu9250_current.mag_y,
+               ao_mpu9250_current.mag_z);
+}
+
+#if MPU9250_TEST
+
+static void
+ao_mpu9250_read(void)
+{
+       uint8_t addr;
+       uint8_t val;
+
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       addr = ao_cmd_lex_i;
+       ao_mpu9250_spi_get();
+       val = _ao_mpu9250_reg_read(addr);
+       ao_mpu9250_spi_put();
+       printf("Addr %02x val %02x\n", addr, val);
+}
+
+static void
+ao_mpu9250_write(void)
+{
+       uint8_t addr;
+       uint8_t val;
+
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       addr = ao_cmd_lex_i;
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       val = ao_cmd_lex_i;
+       printf("Addr %02x val %02x\n", addr, val);
+       ao_mpu9250_spi_get();
+       _ao_mpu9250_reg_write(addr, val);
+       ao_mpu9250_spi_put();
+}
+
+static void
+ao_mpu9250_mag_read(void)
+{
+       uint8_t addr;
+       uint8_t val;
+
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       addr = ao_cmd_lex_i;
+       ao_mpu9250_spi_get();
+       val = _ao_mpu9250_mag_reg_read(addr);
+       ao_mpu9250_spi_put();
+       printf("Addr %02x val %02x\n", addr, val);
+}
+
+static void
+ao_mpu9250_mag_write(void)
+{
+       uint8_t addr;
+       uint8_t val;
+
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       addr = ao_cmd_lex_i;
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       val = ao_cmd_lex_i;
+       printf("Addr %02x val %02x\n", addr, val);
+       ao_mpu9250_spi_get();
+       _ao_mpu9250_mag_reg_write(addr, val);
+       ao_mpu9250_spi_put();
+}
+
+#endif /* MPU9250_TEST */
+
+static const struct ao_cmds ao_mpu9250_cmds[] = {
+       { ao_mpu9250_show,      "I\0Show MPU9250 status" },
+#if MPU9250_TEST
+       { ao_mpu9250_read,      "R <addr>\0Read MPU9250 register" },
+       { ao_mpu9250_write,     "W <addr> <val>\0Write MPU9250 register" },
+       { ao_mpu9250_mag_read,  "G <addr>\0Read MPU9250 Mag register" },
+       { ao_mpu9250_mag_write, "P <addr> <val>\0Write MPU9250 Mag register" },
+#endif
+       { 0, NULL }
+};
+
+void
+ao_mpu9250_init(void)
+{
+       ao_mpu9250_configured = 0;
+
+       ao_add_task(&ao_mpu9250_task, ao_mpu9250, "mpu9250");
+
+#if AO_MPU9250_SPI
+       ao_spi_init_cs(AO_MPU9250_SPI_CS_PORT, (1 << AO_MPU9250_SPI_CS_PIN));
+
+       /* Pretend to be the mpu9250 task. Grab the SPI bus right away and
+        * hold it for the task so that nothing else uses the SPI bus before
+        * we get the I2C mode disabled in the chip
+        */
+
+       ao_cur_task = &ao_mpu9250_task;
+       ao_spi_get(AO_MPU9250_SPI_BUS, AO_SPI_SPEED_1MHz);
+       ao_cur_task = NULL;
+#endif
+       ao_cmd_register(&ao_mpu9250_cmds[0]);
+}
+#endif
diff --git a/src/drivers/ao_mpu9250.h b/src/drivers/ao_mpu9250.h
new file mode 100644 (file)
index 0000000..5e8e088
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * 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_MPU9250_H_
+#define _AO_MPU9250_H_
+
+#ifndef M_PI
+#define M_PI 3.1415926535897832384626433
+#endif
+
+#define MPU9250_ADDR_WRITE     0xd0
+#define MPU9250_ADDR_READ      0xd1
+
+/* From Tridge */
+#define MPUREG_XG_OFFS_TC 0x00
+#define MPUREG_YG_OFFS_TC 0x01
+#define MPUREG_ZG_OFFS_TC 0x02
+#define MPUREG_X_FINE_GAIN 0x03
+#define MPUREG_Y_FINE_GAIN 0x04
+#define MPUREG_Z_FINE_GAIN 0x05
+#define MPUREG_XA_OFFS_H 0x06 // X axis accelerometer offset (high byte)
+#define MPUREG_XA_OFFS_L 0x07 // X axis accelerometer offset (low byte)
+#define MPUREG_YA_OFFS_H 0x08 // Y axis accelerometer offset (high byte)
+#define MPUREG_YA_OFFS_L 0x09 // Y axis accelerometer offset (low byte)
+#define MPUREG_ZA_OFFS_H 0x0A // Z axis accelerometer offset (high byte)
+#define MPUREG_ZA_OFFS_L 0x0B // Z axis accelerometer offset (low byte)
+#define MPUREG_PRODUCT_ID 0x0C // Product ID Register
+#define MPUREG_XG_OFFS_USRH 0x13 // X axis gyro offset (high byte)
+#define MPUREG_XG_OFFS_USRL 0x14 // X axis gyro offset (low byte)
+#define MPUREG_YG_OFFS_USRH 0x15 // Y axis gyro offset (high byte)
+#define MPUREG_YG_OFFS_USRL 0x16 // Y axis gyro offset (low byte)
+#define MPUREG_ZG_OFFS_USRH 0x17 // Z axis gyro offset (high byte)
+#define MPUREG_ZG_OFFS_USRL 0x18 // Z axis gyro offset (low byte)
+
+#define MPU9250_SMPRT_DIV      0x19
+
+#define MPU9250_CONFIG         0x1a
+
+#define  MPU9250_CONFIG_FIFO_MODE      6
+# define  MPU9250_CONFIG_FIFO_MODE_REPLACE     0
+# define  MPU9250_CONFIG_FIFO_MODE_DROP                1
+
+#define  MPU9250_CONFIG_EXT_SYNC_SET   3
+#define  MPU9250_CONFIG_EXT_SYNC_SET_DISABLED          0
+#define  MPU9250_CONFIG_EXT_SYNC_SET_TEMP_OUT_L                1
+#define  MPU9250_CONFIG_EXT_SYNC_SET_GYRO_XOUT_L       2
+#define  MPU9250_CONFIG_EXT_SYNC_SET_GYRO_YOUT_L       3
+#define  MPU9250_CONFIG_EXT_SYNC_SET_GYRO_ZOUT_L       4
+#define  MPU9250_CONFIG_EXT_SYNC_SET_ACCEL_XOUT_L      5
+#define  MPU9250_CONFIG_EXT_SYNC_SET_ACCEL_YOUT_L      6
+#define  MPU9250_CONFIG_EXT_SYNC_SET_ACCEL_ZOUT_L      7
+#define  MPU9250_CONFIG_EXT_SYNC_SET_MASK              7
+
+#define  MPU9250_CONFIG_DLPF_CFG       0
+#define  MPU9250_CONFIG_DLPF_CFG_250                   0
+#define  MPU9250_CONFIG_DLPF_CFG_184                   1
+#define  MPU9250_CONFIG_DLPF_CFG_92                    2
+#define  MPU9250_CONFIG_DLPF_CFG_41                    3
+#define  MPU9250_CONFIG_DLPF_CFG_20                    4
+#define  MPU9250_CONFIG_DLPF_CFG_10                    5
+#define  MPU9250_CONFIG_DLPF_CFG_5                     6
+#define  MPU9250_CONFIG_DLPF_CFG_MASK                  7
+
+#define MPU9250_GYRO_CONFIG    0x1b
+# define MPU9250_GYRO_CONFIG_XG_ST     7
+# define MPU9250_GYRO_CONFIG_YG_ST     6
+# define MPU9250_GYRO_CONFIG_ZG_ST     5
+# define MPU9250_GYRO_CONFIG_FS_SEL    3
+# define MPU9250_GYRO_CONFIG_FS_SEL_250                0
+# define MPU9250_GYRO_CONFIG_FS_SEL_500                1
+# define MPU9250_GYRO_CONFIG_FS_SEL_1000       2
+# define MPU9250_GYRO_CONFIG_FS_SEL_2000       3
+# define MPU9250_GYRO_CONFIG_FS_SEL_MASK       3
+# define MPU9250_GYRO_CONFIG_FCHOICE_B 0
+# define MPU9250_GYRO_CONFIG_FCHOICE_B_8800    3
+# define MPU9250_GYRO_CONFIG_FCHOICE_B_3600    2
+# define MPU9250_GYRO_CONFIG_FCHOICE_B_LOW     0
+
+#define MPU9250_ACCEL_CONFIG   0x1c
+# define MPU9250_ACCEL_CONFIG_XA_ST    7
+# define MPU9250_ACCEL_CONFIG_YA_ST    6
+# define MPU9250_ACCEL_CONFIG_ZA_ST    5
+# define MPU9250_ACCEL_CONFIG_AFS_SEL  3
+# define MPU9250_ACCEL_CONFIG_AFS_SEL_2G               0
+# define MPU9250_ACCEL_CONFIG_AFS_SEL_4G               1
+# define MPU9250_ACCEL_CONFIG_AFS_SEL_8G               2
+# define MPU9250_ACCEL_CONFIG_AFS_SEL_16G      3
+# define MPU9250_ACCEL_CONFIG_AFS_SEL_MASK     3
+
+#define MPU9250_MST_CTRL       0x24
+#define  MPU9250_MST_CTRL_MULT_MST_EN          7
+#define  MPU9250_MST_CTRL_WAIT_FOR_ES          6
+#define  MPU9250_MST_CTRL_SLV_3_FIFO_EN                5
+#define  MPU9250_MST_CTRL_I2C_MST_P_NSR                4
+#define  MPU9250_MST_CTRL_I2C_MST_CLK          0
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_348              0
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_333              1
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_320              2
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_308              3
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_296              4
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_286              5
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_276              6
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_267              7
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_258              8
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_500              9
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_471              10
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_444              11
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_421              12
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_400              13
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_381              14
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_364              15
+#define  MPU9250_MST_CTRL_I2C_MST_CLK_MASK             15
+
+#define MPU9250_I2C_SLV0_ADDR  0x25
+#define MPU9250_I2C_SLV0_REG   0x26
+#define MPU9250_I2C_SLV0_CTRL  0x27
+
+#define  MPU9250_I2C_SLV0_CTRL_I2C_SLV0_EN     7
+#define  MPU9250_I2C_SLV0_CTRL_I2C_SLV0_BYTE_SW        6
+#define  MPU9250_I2C_SLV0_CTRL_I2C_SLV0_REG_DIS        5
+#define  MPU9250_I2C_SLV0_CTRL_I2C_SLV0_GRP    4
+#define  MPU9250_I2C_SLV0_CTRL_I2C_SLV0_LENG   0
+
+#define MPU9250_I2C_SLV1_ADDR  0x28
+#define MPU9250_I2C_SLV1_REG   0x29
+#define MPU9250_I2C_SLV1_CTRL  0x2a
+
+#define MPU9250_I2C_SLV2_ADDR  0x2b
+#define MPU9250_I2C_SLV2_REG   0x2c
+#define MPU9250_I2C_SLV2_CTRL  0x2d
+
+#define MPU9250_I2C_SLV3_ADDR  0x2e
+#define MPU9250_I2C_SLV3_REG   0x2f
+#define MPU9250_I2C_SLV3_CTRL  0x30
+
+#define MPU9250_I2C_SLV4_ADDR  0x31
+#define MPU9250_I2C_SLV4_REG   0x32
+#define MPU9250_I2C_SLV4_DO    0x33
+#define MPU9250_I2C_SLV4_CTRL  0x34
+#define  MPU9250_I2C_SLV4_CTRL_I2C_SLV4_EN     7
+#define  MPU9250_I2C_SLV4_CTRL_SLV4_DONE_INT_EN        6
+#define  MPU9250_I2C_SLV4_CTRL_I2C_SLV4_REG_DIS        5
+#define  MPU9250_I2C_SLV4_CTRL_I2C_MST_DLY     0
+
+#define MPU9250_I2C_SLV4_DI    0x35
+
+#define MPU9250_I2C_MST_STATUS 0x36
+
+#define MPU9250_INT_PIN_CFG    0x37
+
+#define MPU9250_INT_ENABLE     0x38
+#define  MPU9250_INT_ENABLE_WOM_EN             6
+#define  MPU9250_INT_ENABLE_FIFO_OFLOW_EN      4
+#define  MPU9250_INT_ENABLE_FSYNC_INT_EN       3
+#define  MPU9250_INT_ENABLE_RAW_RDY_EN         0
+
+#define MPU9250_INT_STATUS     0x3a
+#define  MPU9250_INT_STATUS_WOM_INT            6
+#define  MPU9250_INT_STATUS_FIFO_OFLOW_INT     4
+#define  MPU9250_INT_STATUS_FSYNC_INT          3
+#define  MPU9250_INT_STATUS_RAW_RDY_INT                0
+
+#define MPU9250_ACCEL_XOUT_H           0x3b
+#define MPU9250_ACCEL_XOUT_L           0x3c
+#define MPU9250_ACCEL_YOUT_H           0x3d
+#define MPU9250_ACCEL_YOUT_L           0x3e
+#define MPU9250_ACCEL_ZOUT_H           0x3f
+#define MPU9250_ACCEL_ZOUT_L           0x40
+#define MPU9250_TEMP_H                 0x41
+#define MPU9250_TEMP_L                 0x42
+#define MPU9250_GYRO_XOUT_H            0x43
+#define MPU9250_GYRO_XOUT_L            0x44
+#define MPU9250_GYRO_YOUT_H            0x45
+#define MPU9250_GYRO_YOUT_L            0x46
+#define MPU9250_GYRO_ZOUT_H            0x47
+#define MPU9250_GYRO_ZOUT_L            0x48
+
+#define MPU9250_I2C_MST_DELAY_CTRL     0x67
+
+#define  MPU9250_I2C_MST_DELAY_CTRL_DELAY_ES_SHADOW    7
+#define  MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV4_DLY_EN    4
+#define  MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV3_DLY_EN    3
+#define  MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV2_DLY_EN    2
+#define  MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV1_DLY_EN    1
+#define  MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV0_DLY_EN    0
+
+#define MPU9250_SIGNAL_PATH_RESET      0x68
+#define MPU9250_SIGNAL_PATH_RESET_GYRO_RESET   2
+#define MPU9250_SIGNAL_PATH_RESET_ACCEL_RESET  1
+#define MPU9250_SIGNAL_PATH_RESET_TEMP_RESET   0
+
+#define MPU9250_USER_CTRL              0x6a
+#define MPU9250_USER_CTRL_FIFO_EN              6
+#define MPU9250_USER_CTRL_I2C_MST_EN           5
+#define MPU9250_USER_CTRL_I2C_IF_DIS           4
+#define MPU9250_USER_CTRL_FIFO_RESET           2
+#define MPU9250_USER_CTRL_I2C_MST_RESET                1
+#define MPU9250_USER_CTRL_SIG_COND_RESET       0
+
+#define MPU9250_PWR_MGMT_1     0x6b
+#define MPU9250_PWR_MGMT_1_DEVICE_RESET                7
+#define MPU9250_PWR_MGMT_1_SLEEP               6
+#define MPU9250_PWR_MGMT_1_CYCLE               5
+#define MPU9250_PWR_MGMT_1_TEMP_DIS            3
+#define MPU9250_PWR_MGMT_1_CLKSEL              0
+#define MPU9250_PWR_MGMT_1_CLKSEL_INTERNAL             0
+#define MPU9250_PWR_MGMT_1_CLKSEL_PLL_X_AXIS           1
+#define MPU9250_PWR_MGMT_1_CLKSEL_PLL_Y_AXIS           2
+#define MPU9250_PWR_MGMT_1_CLKSEL_PLL_Z_AXIS           3
+#define MPU9250_PWR_MGMT_1_CLKSEL_PLL_EXTERNAL_32K     4
+#define MPU9250_PWR_MGMT_1_CLKSEL_PLL_EXTERNAL_19M     5
+#define MPU9250_PWR_MGMT_1_CLKSEL_STOP                 7
+#define MPU9250_PWR_MGMT_1_CLKSEL_MASK                 7
+
+#define MPU9250_PWR_MGMT_2     0x6c
+
+#define MPU9250_WHO_AM_I       0x75
+#define MPU9250_I_AM_9250      0x71
+
+/* AK8963 mag sensor on the I2C bus */
+
+#define MPU9250_MAG_ADDR       0x0c
+
+#define MPU9250_MAG_WIA                0x00
+#define  MPU9250_MAG_WIA_VALUE         0x48
+
+#define MPU9250_MAG_INFO       0x01
+#define MPU9250_MAG_ST1        0x02
+#define  MPU9250_MAG_ST1_DOR           1
+#define  MPU9250_MAG_ST1_DRDY          0
+
+#define MPU9250_MAG_HXL                0x03
+#define MPU9250_MAG_HXH                0x04
+#define MPU9250_MAG_HYL                0x05
+#define MPU9250_MAG_HYH                0x06
+#define MPU9250_MAG_HZL                0x07
+#define MPU9250_MAG_HZH                0x08
+#define MPU9250_MAG_ST2                0x09
+#define  MPU9250_MAG_ST2_BITM          4
+#define  MPU9250_MAG_ST2_HOFL          3
+
+#define MPU9250_MAG_CNTL1      0x0a
+#define  MPU9250_MAG_CNTL1_MODE                0
+#define  MPU9250_MAG_CNTL1_MODE_POWER_DOWN     0x0
+#define  MPU9250_MAG_CNTL1_MODE_SINGLE         0x1
+#define  MPU9250_MAG_CNTL1_MODE_CONT_1         0x2     /* 8Hz */
+#define  MPU9250_MAG_CNTL1_MODE_CONT_2         0x6     /* 100Hz */
+#define  MPU9250_MAG_CNTL1_MODE_EXTERNAL       0x4
+#define  MPU9250_MAG_CNTL1_MODE_SELF_TEST      0x8
+#define  MPU9250_MAG_CNTL1_MODE_FUSE_ACCESS    0xf
+
+#define  MPU9250_MAG_CNTL1_BIT         4
+#define  MPU9250_MAG_CNTL1_BIT_14              0
+#define  MPU9250_MAG_CNTL1_BIT_16              1
+
+#define MPU9250_MAG_CNTL2      0x0b
+#define  MPU9250_MAG_CNTL2_SRST                0
+
+#define MPU9250_MAG_ASTC       0x0c
+#define  MPU9250_MAG_ASTC_SELF         6
+
+#define MPU9250_MAG_TS1                0x0d
+#define MPU9250_MAG_TS2                0x0e
+#define MPU9250_MAG_I2CDIS     0x0f
+#define  MPU9250_MAG_I2CDIS_VALUE      0x1d
+
+#define MPU9250_MAG_ASAX       0x10
+#define MPU9250_MAG_ASAY       0x11
+#define MPU9250_MAG_ASAZ       0x12
+
+/* Self test acceleration is approximately 0.5g */
+#define MPU9250_ST_ACCEL(full_scale)   (32767 / ((full_scale) * 2))
+
+/* Self test gyro is approximately 50°/s */
+#define MPU9250_ST_GYRO(full_scale)    ((int16_t) (((int32_t) 32767 * (int32_t) 50) / (full_scale)))
+
+#define MPU9250_GYRO_FULLSCALE ((float) 2000 * M_PI/180.0)
+
+static inline float
+ao_mpu9250_gyro(float sensor) {
+       return sensor * ((float) (MPU9250_GYRO_FULLSCALE / 32767.0));
+}
+
+#define MPU9250_ACCEL_FULLSCALE        16
+
+static inline float
+ao_mpu9250_accel(int16_t sensor) {
+       return (float) sensor * ((float) (MPU9250_ACCEL_FULLSCALE * GRAVITY / 32767.0));
+}
+
+struct ao_mpu9250_sample {
+       int16_t         accel_x;
+       int16_t         accel_y;
+       int16_t         accel_z;
+       int16_t         temp;
+       int16_t         gyro_x;
+       int16_t         gyro_y;
+       int16_t         gyro_z;
+       int16_t         mag_x;
+       int16_t         mag_y;
+       int16_t         mag_z;
+};
+
+extern struct ao_mpu9250_sample        ao_mpu9250_current;
+
+void
+ao_mpu9250_init(void);
+
+/* Product ID Description for MPU9250
+ * high 4 bits low 4 bits
+ * Product Name Product Revision
+ */
+#define MPU9250ES_REV_C4 0x14  /* 0001 0100 */
+#define MPU9250ES_REV_C5 0x15  /* 0001 0101 */
+#define MPU9250ES_REV_D6 0x16  /* 0001 0110 */
+#define MPU9250ES_REV_D7 0x17  /* 0001 0111 */
+#define MPU9250ES_REV_D8 0x18  /* 0001 1000 */
+#define MPU9250_REV_C4 0x54    /* 0101 0100 */
+#define MPU9250_REV_C5 0x55    /* 0101 0101 */
+#define MPU9250_REV_D6 0x56    /* 0101 0110 */
+#define MPU9250_REV_D7 0x57    /* 0101 0111 */
+#define MPU9250_REV_D8 0x58    /* 0101 1000 */
+#define MPU9250_REV_D9 0x59    /* 0101 1001 */
+
+#endif /* _AO_MPU9250_H_ */
index 42a8b09c4de723b1c767cc44e4478786e4fde1f7..b80164786ba1f88b61f8d6df17b1f2e7da03bde6 100644 (file)
@@ -69,6 +69,8 @@
 #define AO_CONFIG_MAX_SIZE                     1024
 #define LOG_ERASE_MARK                         0x55
 #define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMEGA
+
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
 #define USE_EEPROM_CONFIG      1
@@ -84,7 +86,7 @@
 #define HAS_SPI_1              1
 #define SPI_1_PA5_PA6_PA7      1       /* Barometer */
 #define SPI_1_PB3_PB4_PB5      1       /* Accelerometer, Gyro */
-#define SPI_1_PE13_PE14_PE15   0       
+#define SPI_1_PE13_PE14_PE15   0
 #define SPI_1_OSPEEDR          STM_OSPEEDR_10MHz
 
 #define HAS_SPI_2              1
index e56fbb2e4acec01b99a3ce4af8e37147fffc49bf..139050cf78c64136792fbcaf870b170d177f578f 100644 (file)
@@ -78,6 +78,7 @@ typedef AO_PORT_TYPE ao_port_t;
 #define AO_PANIC_SELF_TEST_CC1120      0x40 | 1        /* Self test failure */
 #define AO_PANIC_SELF_TEST_HMC5883     0x40 | 2        /* Self test failure */
 #define AO_PANIC_SELF_TEST_MPU6000     0x40 | 3        /* Self test failure */
+#define AO_PANIC_SELF_TEST_MPU9250     0x40 | 3        /* Self test failure */
 #define AO_PANIC_SELF_TEST_MS5607      0x40 | 4        /* Self test failure */
 
 /* Stop the operating system, beeping and blinking the reason */
index 881f3500ab7efd4c4d5dd992eef09269a3c0d11b..c1e9cef2cc901694a854b3d8a9f4d0c6e33eacda 100644 (file)
@@ -304,7 +304,7 @@ version(void)
               , ao_flight_number
 #endif
 #if HAS_LOG
-              , ao_log_format
+              , AO_LOG_FORMAT
 #if !DISABLE_LOG_SPACE
               , (unsigned long) ao_storage_log_max
 #endif
index d62852efd69cdc707a7dacf8c49e2f898e18514c..88d0e91675a4c7cf61eec8ab454f4fd161e9fe72 100644 (file)
 #define AO_DATA_MPU6000        0
 #endif
 
+#if HAS_MPU9250
+#include <ao_mpu9250.h>
+#define AO_DATA_MPU9250        (1 << 2)
+#else
+#define AO_DATA_MPU9250        0
+#endif
+
 #if HAS_HMC5883
 #include <ao_hmc5883.h>
 #define AO_DATA_HMC5883        (1 << 3)
@@ -57,7 +64,7 @@
 
 #ifdef AO_DATA_RING
 
-#define AO_DATA_ALL    (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X)
+#define AO_DATA_ALL    (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X|AO_DATA_MPU9250)
 
 struct ao_data {
        uint16_t                        tick;
@@ -74,6 +81,9 @@ struct ao_data {
        int16_t                         z_accel;
 #endif
 #endif
+#if HAS_MPU9250
+       struct ao_mpu9250_sample        mpu9250;
+#endif
 #if HAS_HMC5883
        struct ao_hmc5883_sample        hmc5883;
 #endif
@@ -320,6 +330,47 @@ typedef int16_t angle_t;   /* in degrees */
 #define ao_data_pitch(packet)  ((packet)->mpu6000.gyro_x)
 #define ao_data_yaw(packet)    ((packet)->mpu6000.gyro_z)
 
+static inline float ao_convert_gyro(float sensor)
+{
+       return ao_mpu6000_gyro(sensor);
+}
+
+static inline float ao_convert_accel(int16_t sensor)
+{
+       return ao_mpu6000_accel(sensor);
+}
+
+#endif
+
+#if !HAS_GYRO && HAS_MPU9250
+
+#define HAS_GYRO       1
+
+typedef int16_t        gyro_t;         /* in raw sample units */
+typedef int16_t angle_t;       /* in degrees */
+
+/* Y axis is aligned with the direction of motion (along) */
+/* X axis is aligned in the other board axis (across) */
+/* Z axis is aligned perpendicular to the board (through) */
+
+#define ao_data_along(packet)  ((packet)->mpu9250.accel_y)
+#define ao_data_across(packet) ((packet)->mpu9250.accel_x)
+#define ao_data_through(packet)        ((packet)->mpu9250.accel_z)
+
+#define ao_data_roll(packet)   ((packet)->mpu9250.gyro_y)
+#define ao_data_pitch(packet)  ((packet)->mpu9250.gyro_x)
+#define ao_data_yaw(packet)    ((packet)->mpu9250.gyro_z)
+
+static inline float ao_convert_gyro(float sensor)
+{
+       return ao_mpu9250_gyro(sensor);
+}
+
+static inline float ao_convert_accel(int16_t sensor)
+{
+       return ao_mpu9250_accel(sensor);
+}
+
 #endif
 
 #if !HAS_MAG && HAS_HMC5883
@@ -334,4 +385,21 @@ typedef int16_t ao_mag_t;          /* in raw sample units */
 
 #endif
 
+#if !HAS_MAG && HAS_MPU9250
+
+#define HAS_MAG                1
+
+typedef int16_t ao_mag_t;              /* in raw sample units */
+
+/* Note that this order is different from the accel and gyro. For some
+ * reason, the mag sensor axes aren't the same as the other two
+ * sensors. Also, the Z axis is flipped in sign.
+ */
+
+#define ao_data_mag_along(packet)      ((packet)->mpu9250.mag_x)
+#define ao_data_mag_across(packet)     ((packet)->mpu9250.mag_y)
+#define ao_data_mag_through(packet)    ((packet)->mpu9250.mag_z)
+
+#endif
+
 #endif /* _AO_DATA_H_ */
index f06125cd1329f361f7e91e92afcaadc2be420b38..cb02c4549ee20564981f8fafa7c2072b1bdd1b65 100644 (file)
@@ -21,7 +21,7 @@
 #include <ao_log.h>
 #endif
 
-#if HAS_MPU6000
+#if HAS_MPU6000 || HAS_MPU9250
 #include <ao_quaternion.h>
 #endif
 
index 39688fea70693816b1cd70630f9b7265a18e4830..75c2f367ec390a7b2a2311da9909793b0fa52d98 100644 (file)
@@ -45,13 +45,13 @@ ao_gps_report(void)
                        gps_log.u.gps_time.minute = gps_data.minute;
                        gps_log.u.gps_time.second = gps_data.second;
                        gps_log.u.gps_time.flags = gps_data.flags;
-                       ao_log_data(&gps_log);
+                       ao_log_write(&gps_log);
                        gps_log.type = AO_LOG_GPS_LAT;
                        gps_log.u.gps_latitude = gps_data.latitude;
-                       ao_log_data(&gps_log);
+                       ao_log_write(&gps_log);
                        gps_log.type = AO_LOG_GPS_LON;
                        gps_log.u.gps_longitude = gps_data.longitude;
-                       ao_log_data(&gps_log);
+                       ao_log_write(&gps_log);
                        gps_log.type = AO_LOG_GPS_ALT;
                        gps_log.u.gps_altitude.altitude_low = gps_data.altitude_low;
 #if HAS_WIDE_GPS
@@ -59,14 +59,14 @@ ao_gps_report(void)
 #else
                        gps_log.u.gps_altitude.altitude_high = 0xffff;
 #endif
-                       ao_log_data(&gps_log);
+                       ao_log_write(&gps_log);
                        if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
                                gps_log.type = AO_LOG_GPS_DATE;
                                gps_log.u.gps_date.year = gps_data.year;
                                gps_log.u.gps_date.month = gps_data.month;
                                gps_log.u.gps_date.day = gps_data.day;
                                gps_log.u.gps_date.extra = 0;
-                               date_reported = ao_log_data(&gps_log);
+                               date_reported = ao_log_write(&gps_log);
                        }
                }
                if (new & AO_GPS_NEW_TRACKING) {
@@ -78,7 +78,7 @@ ao_gps_report(void)
                                        if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid))
                                        {
                                                gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
-                                               ao_log_data(&gps_log);
+                                               ao_log_write(&gps_log);
                                        }
                        }
                }
index 8a29865577b19a31ec0a7970031a69b20dd9dc4d..85614b85bd3eea31ec2c773e85c146620adaa4a0 100644 (file)
@@ -105,7 +105,7 @@ ao_gps_report_mega(void)
                        gps_log.u.gps.hdop = gps_data.hdop;
                        gps_log.u.gps.vdop = gps_data.vdop;
                        gps_log.u.gps.mode = gps_data.mode;
-                       ao_log_mega(&gps_log);
+                       ao_log_write(&gps_log);
                }
                if ((new & AO_GPS_NEW_TRACKING) && (n = gps_tracking_data.channels) != 0) {
                        gps_log.tick = ao_gps_tick;
@@ -120,7 +120,7 @@ ao_gps_report_mega(void)
                                                break;
                                }
                        gps_log.u.gps_sat.channels = i;
-                       ao_log_mega(&gps_log);
+                       ao_log_write(&gps_log);
                }
        }
 }
index 508f151950bd9730e76b0f2ca1a3b02932f0868c..523fb17fe8529615ce4932d45e3c35012e11d86a 100644 (file)
@@ -47,7 +47,7 @@ ao_gps_report_metrum(void)
                        gps_log.u.gps.longitude = gps_data.longitude;
                        gps_log.u.gps.altitude_low = gps_data.altitude_low;
                        gps_log.u.gps.altitude_high = gps_data.altitude_high;
-                       ao_log_metrum(&gps_log);
+                       ao_log_write(&gps_log);
 
                        gps_log.type = AO_LOG_GPS_TIME;
                        gps_log.u.gps_time.hour = gps_data.hour;
@@ -58,7 +58,7 @@ ao_gps_report_metrum(void)
                        gps_log.u.gps_time.month = gps_data.month;
                        gps_log.u.gps_time.day = gps_data.day;
                        gps_log.u.gps_time.pdop = gps_data.pdop;
-                       ao_log_metrum(&gps_log);
+                       ao_log_write(&gps_log);
                }
 
                if ((new & AO_GPS_NEW_TRACKING) && (n = gps_tracking_data.channels)) {
@@ -71,7 +71,7 @@ ao_gps_report_metrum(void)
                                        if (i == 4) {
                                                gps_log.u.gps_sat.channels = i;
                                                gps_log.u.gps_sat.more = 1;
-                                               ao_log_metrum(&gps_log);
+                                               ao_log_write(&gps_log);
                                                i = 0;
                                        }
                                        gps_log.u.gps_sat.sats[i].svid = svid;
@@ -82,7 +82,7 @@ ao_gps_report_metrum(void)
                        if (i) {
                                gps_log.u.gps_sat.channels = i;
                                gps_log.u.gps_sat.more = 0;
-                               ao_log_metrum(&gps_log);
+                               ao_log_write(&gps_log);
                        }
                }
        }
index a7fa5ec2fa4d498a1220093a86f4ea1579792fef..50583f52929722d14575fd185bdc3fd95389d236 100644 (file)
@@ -111,7 +111,7 @@ ao_dump_state(void *wchan);
 void
 ao_sleep(void *wchan);
 
-const char const * const ao_state_names[] = {
+const char * const ao_state_names[] = {
        "startup", "idle", "pad", "boost", "fast",
        "coast", "drogue", "main", "landed", "invalid"
 };
index 0589b4b00513b4fb8b80b03d22b7275dfc510a2b..f70c723296afb753b930546553cc6ceee44c6792 100644 (file)
@@ -29,7 +29,7 @@ __pdata uint32_t ao_log_end_pos;
 __pdata uint32_t ao_log_start_pos;
 __xdata uint8_t        ao_log_running;
 __pdata enum ao_flight_state ao_log_state;
-__xdata uint16_t ao_flight_number;
+__xdata int16_t ao_flight_number;
 
 void
 ao_log_flush(void)
@@ -111,6 +111,85 @@ ao_log_erase_mark(void)
        ao_config_put();
 }
 
+#ifndef AO_LOG_UNCOMMON
+/*
+ * Common logging functions which depend on the type of the log data
+ * structure.
+ */
+
+__xdata ao_log_type log;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (ao_log_type); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_write(__xdata ao_log_type *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (ao_log_type));
+                       ao_log_current_pos += sizeof (ao_log_type);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+uint8_t
+ao_log_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+uint8_t
+ao_log_check_clear(void)
+{
+       uint8_t *b = (uint8_t *) &log;
+       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_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (ao_log_type)))
+               return -(int16_t) (slot + 1);
+
+       if (ao_log_check_clear())
+               return 0;
+
+       if (!ao_log_check_data() || log.type != AO_LOG_FLIGHT)
+               return -(int16_t) (slot + 1);
+
+       return log.u.flight.flight;
+}
+#endif
+
 static uint8_t
 ao_log_slots()
 {
@@ -123,21 +202,21 @@ ao_log_pos(uint8_t slot)
        return ((slot) * ao_config.flight_log_max);
 }
 
-static uint16_t
+static int16_t
 ao_log_max_flight(void)
 {
        uint8_t         log_slot;
        uint8_t         log_slots;
-       uint16_t        log_flight;
-       uint16_t        max_flight = 0;
+       int16_t         log_flight;
+       int16_t         max_flight = 0;
 
        /* Scan the log space looking for the biggest flight number */
        log_slots = ao_log_slots();
        for (log_slot = 0; log_slot < log_slots; log_slot++) {
                log_flight = ao_log_flight(log_slot);
-               if (!log_flight)
+               if (log_flight <= 0)
                        continue;
-               if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0)
+               if (max_flight == 0 || log_flight > max_flight)
                        max_flight = log_flight;
        }
        return max_flight;
@@ -228,24 +307,24 @@ ao_log_scan(void) __reentrant
 
        if (ao_flight_number) {
                uint32_t        full = ao_log_current_pos;
-               uint32_t        empty = ao_log_end_pos - ao_log_size;
+               uint32_t        empty = ao_log_end_pos - AO_LOG_SIZE;
 
                /* If there's already a flight started, then find the
                 * end of it
                 */
                for (;;) {
                        ao_log_current_pos = (full + empty) >> 1;
-                       ao_log_current_pos -= ao_log_current_pos % ao_log_size;
+                       ao_log_current_pos -= ao_log_current_pos % AO_LOG_SIZE;
 
                        if (ao_log_current_pos == full) {
-                               if (ao_log_check(ao_log_current_pos))
-                                       ao_log_current_pos += ao_log_size;
+                               if (ao_log_check(ao_log_current_pos) != AO_LOG_EMPTY)
+                                       ao_log_current_pos += AO_LOG_SIZE;
                                break;
                        }
                        if (ao_log_current_pos == empty)
                                break;
 
-                       if (ao_log_check(ao_log_current_pos)) {
+                       if (ao_log_check(ao_log_current_pos) != AO_LOG_EMPTY) {
                                full = ao_log_current_pos;
                        } else {
                                empty = ao_log_current_pos;
@@ -259,10 +338,11 @@ ao_log_scan(void) __reentrant
        ao_wakeup(&ao_flight_number);
        return ret;
 #else
-
-       if (ao_flight_number)
-               if (++ao_flight_number == 0)
+       if (ao_flight_number) {
+               ++ao_flight_number;
+               if (ao_flight_number <= 0)
                        ao_flight_number = 1;
+       }
 
        ao_log_find_max_erase_flight();
 
@@ -330,7 +410,7 @@ ao_log_list(void) __reentrant
 {
        uint8_t slot;
        uint8_t slots;
-       uint16_t flight;
+       int16_t flight;
 
        slots = ao_log_slots();
        for (slot = 0; slot < slots; slot++)
@@ -350,18 +430,25 @@ ao_log_delete(void) __reentrant
 {
        uint8_t slot;
        uint8_t slots;
+       int16_t cmd_flight = 1;
 
+       ao_cmd_white();
+       if (ao_cmd_lex_c == '-') {
+               cmd_flight = -1;
+               ao_cmd_lex();
+       }
        ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
+       cmd_flight *= (int16_t) ao_cmd_lex_i;
 
        slots = ao_log_slots();
        /* Look for the flight log matching the requested flight */
-       if (ao_cmd_lex_i) {
+       if (cmd_flight) {
                for (slot = 0; slot < slots; slot++) {
-                       if (ao_log_flight(slot) == ao_cmd_lex_i) {
+                       if (ao_log_flight(slot) == cmd_flight) {
 #if HAS_TRACKER
-                               ao_tracker_erase_start(ao_cmd_lex_i);
+                               ao_tracker_erase_start(cmd_flight);
 #endif
                                ao_log_erase(slot);
 #if HAS_TRACKER
@@ -372,7 +459,7 @@ ao_log_delete(void) __reentrant
                        }
                }
        }
-       printf("No such flight: %d\n", ao_cmd_lex_i);
+       printf("No such flight: %d\n", cmd_flight);
 }
 
 __code struct ao_cmds ao_log_cmds[] = {
index aca669db668c84e5aabbc818f588a59fe299c4a0..5f04ef9ab676839e7b136308803eee200cbf470d 100644 (file)
@@ -29,7 +29,7 @@
  * the log. Tasks may wait for this to be initialized
  * by sleeping on this variable.
  */
-extern __xdata uint16_t ao_flight_number;
+extern __xdata int16_t ao_flight_number;
 extern __xdata uint8_t ao_log_mutex;
 extern __pdata uint32_t ao_log_current_pos;
 extern __pdata uint32_t ao_log_end_pos;
@@ -54,17 +54,28 @@ extern __pdata enum ao_flight_state ao_log_state;
 #define AO_LOG_FORMAT_TELEMINI3                12      /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */
 #define AO_LOG_FORMAT_TELEFIRETWO      13      /* 32-byte test stand data */
 #define AO_LOG_FORMAT_EASYMINI2                14      /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */
+#define AO_LOG_FORMAT_TELEMEGA_3       15      /* 32 byte typed telemega records with 32 bit gyro cal and mpu9250 */
 #define AO_LOG_FORMAT_NONE             127     /* No log at all */
 
-extern __code uint8_t ao_log_format;
-extern __code uint8_t ao_log_size;
+/* Return the flight number from the given log slot, 0 if none, -slot on failure */
 
-/* Return the flight number from the given log slot, 0 if none */
-uint16_t
+int16_t
 ao_log_flight(uint8_t slot);
 
-/* Check if there is valid log data at the specified location */
+/* Checksum the loaded log record */
+uint8_t
+ao_log_check_data(void);
+
+/* Check to see if the loaded log record is empty */
 uint8_t
+ao_log_check_clear(void);
+
+/* Check if there is valid log data at the specified location */
+#define AO_LOG_VALID   1
+#define AO_LOG_EMPTY   0
+#define AO_LOG_INVALID         -1
+
+int8_t
 ao_log_check(uint32_t pos);
 
 /* Flush the log */
@@ -463,21 +474,48 @@ struct ao_log_gps {
        } u;
 };
 
-/* Write a record to the eeprom log */
-uint8_t
-ao_log_data(__xdata struct ao_log_record *log) __reentrant;
+#if AO_LOG_FORMAT == AO_LOG_FOMAT_TELEMEGA_OLD || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMEGA_3
+typedef struct ao_log_mega ao_log_type;
+#endif
 
-uint8_t
-ao_log_mega(__xdata struct ao_log_mega *log) __reentrant;
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMETRUM
+typedef struct ao_log_metrum ao_log_type;
+#endif
 
-uint8_t
-ao_log_metrum(__xdata struct ao_log_metrum *log) __reentrant;
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_EASYMINI1 || AO_LOG_FORMAT == AO_LOG_FORMAT_EASYMINI2 || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMINI2 || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMINI3
+typedef struct ao_log_mini ao_log_type;
+#endif
 
-uint8_t
-ao_log_mini(__xdata struct ao_log_mini *log) __reentrant;
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_TELEGPS
+typedef struct ao_log_gps ao_log_type;
+#endif
+
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_FULL
+typedef struct ao_log_record ao_log_type;
+#endif
+
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_TINY
+#define AO_LOG_UNCOMMON        1
+#endif
+
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMETRY
+#define AO_LOG_UNCOMMON        1
+#endif
+
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_TELESCIENCE
+#define AO_LOG_UNCOMMON        1
+#endif
+
+#ifndef AO_LOG_UNCOMMON
+extern __xdata ao_log_type log;
+
+#define AO_LOG_SIZE sizeof(ao_log_type)
+
+/* Write a record to the eeprom log */
 
 uint8_t
-ao_log_gps(__xdata struct ao_log_gps *log) __reentrant;
+ao_log_write(__xdata ao_log_type *log) __reentrant;
+#endif
 
 void
 ao_log_flush(void);
index e32abd1a69cc7dc18214c3d506d1470b6ffca62e..28a893c700e11a609b2043c85db289c206c5297c 100644 (file)
 
 #include "ao.h"
 
-static __xdata struct ao_log_record log;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL;
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       for (i = 0; i < sizeof (struct ao_log_record); i++)
-               sum += *b++;
-       return -sum;
-}
-
-uint8_t
-ao_log_data(__xdata struct ao_log_record *log) __reentrant
-{
-       uint8_t wrote = 0;
-       /* set checksum */
-       log->csum = 0;
-       log->csum = ao_log_csum((__xdata uint8_t *) log);
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        log,
-                                        sizeof (struct ao_log_record));
-                       ao_log_current_pos += sizeof (struct ao_log_record);
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
-static uint8_t
-ao_log_dump_check_data(void)
-{
-       if (ao_log_csum((uint8_t *) &log) != 0)
-               return 0;
-       return 1;
-}
-
 static __data uint8_t  ao_log_data_pos;
 
 /* a hack to make sure that ao_log_records fill the eeprom block in even units */
@@ -91,7 +47,7 @@ ao_log(void)
        log.u.flight.ground_accel = ao_ground_accel;
 #endif
        log.u.flight.flight = ao_flight_number;
-       ao_log_data(&log);
+       ao_log_write(&log);
 
        /* Write the whole contents of the ring to the log
         * when starting up.
@@ -107,7 +63,7 @@ ao_log(void)
                                log.type = AO_LOG_SENSOR;
                                log.u.sensor.accel = ao_data_ring[ao_log_data_pos].adc.accel;
                                log.u.sensor.pres = ao_data_ring[ao_log_data_pos].adc.pres;
-                               ao_log_data(&log);
+                               ao_log_write(&log);
                                if (ao_log_state <= ao_flight_coast)
                                        next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
                                else
@@ -117,11 +73,11 @@ ao_log(void)
                                log.type = AO_LOG_TEMP_VOLT;
                                log.u.temp_volt.temp = ao_data_ring[ao_log_data_pos].adc.temp;
                                log.u.temp_volt.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
-                               ao_log_data(&log);
+                               ao_log_write(&log);
                                log.type = AO_LOG_DEPLOY;
                                log.u.deploy.drogue = ao_data_ring[ao_log_data_pos].adc.sense_d;
                                log.u.deploy.main = ao_data_ring[ao_log_data_pos].adc.sense_m;
-                               ao_log_data(&log);
+                               ao_log_write(&log);
                                next_other = log.tick + AO_OTHER_INTERVAL;
                        }
                        ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
@@ -133,7 +89,7 @@ ao_log(void)
                        log.tick = ao_sample_tick;
                        log.u.state.state = ao_log_state;
                        log.u.state.reason = 0;
-                       ao_log_data(&log);
+                       ao_log_write(&log);
 
                        if (ao_log_state == ao_flight_landed)
                                ao_log_stop();
@@ -147,16 +103,3 @@ ao_log(void)
                        ao_sleep(&ao_log_running);
        }
 }
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
-       if (!ao_storage_read(ao_log_pos(slot),
-                            &log,
-                            sizeof (struct ao_log_record)))
-               return 0;
-
-       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
-               return log.u.flight.flight;
-       return 0;
-}
index 02551169fd46f80a18a8839f5518ef9d63c22da1..a55d93f115791b0d391e249a03e6e20cd4e9de7e 100644 (file)
 #include <ao_distance.h>
 #include <ao_tracker.h>
 
-static __xdata struct ao_log_gps log;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEGPS;
-__code uint8_t ao_log_size = sizeof (struct ao_log_gps);
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       for (i = 0; i < sizeof (struct ao_log_gps); i++)
-               sum += *b++;
-       return -sum;
-}
-
-uint8_t
-ao_log_gps(__xdata struct ao_log_gps *log) __reentrant
-{
-       uint8_t wrote = 0;
-       /* set checksum */
-       log->csum = 0;
-       log->csum = ao_log_csum((__xdata uint8_t *) log);
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        log,
-                                        sizeof (struct ao_log_gps));
-                       ao_log_current_pos += sizeof (struct ao_log_gps);
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
 void
 ao_log_gps_flight(void)
 {
        log.type = AO_LOG_FLIGHT;
        log.tick = ao_time();
        log.u.flight.flight = ao_flight_number;
-       ao_log_gps(&log);
+       ao_log_write(&log);
 }
 
 void
@@ -94,7 +57,7 @@ ao_log_gps_data(uint16_t tick, struct ao_telemetry_location *gps_data)
        log.u.gps.hdop = gps_data->hdop;
        log.u.gps.vdop = gps_data->vdop;
        log.u.gps.mode = gps_data->mode;
-       ao_log_gps(&log);
+       ao_log_write(&log);
 }
 
 void
@@ -115,39 +78,21 @@ ao_log_gps_tracking(uint16_t tick, struct ao_telemetry_satellite *gps_tracking_d
                                break;
                }
        log.u.gps_sat.channels = i;
-       ao_log_gps(&log);
+       ao_log_write(&log);
 }
 
-static uint8_t
-ao_log_dump_check_data(void)
-{
-       if (ao_log_csum((uint8_t *) &log) != 0)
-               return 0;
-       return 1;
-}
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
-       if (!ao_storage_read(ao_log_pos(slot),
-                            &log,
-                            sizeof (struct ao_log_gps)))
-               return 0;
-
-       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
-               return log.u.flight.flight;
-       return 0;
-}
-
-uint8_t
+int8_t
 ao_log_check(uint32_t pos)
 {
        if (!ao_storage_read(pos,
                             &log,
                             sizeof (struct ao_log_gps)))
-               return 0;
+               return AO_LOG_INVALID;
+
+       if (ao_log_check_clear())
+               return AO_LOG_EMPTY;
 
-       if (ao_log_dump_check_data())
-               return 1;
-       return 0;
+       if (!ao_log_check_data())
+               return AO_LOG_INVALID;
+       return AO_LOG_VALID;
 }
index b86abe7af8ebec882225c88c4f5e34619ff13195..c6bdf1e23c53cba1d4329bccdfdc21a591c8c851 100644 (file)
 #include <ao_data.h>
 #include <ao_flight.h>
 
-static __xdata struct ao_log_mega log;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMEGA;
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       for (i = 0; i < sizeof (struct ao_log_mega); i++)
-               sum += *b++;
-       return -sum;
-}
-
-uint8_t
-ao_log_mega(__xdata struct ao_log_mega *log) __reentrant
-{
-       uint8_t wrote = 0;
-       /* set checksum */
-       log->csum = 0;
-       log->csum = ao_log_csum((__xdata uint8_t *) log);
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        log,
-                                        sizeof (struct ao_log_mega));
-                       ao_log_current_pos += sizeof (struct ao_log_mega);
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
-static uint8_t
-ao_log_dump_check_data(void)
-{
-       if (ao_log_csum((uint8_t *) &log) != 0)
-               return 0;
-       return 1;
-}
-
 #if HAS_FLIGHT
 static __data uint8_t  ao_log_data_pos;
 
@@ -106,7 +62,7 @@ ao_log(void)
 #endif
        log.u.flight.ground_pres = ao_ground_pres;
        log.u.flight.flight = ao_flight_number;
-       ao_log_mega(&log);
+       ao_log_write(&log);
 #endif
 
        /* Write the whole contents of the ring to the log
@@ -137,9 +93,20 @@ ao_log(void)
                                log.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].hmc5883.x;
                                log.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].hmc5883.z;
                                log.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].hmc5883.y;
+#endif
+#if HAS_MPU9250
+                               log.u.sensor.accel_x = ao_data_ring[ao_log_data_pos].mpu9250.accel_x;
+                               log.u.sensor.accel_y = ao_data_ring[ao_log_data_pos].mpu9250.accel_y;
+                               log.u.sensor.accel_z = ao_data_ring[ao_log_data_pos].mpu9250.accel_z;
+                               log.u.sensor.gyro_x = ao_data_ring[ao_log_data_pos].mpu9250.gyro_x;
+                               log.u.sensor.gyro_y = ao_data_ring[ao_log_data_pos].mpu9250.gyro_y;
+                               log.u.sensor.gyro_z = ao_data_ring[ao_log_data_pos].mpu9250.gyro_z;
+                               log.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].mpu9250.mag_x;
+                               log.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].mpu9250.mag_z;
+                               log.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].mpu9250.mag_y;
 #endif
                                log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
-                               ao_log_mega(&log);
+                               ao_log_write(&log);
                                if (ao_log_state <= ao_flight_coast)
                                        next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
                                else
@@ -153,7 +120,7 @@ ao_log(void)
                                for (i = 0; i < AO_ADC_NUM_SENSE; i++)
                                        log.u.volt.sense[i] = ao_data_ring[ao_log_data_pos].adc.sense[i];
                                log.u.volt.pyro = ao_pyro_fired;
-                               ao_log_mega(&log);
+                               ao_log_write(&log);
                                next_other = log.tick + AO_OTHER_INTERVAL;
                        }
                        ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
@@ -166,7 +133,7 @@ ao_log(void)
                        log.tick = ao_time();
                        log.u.state.state = ao_log_state;
                        log.u.state.reason = 0;
-                       ao_log_mega(&log);
+                       ao_log_write(&log);
 
                        if (ao_log_state == ao_flight_landed)
                                ao_log_stop();
@@ -185,15 +152,3 @@ ao_log(void)
 }
 #endif /* HAS_FLIGHT */
 
-uint16_t
-ao_log_flight(uint8_t slot)
-{
-       if (!ao_storage_read(ao_log_pos(slot),
-                            &log,
-                            sizeof (struct ao_log_mega)))
-               return 0;
-
-       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
-               return log.u.flight.flight;
-       return 0;
-}
index 154b1740c6b41cfe93b40ab865fe84c309f72960..afb8f637d292316a393aa4db5e70d056166c435a 100644 (file)
 #include <ao_data.h>
 #include <ao_flight.h>
 
-static __xdata struct ao_log_metrum log;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMETRUM;
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       for (i = 0; i < sizeof (struct ao_log_metrum); i++)
-               sum += *b++;
-       return -sum;
-}
-
-uint8_t
-ao_log_metrum(__xdata struct ao_log_metrum *log) __reentrant
-{
-       uint8_t wrote = 0;
-       /* set checksum */
-       log->csum = 0;
-       log->csum = ao_log_csum((__xdata uint8_t *) log);
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        log,
-                                        sizeof (struct ao_log_metrum));
-                       ao_log_current_pos += sizeof (struct ao_log_metrum);
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
-static uint8_t
-ao_log_dump_check_data(void)
-{
-       if (ao_log_csum((uint8_t *) &log) != 0)
-               return 0;
-       return 1;
-}
-
 #if HAS_ADC
 static __data uint8_t  ao_log_data_pos;
 
@@ -97,7 +53,7 @@ ao_log(void)
 #endif
        log.u.flight.ground_pres = ao_ground_pres;
        log.u.flight.flight = ao_flight_number;
-       ao_log_metrum(&log);
+       ao_log_write(&log);
 #endif
 
        /* Write the whole contents of the ring to the log
@@ -119,7 +75,7 @@ ao_log(void)
 #if HAS_ACCEL
                                log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
 #endif
-                               ao_log_metrum(&log);
+                               ao_log_write(&log);
                                if (ao_log_state <= ao_flight_coast)
                                        next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
                                else
@@ -130,7 +86,7 @@ ao_log(void)
                                log.u.volt.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
                                log.u.volt.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
                                log.u.volt.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
-                               ao_log_metrum(&log);
+                               ao_log_write(&log);
                                next_other = log.tick + AO_OTHER_INTERVAL;
                        }
                        ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
@@ -143,7 +99,7 @@ ao_log(void)
                        log.tick = ao_time();
                        log.u.state.state = ao_log_state;
                        log.u.state.reason = 0;
-                       ao_log_metrum(&log);
+                       ao_log_write(&log);
 
                        if (ao_log_state == ao_flight_landed)
                                ao_log_stop();
@@ -161,16 +117,3 @@ ao_log(void)
        }
 }
 #endif
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
-       if (!ao_storage_read(ao_log_pos(slot),
-                            &log,
-                            sizeof (struct ao_log_metrum)))
-               return 0;
-
-       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
-               return log.u.flight.flight;
-       return 0;
-}
index d5735cdc4a8c66a0c7cc3c24a907ec967aaa64db..af2fa6059e11ca33c66fc8f8817d1b6126717031 100644 (file)
 #include <ao_data.h>
 #include <ao_flight.h>
 
-static __xdata struct ao_log_mini log;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT;
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       for (i = 0; i < sizeof (struct ao_log_mini); i++)
-               sum += *b++;
-       return -sum;
-}
-
-uint8_t
-ao_log_mini(__xdata struct ao_log_mini *log) __reentrant
-{
-       uint8_t wrote = 0;
-       /* set checksum */
-       log->csum = 0;
-       log->csum = ao_log_csum((__xdata uint8_t *) log);
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        log,
-                                        sizeof (struct ao_log_mini));
-                       ao_log_current_pos += sizeof (struct ao_log_mini);
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
-static uint8_t
-ao_log_dump_check_data(void)
-{
-       if (ao_log_csum((uint8_t *) &log) != 0)
-               return 0;
-       return 1;
-}
-
 static __data uint8_t  ao_log_data_pos;
 
 /* a hack to make sure that ao_log_minis fill the eeprom block in even units */
@@ -92,7 +48,7 @@ ao_log(void)
        log.tick = ao_sample_tick;
        log.u.flight.flight = ao_flight_number;
        log.u.flight.ground_pres = ao_ground_pres;
-       ao_log_mini(&log);
+       ao_log_write(&log);
 #endif
 
        /* Write the whole contents of the ring to the log
@@ -116,7 +72,7 @@ ao_log(void)
                                log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
                                log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
 #endif
-                               ao_log_mini(&log);
+                               ao_log_write(&log);
                                if (ao_log_state <= ao_flight_coast)
                                        next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
                                else
@@ -132,7 +88,7 @@ ao_log(void)
                        log.tick = ao_time();
                        log.u.state.state = ao_log_state;
                        log.u.state.reason = 0;
-                       ao_log_mini(&log);
+                       ao_log_write(&log);
 
                        if (ao_log_state == ao_flight_landed)
                                ao_log_stop();
@@ -149,16 +105,3 @@ ao_log(void)
                        ao_sleep(&ao_log_running);
        }
 }
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
-       if (!ao_storage_read(ao_log_pos(slot),
-                            &log,
-                            sizeof (struct ao_log_mini)))
-               return 0;
-
-       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
-               return log.u.flight.flight;
-       return 0;
-}
index 7769b7b5749773c3ffa51a42c90e138d83297172..0b8e39d6aa4d74dc9cad9d6861ac1a8972b062e3 100644 (file)
@@ -29,8 +29,6 @@ static __data uint16_t        ao_log_tiny_interval;
 #define AO_PAD_RING    2
 #endif
 
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY;
-
 void
 ao_log_tiny_set_interval(uint16_t ticks)
 {
@@ -149,7 +147,7 @@ ao_log(void)
        }
 }
 
-uint16_t
+int16_t
 ao_log_flight(uint8_t slot)
 {
        static __xdata uint16_t flight;
index 9543b3ef20cd60f8a9d85f9442ea3ea5dd3d98cd..e5c30eec42da6e1504880684f773da59760bd482 100644 (file)
@@ -76,7 +76,7 @@ uint16_t      ao_pyro_fired;
 
 #if PYRO_DBG
 int pyro_dbg;
-#define DBG(...)       do { if (pyro_dbg) printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } while (0)
+#define DBG(...)       do { if (pyro_dbg) { printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } } while (0)
 #else
 #define DBG(...)
 #endif
@@ -239,11 +239,8 @@ ao_pyro_pins_fire(uint16_t fire)
        }
        ao_delay(ao_config.pyro_time);
        for (p = 0; p < AO_PYRO_NUM; p++) {
-               if (fire & (1 << p)) {
+               if (fire & (1 << p))
                        ao_pyro_pin_set(p, 0);
-                       ao_config.pyro[p].fired = 1;
-                       ao_pyro_fired |= (1 << p);
-               }
        }
        ao_delay(AO_MS_TO_TICKS(50));
 }
@@ -261,7 +258,7 @@ ao_pyro_check(void)
 
                /* Ignore igniters which have already fired
                 */
-               if (pyro->fired)
+               if (ao_pyro_fired & (1 << p))
                        continue;
 
                /* Ignore disabled igniters
@@ -296,7 +293,7 @@ ao_pyro_check(void)
                         * by setting the fired bit
                         */
                        if (!ao_pyro_ready(pyro)) {
-                               pyro->fired = 1;
+                               ao_pyro_fired |= (1 << p);
                                continue;
                        }
 
@@ -307,8 +304,10 @@ ao_pyro_check(void)
                fire |= (1 << p);
        }
 
-       if (fire)
+       if (fire) {
+               ao_pyro_fired |= fire;
                ao_pyro_pins_fire(fire);
+       }
 
        return any_waiting;
 }
@@ -482,7 +481,7 @@ ao_pyro_set(void)
                        break;
 
                for (c = 0; c < AO_PYRO_NAME_LEN - 1; c++) {
-                       if (ao_cmd_is_white())
+                       if (ao_cmd_is_white() || ao_cmd_lex_c == '\n')
                                break;
                        name[c] = ao_cmd_lex_c;
                        ao_cmd_lex();
index a730ef1947c21ee683cf39f2f276cdfa9a16db3d..3ab5af3bf8972d2f2e1ae2f79e482cc96b272e8e 100644 (file)
@@ -63,7 +63,7 @@ struct ao_pyro {
        uint8_t                 state_less, state_greater_or_equal;
        int16_t                 motor;
        uint16_t                delay_done;
-       uint8_t                 fired;
+       uint8_t                 _unused;        /* was 'fired' */
 };
 
 #define AO_PYRO_8_BIT_VALUE    (ao_pyro_state_less|ao_pyro_state_greater_or_equal)
index f0ab0169805fb6a1db38ddde5ca7b803b2f530c9..61519478a2a2c6ab1df8f36c7db14869e37fe20c 100644 (file)
@@ -184,9 +184,9 @@ ao_sample_rotate(void)
 #else
        static const float dt = 1/TIME_DIV;
 #endif
-       float   x = ao_mpu6000_gyro((float) ((ao_sample_pitch << 9) - ao_ground_pitch) / 512.0f) * dt;
-       float   y = ao_mpu6000_gyro((float) ((ao_sample_yaw << 9) - ao_ground_yaw) / 512.0f) * dt;
-       float   z = ao_mpu6000_gyro((float) ((ao_sample_roll << 9) - ao_ground_roll) / 512.0f) * dt;
+       float   x = ao_convert_gyro((float) ((ao_sample_pitch << 9) - ao_ground_pitch) / 512.0f) * dt;
+       float   y = ao_convert_gyro((float) ((ao_sample_yaw << 9) - ao_ground_yaw) / 512.0f) * dt;
+       float   z = ao_convert_gyro((float) ((ao_sample_roll << 9) - ao_ground_roll) / 512.0f) * dt;
        struct ao_quaternion    rot;
 
        ao_quaternion_init_half_euler(&rot, x, y, z);
index f0ee0a14e5070f3b0c61b800dec4eda9526b7edf..dc09b5c772cb37fab569824f25dbe9e602cce8bb 100644 (file)
@@ -84,7 +84,7 @@ __pdata int8_t ao_cur_stdio;
 #endif
 
 void
-putchar(char c)
+ao_putchar(char c)
 {
 #if LOW_LEVEL_DEBUG
        if (!ao_cur_task) {
@@ -110,7 +110,7 @@ flush(void)
 __xdata uint8_t ao_stdin_ready;
 
 char
-getchar(void) __reentrant
+ao_getchar(void) __reentrant
 {
        int c;
        int8_t stdio;
index bee9293e8d1bb1dc7f2a76a9986433b6a5e81a0c..400751de03ca5d8a95debcac49403fa32b681b61 100644 (file)
@@ -22,6 +22,9 @@
 uint8_t
 ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
 {
+#ifdef CC1111
+       return ao_storage_device_read(pos, buf, len);
+#else
        uint16_t this_len;
        uint16_t this_off;
 
@@ -47,11 +50,15 @@ ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
                pos += this_len;
        }
        return 1;
+#endif
 }
 
 uint8_t
 ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
 {
+#ifdef CC1111
+       return ao_storage_device_write(pos, buf, len);
+#else
        uint16_t this_len;
        uint16_t this_off;
 
@@ -77,9 +84,10 @@ ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
                pos += this_len;
        }
        return 1;
+#endif
 }
 
-static __xdata uint8_t storage_data[8];
+static __xdata uint8_t storage_data[128];
 
 static void
 ao_storage_dump(void) __reentrant
@@ -159,6 +167,154 @@ ao_storage_zapall(void) __reentrant
                ao_storage_erase(pos);
 }
 
+#if AO_STORAGE_TEST
+
+static void
+ao_storage_failure(uint32_t pos, char *format, ...)
+{
+       va_list a;
+       printf("TEST FAILURE AT %08x: ", pos);
+       va_start(a, format);
+       vprintf(format, a);
+       va_end(a);
+}
+
+static uint8_t
+ao_storage_check_block(uint32_t pos, uint8_t value)
+{
+       uint32_t        offset;
+       uint32_t        byte;
+
+       for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
+               if (!ao_storage_read(pos + offset, storage_data, sizeof (storage_data))) {
+                       ao_storage_failure(pos + offset, "read failed\n");
+                       return 0;
+               }
+               for (byte = 0; byte < sizeof (storage_data); byte++)
+                       if (storage_data[byte] != value) {
+                               ao_storage_failure(pos + offset + byte,
+                                                  "want %02x got %02x\n",
+                                                  value, storage_data[byte]);
+                               return 0;
+                       }
+       }
+       return 1;
+}
+
+static uint8_t
+ao_storage_fill_block(uint32_t pos, uint8_t value)
+{
+       uint32_t        offset;
+       uint32_t        byte;
+
+       for (byte = 0; byte < sizeof (storage_data); byte++)
+               storage_data[byte] = value;
+       for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
+               if (!ao_storage_write(pos + offset, storage_data, sizeof (storage_data))) {
+                       ao_storage_failure(pos + offset, "write failed\n");
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static uint8_t
+ao_storage_check_incr_block(uint32_t pos)
+{
+       uint32_t        offset;
+       uint32_t        byte;
+
+       for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
+               if (!ao_storage_read(pos + offset, storage_data, sizeof (storage_data))) {
+                       ao_storage_failure(pos + offset, "read failed\n");
+                       return 0;
+               }
+               for (byte = 0; byte < sizeof (storage_data); byte++) {
+                       uint8_t value = offset + byte;
+                       if (storage_data[byte] != value) {
+                               ao_storage_failure(pos + offset + byte,
+                                                  "want %02x got %02x\n",
+                                                  value, storage_data[byte]);
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+
+static uint8_t
+ao_storage_fill_incr_block(uint32_t pos)
+{
+       uint32_t        offset;
+       uint32_t        byte;
+
+       for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_data)) {
+               for (byte = 0; byte < sizeof (storage_data); byte++)
+                       storage_data[byte] = offset + byte;
+               if (!ao_storage_write(pos + offset, storage_data, sizeof (storage_data))) {
+                       ao_storage_failure(pos + offset, "write failed\n");
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static uint8_t
+ao_storage_fill_check_block(uint32_t pos, uint8_t value)
+{
+       return ao_storage_fill_block(pos, value) && ao_storage_check_block(pos, value);
+}
+
+static uint8_t
+ao_storage_incr_check_block(uint32_t pos)
+{
+       return ao_storage_fill_incr_block(pos) && ao_storage_check_incr_block(pos);
+}
+
+static uint8_t
+ao_storage_test_block(uint32_t pos) __reentrant
+{
+       ao_storage_erase(pos);
+       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);
+       printf(" 0xaa"); flush();
+       if (!ao_storage_fill_check_block(pos, 0xaa))
+               return 0;
+       ao_storage_erase(pos);
+       printf(" 0x55"); flush();
+       if (!ao_storage_fill_check_block(pos, 0x55))
+               return 0;
+       ao_storage_erase(pos);
+       printf(" increment"); flush();
+       if (!ao_storage_incr_check_block(pos))
+               return 0;
+       ao_storage_erase(pos);
+       printf(" pass\n"); flush();
+       return 1;
+}
+
+static void
+ao_storage_test(void) __reentrant
+{
+       uint32_t        pos;
+
+       ao_cmd_white();
+       if (!ao_match_word("DoIt"))
+               return;
+       for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) {
+               printf("Testing block 0x%08x:", pos); flush();
+               if (!ao_storage_test_block(pos))
+                       break;
+       }
+       printf("Test complete\n");
+}
+#endif /* AO_STORAGE_TEST */
+
 void
 ao_storage_info(void) __reentrant
 {
@@ -176,6 +332,9 @@ __code struct ao_cmds ao_storage_cmds[] = {
 #endif
        { ao_storage_zap, "z <block>\0Erase <block>" },
        { 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" },
+#endif
        { 0, NULL },
 };
 
index 30b018ffe36aff064afb91b0a8fe1c41e1a20483..7549b59838d6abbc4c85a22e5b42ae4ce7e9449e 100644 (file)
@@ -44,6 +44,9 @@ struct ao_task {
        ao_arch_task_members            /* any architecture-specific fields */
        uint8_t task_id;                /* unique id */
        __code char *name;              /* task name */
+#ifdef NEWLIB
+       int __errno;                    /* storage for errno in newlib libc */
+#endif
 #if HAS_TASK_QUEUE
        struct ao_list  queue;
        struct ao_list  alarm_queue;
index 2ae1e41bb42ffb31701176424c461831c52d98b6..9ed612ceeb263ce8dc10e91e6028522072aaa492 100644 (file)
@@ -141,7 +141,7 @@ ao_send_mega_sensor(void)
        telemetry.generic.tick = packet->tick;
        telemetry.generic.type = AO_TELEMETRY_MEGA_SENSOR;
 
-#if HAS_MPU6000
+#if HAS_MPU6000 || HAS_MPU9250
        telemetry.mega_sensor.orient = ao_sample_orient;
 #endif
        telemetry.mega_sensor.accel = ao_data_accel(packet);
@@ -164,6 +164,20 @@ ao_send_mega_sensor(void)
        telemetry.mega_sensor.mag_y = packet->hmc5883.y;
 #endif
 
+#if HAS_MPU9250
+       telemetry.mega_sensor.accel_x = packet->mpu9250.accel_x;
+       telemetry.mega_sensor.accel_y = packet->mpu9250.accel_y;
+       telemetry.mega_sensor.accel_z = packet->mpu9250.accel_z;
+
+       telemetry.mega_sensor.gyro_x = packet->mpu9250.gyro_x;
+       telemetry.mega_sensor.gyro_y = packet->mpu9250.gyro_y;
+       telemetry.mega_sensor.gyro_z = packet->mpu9250.gyro_z;
+
+       telemetry.mega_sensor.mag_x = packet->mpu9250.mag_x;
+       telemetry.mega_sensor.mag_z = packet->mpu9250.mag_z;
+       telemetry.mega_sensor.mag_y = packet->mpu9250.mag_y;
+#endif
+
        ao_telemetry_send();
 }
 
index 2609bea3653c5c9cd71ebff8b89863f7d361f98e..4eb045b6ff8d9a10df326e383ae273aa8929e437 100644 (file)
@@ -5,6 +5,12 @@
 
 include ../stmf0/Makefile.defs
 
+include ../scheme/Makefile-inc
+
+NEWLIB_FULL=-lm -lc -lgcc
+
+LIBS=$(NEWLIB_FULL)
+
 INC = \
        ao.h \
        ao_arch.h \
@@ -13,9 +19,7 @@ INC = \
        ao_pins.h \
        ao_product.h \
        ao_task.h \
-       ao_lisp.h \
-       ao_lisp_const.h \
-       ao_lisp_os.h \
+       $(SCHEME_HDRS) \
        stm32f0.h \
        Makefile
 
@@ -35,23 +39,8 @@ ALTOS_SRC = \
        ao_timer.c \
        ao_usb_stm.c \
        ao_flash_stm.c \
-       ao_lisp_lex.c \
-       ao_lisp_mem.c \
-       ao_lisp_cons.c \
-       ao_lisp_eval.c \
-       ao_lisp_string.c \
-       ao_lisp_atom.c \
-       ao_lisp_int.c \
-       ao_lisp_poly.c \
-       ao_lisp_builtin.c \
-       ao_lisp_read.c \
-       ao_lisp_rep.c \
-       ao_lisp_frame.c \
-       ao_lisp_error.c \
-       ao_lisp_lambda.c \
-       ao_lisp_save.c \
-       ao_lisp_stack.c \
-       ao_lisp_os_save.c
+       $(SCHEME_SRCS) \
+       ao_scheme_os_save.c
 
 PRODUCT=LambdaKey-v1.0
 PRODUCT_DEF=-DLAMBDAKEY
@@ -61,6 +50,12 @@ CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g
 
 LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld
 
+MAP=$(PROG).map
+NEWLIB=/local/newlib-mini
+MAPFILE=-Wl,-M=$(MAP)
+LDFLAGS=-L../stmf0 -L$(NEWLIB)/arm-none-eabi/lib/thumb/v6-m/ -Wl,-Tlambda.ld $(MAPFILE) -nostartfiles
+AO_CFLAGS=-I. -I../stmf0 -I../kernel -I../drivers -I.. -I../scheme -isystem $(NEWLIB)/arm-none-eabi/include -DNEWLIB
+
 PROGNAME=lambdakey-v1.0
 PROG=$(PROGNAME)-$(VERSION).elf
 HEX=$(PROGNAME)-$(VERSION).ihx
index 8bd344cf57139fe47f9264e7e2f6cf6514e34e2a..d0996eb429c41c0d36a6735676d18ad955675bf1 100644 (file)
  */
 
 #include <ao.h>
-#include <ao_lisp.h>
+#include <ao_scheme.h>
 
-static void lisp_cmd() {
-       ao_lisp_read_eval_print();
+static void scheme_cmd() {
+       ao_scheme_read_eval_print();
 }
 
 static const struct ao_cmds blink_cmds[] = {
-       { lisp_cmd,     "l\0Run lisp interpreter" },
+       { scheme_cmd,   "l\0Run scheme interpreter" },
        { 0, 0 }
 };
 
diff --git a/src/lambdakey-v1.0/ao_lisp_os.h b/src/lambdakey-v1.0/ao_lisp_os.h
deleted file mode 100644 (file)
index 1993ac4..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright © 2016 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_LISP_OS_H_
-#define _AO_LISP_OS_H_
-
-#include "ao.h"
-
-static inline int
-ao_lisp_getc() {
-       static uint8_t  at_eol;
-       int c;
-
-       if (at_eol) {
-               ao_cmd_readline();
-               at_eol = 0;
-       }
-       c = ao_cmd_lex();
-       if (c == '\n')
-               at_eol = 1;
-       return c;
-}
-
-static inline void
-ao_lisp_os_flush(void)
-{
-       flush();
-}
-
-static inline void
-ao_lisp_abort(void)
-{
-       ao_panic(1);
-}
-
-static inline void
-ao_lisp_os_led(int led)
-{
-       ao_led_set(led);
-}
-
-static inline void
-ao_lisp_os_delay(int delay)
-{
-       ao_delay(AO_MS_TO_TICKS(delay));
-}
-
-#endif
diff --git a/src/lambdakey-v1.0/ao_lisp_os_save.c b/src/lambdakey-v1.0/ao_lisp_os_save.c
deleted file mode 100644 (file)
index 4413839..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-#include <ao.h>
-#include <ao_lisp.h>
-#include <ao_flash.h>
-
-extern uint8_t __flash__[];
-
-/* saved variables to rebuild the heap
-
-   ao_lisp_atoms
-   ao_lisp_frame_global
- */
-
-int
-ao_lisp_os_save(void)
-{
-       int i;
-
-       for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) {
-               uint32_t        *dst = (uint32_t *) &__flash__[i];
-               uint32_t        *src = (uint32_t *) &ao_lisp_pool[i];
-
-               ao_flash_page(dst, src);
-       }
-       return 1;
-}
-
-int
-ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset)
-{
-       memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save));
-       return 1;
-}
-
-int
-ao_lisp_os_restore(void)
-{
-       memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL);
-       return 1;
-}
diff --git a/src/lambdakey-v1.0/ao_scheme_os.h b/src/lambdakey-v1.0/ao_scheme_os.h
new file mode 100644 (file)
index 0000000..a620684
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_SCHEME_OS_H_
+#define _AO_SCHEME_OS_H_
+
+#include "ao.h"
+
+#define AO_SCHEME_SAVE 1
+
+#define AO_SCHEME_POOL_TOTAL   2048
+
+#ifndef __BYTE_ORDER
+#define        __LITTLE_ENDIAN 1234
+#define        __BIG_ENDIAN    4321
+#define __BYTE_ORDER   __LITTLE_ENDIAN
+#endif
+
+static inline int
+ao_scheme_getc() {
+       static uint8_t  at_eol;
+       int c;
+
+       if (at_eol) {
+               ao_cmd_readline();
+               at_eol = 0;
+       }
+       c = ao_cmd_lex();
+       if (c == '\n')
+               at_eol = 1;
+       return c;
+}
+
+static inline void
+ao_scheme_os_flush(void)
+{
+       flush();
+}
+
+static inline void
+ao_scheme_abort(void)
+{
+       ao_panic(1);
+}
+
+static inline void
+ao_scheme_os_led(int led)
+{
+       ao_led_set(led);
+}
+
+#define AO_SCHEME_JIFFIES_PER_SECOND   AO_HERTZ
+
+static inline void
+ao_scheme_os_delay(int delay)
+{
+       ao_delay(delay);
+}
+
+static inline int
+ao_scheme_os_jiffy(void)
+{
+       return ao_tick_count;
+}
+#endif
diff --git a/src/lambdakey-v1.0/ao_scheme_os_save.c b/src/lambdakey-v1.0/ao_scheme_os_save.c
new file mode 100644 (file)
index 0000000..184ddb8
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include <ao_scheme.h>
+#include <ao_flash.h>
+
+extern uint8_t __flash__[];
+
+/* saved variables to rebuild the heap
+
+   ao_scheme_atoms
+   ao_scheme_frame_global
+ */
+
+int
+ao_scheme_os_save(void)
+{
+       int i;
+
+       for (i = 0; i < AO_SCHEME_POOL_TOTAL; i += 256) {
+               void    *dst = &__flash__[i];
+               void    *src = &ao_scheme_pool[i];
+
+               ao_flash_page(dst, src);
+       }
+       return 1;
+}
+
+int
+ao_scheme_os_restore_save(struct ao_scheme_os_save *save, int offset)
+{
+       memcpy(save, &__flash__[offset], sizeof (struct ao_scheme_os_save));
+       return 1;
+}
+
+int
+ao_scheme_os_restore(void)
+{
+       memcpy(ao_scheme_pool, __flash__, AO_SCHEME_POOL_TOTAL);
+       return 1;
+}
diff --git a/src/lisp/.gitignore b/src/lisp/.gitignore
deleted file mode 100644 (file)
index 76a555e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ao_lisp_make_const
-ao_lisp_const.h
diff --git a/src/lisp/Makefile b/src/lisp/Makefile
deleted file mode 100644 (file)
index 25796ec..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-all: ao_lisp_const.h
-
-clean:
-       rm -f ao_lisp_const.h $(OBJS) ao_lisp_make_const
-
-ao_lisp_const.h: ao_lisp_const.lisp ao_lisp_make_const
-       ./ao_lisp_make_const -o $@ ao_lisp_const.lisp
-
-include Makefile-inc
-SRCS=$(LISP_SRCS)
-
-HDRS=$(LISP_HDRS)
-
-OBJS=$(SRCS:.c=.o)
-
-CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. -Wall -Wextra -no-pie
-
-
-ao_lisp_make_const:  $(OBJS)
-       $(CC) $(CFLAGS) -o $@ $(OBJS)
-
-$(OBJS): $(HDRS)
diff --git a/src/lisp/Makefile-inc b/src/lisp/Makefile-inc
deleted file mode 100644 (file)
index 126deeb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-LISP_SRCS=\
-       ao_lisp_make_const.c\
-       ao_lisp_mem.c \
-       ao_lisp_cons.c \
-       ao_lisp_string.c \
-       ao_lisp_atom.c \
-       ao_lisp_int.c \
-       ao_lisp_poly.c \
-       ao_lisp_builtin.c \
-       ao_lisp_read.c \
-       ao_lisp_frame.c \
-       ao_lisp_lambda.c \
-       ao_lisp_eval.c \
-       ao_lisp_rep.c \
-       ao_lisp_save.c \
-       ao_lisp_stack.c \
-       ao_lisp_error.c 
-
-LISP_HDRS=\
-       ao_lisp.h \
-       ao_lisp_os.h \
-       ao_lisp_read.h
diff --git a/src/lisp/Makefile-lisp b/src/lisp/Makefile-lisp
deleted file mode 100644 (file)
index 998c767..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../lisp/Makefile-inc
-
-ao_lisp_const.h: $(LISP_SRCS) $(LISP_HDRS)
-       +cd ../lisp && make $@
diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h
deleted file mode 100644 (file)
index 980514c..0000000
+++ /dev/null
@@ -1,793 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _AO_LISP_H_
-#define _AO_LISP_H_
-
-#define DBG_MEM                0
-#define DBG_EVAL       0
-
-#include <stdint.h>
-#include <string.h>
-#include <ao_lisp_os.h>
-
-typedef uint16_t       ao_poly;
-typedef int16_t                ao_signed_poly;
-
-#ifdef AO_LISP_SAVE
-
-struct ao_lisp_os_save {
-       ao_poly         atoms;
-       ao_poly         globals;
-       uint16_t        const_checksum;
-       uint16_t        const_checksum_inv;
-};
-
-#define AO_LISP_POOL_EXTRA     (sizeof(struct ao_lisp_os_save))
-#define AO_LISP_POOL   ((int) (AO_LISP_POOL_TOTAL - AO_LISP_POOL_EXTRA))
-
-int
-ao_lisp_os_save(void);
-
-int
-ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset);
-
-int
-ao_lisp_os_restore(void);
-
-#endif
-
-#ifdef AO_LISP_MAKE_CONST
-#define AO_LISP_POOL_CONST     16384
-extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));
-#define ao_lisp_pool ao_lisp_const
-#define AO_LISP_POOL AO_LISP_POOL_CONST
-
-#define _atom(n) ao_lisp_atom_poly(ao_lisp_atom_intern(n))
-
-#define _ao_lisp_atom_quote    _atom("quote")
-#define _ao_lisp_atom_set      _atom("set")
-#define _ao_lisp_atom_setq     _atom("setq")
-#define _ao_lisp_atom_t        _atom("t")
-#define _ao_lisp_atom_car      _atom("car")
-#define _ao_lisp_atom_cdr      _atom("cdr")
-#define _ao_lisp_atom_cons     _atom("cons")
-#define _ao_lisp_atom_last     _atom("last")
-#define _ao_lisp_atom_length   _atom("length")
-#define _ao_lisp_atom_cond     _atom("cond")
-#define _ao_lisp_atom_lambda   _atom("lambda")
-#define _ao_lisp_atom_led      _atom("led")
-#define _ao_lisp_atom_delay    _atom("delay")
-#define _ao_lisp_atom_pack     _atom("pack")
-#define _ao_lisp_atom_unpack   _atom("unpack")
-#define _ao_lisp_atom_flush    _atom("flush")
-#define _ao_lisp_atom_eval     _atom("eval")
-#define _ao_lisp_atom_read     _atom("read")
-#define _ao_lisp_atom_eof      _atom("eof")
-#define _ao_lisp_atom_save     _atom("save")
-#define _ao_lisp_atom_restore  _atom("restore")
-#define _ao_lisp_atom_call2fcc _atom("call/cc")
-#define _ao_lisp_atom_collect  _atom("collect")
-#define _ao_lisp_atom_symbolp   _atom("symbol?")
-#define _ao_lisp_atom_builtin   _atom("builtin?")
-#define _ao_lisp_atom_symbolp   _atom("symbol?")
-#define _ao_lisp_atom_symbolp   _atom("symbol?")
-#else
-#include "ao_lisp_const.h"
-#ifndef AO_LISP_POOL
-#define AO_LISP_POOL   3072
-#endif
-extern uint8_t         ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4)));
-#endif
-
-/* Primitive types */
-#define AO_LISP_CONS           0
-#define AO_LISP_INT            1
-#define AO_LISP_STRING         2
-#define AO_LISP_OTHER          3
-
-#define AO_LISP_TYPE_MASK      0x0003
-#define AO_LISP_TYPE_SHIFT     2
-#define AO_LISP_REF_MASK       0x7ffc
-#define AO_LISP_CONST          0x8000
-
-/* These have a type value at the start of the struct */
-#define AO_LISP_ATOM           4
-#define AO_LISP_BUILTIN                5
-#define AO_LISP_FRAME          6
-#define AO_LISP_LAMBDA         7
-#define AO_LISP_STACK          8
-#define AO_LISP_NUM_TYPE       9
-
-/* Leave two bits for types to use as they please */
-#define AO_LISP_OTHER_TYPE_MASK        0x3f
-
-#define AO_LISP_NIL    0
-
-extern uint16_t                ao_lisp_top;
-
-#define AO_LISP_OOM            0x01
-#define AO_LISP_DIVIDE_BY_ZERO 0x02
-#define AO_LISP_INVALID                0x04
-#define AO_LISP_UNDEFINED      0x08
-#define AO_LISP_EOF            0x10
-
-extern uint8_t         ao_lisp_exception;
-
-static inline int
-ao_lisp_is_const(ao_poly poly) {
-       return poly & AO_LISP_CONST;
-}
-
-#define AO_LISP_IS_CONST(a)    (ao_lisp_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_const + AO_LISP_POOL_CONST)
-#define AO_LISP_IS_POOL(a)     (ao_lisp_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL)
-#define AO_LISP_IS_INT(p)      (ao_lisp_base_type(p) == AO_LISP_INT);
-
-void *
-ao_lisp_ref(ao_poly poly);
-
-ao_poly
-ao_lisp_poly(const void *addr, ao_poly type);
-
-struct ao_lisp_type {
-       int     (*size)(void *addr);
-       void    (*mark)(void *addr);
-       void    (*move)(void *addr);
-       char    name[];
-};
-
-struct ao_lisp_cons {
-       ao_poly         car;
-       ao_poly         cdr;
-};
-
-struct ao_lisp_atom {
-       uint8_t         type;
-       uint8_t         pad[1];
-       ao_poly         next;
-       char            name[];
-};
-
-struct ao_lisp_val {
-       ao_poly         atom;
-       ao_poly         val;
-};
-
-struct ao_lisp_frame {
-       uint8_t                 type;
-       uint8_t                 num;
-       ao_poly                 prev;
-       struct ao_lisp_val      vals[];
-};
-
-/* Set on type when the frame escapes the lambda */
-#define AO_LISP_FRAME_MARK     0x80
-#define AO_LISP_FRAME_PRINT    0x40
-
-static inline int ao_lisp_frame_marked(struct ao_lisp_frame *f) {
-       return f->type & AO_LISP_FRAME_MARK;
-}
-
-static inline struct ao_lisp_frame *
-ao_lisp_poly_frame(ao_poly poly) {
-       return ao_lisp_ref(poly);
-}
-
-static inline ao_poly
-ao_lisp_frame_poly(struct ao_lisp_frame *frame) {
-       return ao_lisp_poly(frame, AO_LISP_OTHER);
-}
-
-enum eval_state {
-       eval_sexpr,             /* Evaluate an sexpr */
-       eval_val,               /* Value computed */
-       eval_formal,            /* Formal computed */
-       eval_exec,              /* Start a lambda evaluation */
-       eval_cond,              /* Start next cond clause */
-       eval_cond_test,         /* Check cond condition */
-       eval_progn,             /* Start next progn entry */
-       eval_while,             /* Start while condition */
-       eval_while_test,        /* Check while condition */
-       eval_macro,             /* Finished with macro generation */
-};
-
-struct ao_lisp_stack {
-       uint8_t                 type;           /* AO_LISP_STACK */
-       uint8_t                 state;          /* enum eval_state */
-       ao_poly                 prev;           /* previous stack frame */
-       ao_poly                 sexprs;         /* expressions to evaluate */
-       ao_poly                 values;         /* values computed */
-       ao_poly                 values_tail;    /* end of the values list for easy appending */
-       ao_poly                 frame;          /* current lookup frame */
-       ao_poly                 list;           /* most recent function call */
-};
-
-#define AO_LISP_STACK_MARK     0x80    /* set on type when a reference has been taken */
-#define AO_LISP_STACK_PRINT    0x40    /* stack is being printed */
-
-static inline int ao_lisp_stack_marked(struct ao_lisp_stack *s) {
-       return s->type & AO_LISP_STACK_MARK;
-}
-
-static inline void ao_lisp_stack_mark(struct ao_lisp_stack *s) {
-       s->type |= AO_LISP_STACK_MARK;
-}
-
-static inline struct ao_lisp_stack *
-ao_lisp_poly_stack(ao_poly p)
-{
-       return ao_lisp_ref(p);
-}
-
-static inline ao_poly
-ao_lisp_stack_poly(struct ao_lisp_stack *stack)
-{
-       return ao_lisp_poly(stack, AO_LISP_OTHER);
-}
-
-extern ao_poly                 ao_lisp_v;
-
-#define AO_LISP_FUNC_LAMBDA    0
-#define AO_LISP_FUNC_NLAMBDA   1
-#define AO_LISP_FUNC_MACRO     2
-#define AO_LISP_FUNC_LEXPR     3
-
-#define AO_LISP_FUNC_FREE_ARGS 0x80
-#define AO_LISP_FUNC_MASK      0x7f
-
-#define AO_LISP_FUNC_F_LAMBDA  (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LAMBDA)
-#define AO_LISP_FUNC_F_NLAMBDA (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_NLAMBDA)
-#define AO_LISP_FUNC_F_MACRO   (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_MACRO)
-#define AO_LISP_FUNC_F_LEXPR   (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LEXPR)
-
-struct ao_lisp_builtin {
-       uint8_t         type;
-       uint8_t         args;
-       uint16_t        func;
-};
-
-enum ao_lisp_builtin_id {
-       builtin_eval,
-       builtin_read,
-       builtin_lambda,
-       builtin_lexpr,
-       builtin_nlambda,
-       builtin_macro,
-       builtin_car,
-       builtin_cdr,
-       builtin_cons,
-       builtin_last,
-       builtin_length,
-       builtin_quote,
-       builtin_set,
-       builtin_setq,
-       builtin_cond,
-       builtin_progn,
-       builtin_while,
-       builtin_print,
-       builtin_patom,
-       builtin_plus,
-       builtin_minus,
-       builtin_times,
-       builtin_divide,
-       builtin_mod,
-       builtin_equal,
-       builtin_less,
-       builtin_greater,
-       builtin_less_equal,
-       builtin_greater_equal,
-       builtin_pack,
-       builtin_unpack,
-       builtin_flush,
-       builtin_delay,
-       builtin_led,
-       builtin_save,
-       builtin_restore,
-       builtin_call_cc,
-       builtin_collect,
-       _builtin_last
-};
-
-typedef ao_poly (*ao_lisp_func_t)(struct ao_lisp_cons *cons);
-
-extern const ao_lisp_func_t    ao_lisp_builtins[];
-
-static inline ao_lisp_func_t
-ao_lisp_func(struct ao_lisp_builtin *b)
-{
-       return ao_lisp_builtins[b->func];
-}
-
-struct ao_lisp_lambda {
-       uint8_t         type;
-       uint8_t         args;
-       ao_poly         code;
-       ao_poly         frame;
-};
-
-static inline struct ao_lisp_lambda *
-ao_lisp_poly_lambda(ao_poly poly)
-{
-       return ao_lisp_ref(poly);
-}
-
-static inline ao_poly
-ao_lisp_lambda_poly(struct ao_lisp_lambda *lambda)
-{
-       return ao_lisp_poly(lambda, AO_LISP_OTHER);
-}
-
-static inline void *
-ao_lisp_poly_other(ao_poly poly) {
-       return ao_lisp_ref(poly);
-}
-
-static inline uint8_t
-ao_lisp_other_type(void *other) {
-#if DBG_MEM
-       if ((*((uint8_t *) other) & AO_LISP_OTHER_TYPE_MASK) >= AO_LISP_NUM_TYPE)
-               ao_lisp_abort();
-#endif
-       return *((uint8_t *) other) & AO_LISP_OTHER_TYPE_MASK;
-}
-
-static inline ao_poly
-ao_lisp_other_poly(const void *other)
-{
-       return ao_lisp_poly(other, AO_LISP_OTHER);
-}
-
-static inline int
-ao_lisp_size_round(int size)
-{
-       return (size + 3) & ~3;
-}
-
-static inline int
-ao_lisp_size(const struct ao_lisp_type *type, void *addr)
-{
-       return ao_lisp_size_round(type->size(addr));
-}
-
-#define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER)
-
-static inline int ao_lisp_poly_base_type(ao_poly poly) {
-       return poly & AO_LISP_TYPE_MASK;
-}
-
-static inline int ao_lisp_poly_type(ao_poly poly) {
-       int     type = poly & AO_LISP_TYPE_MASK;
-       if (type == AO_LISP_OTHER)
-               return ao_lisp_other_type(ao_lisp_poly_other(poly));
-       return type;
-}
-
-static inline struct ao_lisp_cons *
-ao_lisp_poly_cons(ao_poly poly)
-{
-       return ao_lisp_ref(poly);
-}
-
-static inline ao_poly
-ao_lisp_cons_poly(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_poly(cons, AO_LISP_CONS);
-}
-
-static inline int
-ao_lisp_poly_int(ao_poly poly)
-{
-       return (int) ((ao_signed_poly) poly >> AO_LISP_TYPE_SHIFT);
-}
-
-static inline ao_poly
-ao_lisp_int_poly(int i)
-{
-       return ((ao_poly) i << 2) | AO_LISP_INT;
-}
-
-static inline char *
-ao_lisp_poly_string(ao_poly poly)
-{
-       return ao_lisp_ref(poly);
-}
-
-static inline ao_poly
-ao_lisp_string_poly(char *s)
-{
-       return ao_lisp_poly(s, AO_LISP_STRING);
-}
-
-static inline struct ao_lisp_atom *
-ao_lisp_poly_atom(ao_poly poly)
-{
-       return ao_lisp_ref(poly);
-}
-
-static inline ao_poly
-ao_lisp_atom_poly(struct ao_lisp_atom *a)
-{
-       return ao_lisp_poly(a, AO_LISP_OTHER);
-}
-
-static inline struct ao_lisp_builtin *
-ao_lisp_poly_builtin(ao_poly poly)
-{
-       return ao_lisp_ref(poly);
-}
-
-static inline ao_poly
-ao_lisp_builtin_poly(struct ao_lisp_builtin *b)
-{
-       return ao_lisp_poly(b, AO_LISP_OTHER);
-}
-
-/* memory functions */
-
-extern int ao_lisp_collects[2];
-extern int ao_lisp_freed[2];
-extern int ao_lisp_loops[2];
-
-/* returns 1 if the object was already marked */
-int
-ao_lisp_mark(const struct ao_lisp_type *type, void *addr);
-
-/* returns 1 if the object was already marked */
-int
-ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr);
-
-void *
-ao_lisp_move_map(void *addr);
-
-/* returns 1 if the object was already moved */
-int
-ao_lisp_move(const struct ao_lisp_type *type, void **ref);
-
-/* returns 1 if the object was already moved */
-int
-ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref);
-
-void *
-ao_lisp_alloc(int size);
-
-#define AO_LISP_COLLECT_FULL           1
-#define AO_LISP_COLLECT_INCREMENTAL    0
-
-int
-ao_lisp_collect(uint8_t style);
-
-void
-ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons);
-
-struct ao_lisp_cons *
-ao_lisp_cons_fetch(int id);
-
-void
-ao_lisp_poly_stash(int id, ao_poly poly);
-
-ao_poly
-ao_lisp_poly_fetch(int id);
-
-void
-ao_lisp_string_stash(int id, char *string);
-
-char *
-ao_lisp_string_fetch(int id);
-
-static inline void
-ao_lisp_stack_stash(int id, struct ao_lisp_stack *stack) {
-       ao_lisp_poly_stash(id, ao_lisp_stack_poly(stack));
-}
-
-static inline struct ao_lisp_stack *
-ao_lisp_stack_fetch(int id) {
-       return ao_lisp_poly_stack(ao_lisp_poly_fetch(id));
-}
-
-/* cons */
-extern const struct ao_lisp_type ao_lisp_cons_type;
-
-struct ao_lisp_cons *
-ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr);
-
-extern struct ao_lisp_cons *ao_lisp_cons_free_list;
-
-void
-ao_lisp_cons_free(struct ao_lisp_cons *cons);
-
-void
-ao_lisp_cons_print(ao_poly);
-
-void
-ao_lisp_cons_patom(ao_poly);
-
-int
-ao_lisp_cons_length(struct ao_lisp_cons *cons);
-
-/* string */
-extern const struct ao_lisp_type ao_lisp_string_type;
-
-char *
-ao_lisp_string_copy(char *a);
-
-char *
-ao_lisp_string_cat(char *a, char *b);
-
-ao_poly
-ao_lisp_string_pack(struct ao_lisp_cons *cons);
-
-ao_poly
-ao_lisp_string_unpack(char *a);
-
-void
-ao_lisp_string_print(ao_poly s);
-
-void
-ao_lisp_string_patom(ao_poly s);
-
-/* atom */
-extern const struct ao_lisp_type ao_lisp_atom_type;
-
-extern struct ao_lisp_atom     *ao_lisp_atoms;
-extern struct ao_lisp_frame    *ao_lisp_frame_global;
-extern struct ao_lisp_frame    *ao_lisp_frame_current;
-
-void
-ao_lisp_atom_print(ao_poly a);
-
-struct ao_lisp_atom *
-ao_lisp_atom_intern(char *name);
-
-ao_poly *
-ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom);
-
-ao_poly
-ao_lisp_atom_get(ao_poly atom);
-
-ao_poly
-ao_lisp_atom_set(ao_poly atom, ao_poly val);
-
-/* int */
-void
-ao_lisp_int_print(ao_poly i);
-
-/* prim */
-void
-ao_lisp_poly_print(ao_poly p);
-
-void
-ao_lisp_poly_patom(ao_poly p);
-
-int
-ao_lisp_poly_mark(ao_poly p, uint8_t note_cons);
-
-/* returns 1 if the object has already been moved */
-int
-ao_lisp_poly_move(ao_poly *p, uint8_t note_cons);
-
-/* eval */
-
-void
-ao_lisp_eval_clear_globals(void);
-
-int
-ao_lisp_eval_restart(void);
-
-ao_poly
-ao_lisp_eval(ao_poly p);
-
-ao_poly
-ao_lisp_set_cond(struct ao_lisp_cons *cons);
-
-/* builtin */
-void
-ao_lisp_builtin_print(ao_poly b);
-
-extern const struct ao_lisp_type ao_lisp_builtin_type;
-
-/* Check argument count */
-ao_poly
-ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max);
-
-/* Check argument type */
-ao_poly
-ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok);
-
-/* Fetch an arg (nil if off the end) */
-ao_poly
-ao_lisp_arg(struct ao_lisp_cons *cons, int argc);
-
-char *
-ao_lisp_args_name(uint8_t args);
-
-/* read */
-extern struct ao_lisp_cons     *ao_lisp_read_cons;
-extern struct ao_lisp_cons     *ao_lisp_read_cons_tail;
-extern struct ao_lisp_cons     *ao_lisp_read_stack;
-
-ao_poly
-ao_lisp_read(void);
-
-/* rep */
-ao_poly
-ao_lisp_read_eval_print(void);
-
-/* frame */
-extern const struct ao_lisp_type ao_lisp_frame_type;
-
-#define AO_LISP_FRAME_FREE     6
-
-extern struct ao_lisp_frame    *ao_lisp_frame_free_list[AO_LISP_FRAME_FREE];
-
-ao_poly
-ao_lisp_frame_mark(struct ao_lisp_frame *frame);
-
-ao_poly *
-ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom);
-
-struct ao_lisp_frame *
-ao_lisp_frame_new(int num);
-
-void
-ao_lisp_frame_free(struct ao_lisp_frame *frame);
-
-void
-ao_lisp_frame_bind(struct ao_lisp_frame *frame, int num, ao_poly atom, ao_poly val);
-
-int
-ao_lisp_frame_add(struct ao_lisp_frame **frame, ao_poly atom, ao_poly val);
-
-void
-ao_lisp_frame_print(ao_poly p);
-
-/* lambda */
-extern const struct ao_lisp_type ao_lisp_lambda_type;
-
-extern const char *ao_lisp_state_names[];
-
-struct ao_lisp_lambda *
-ao_lisp_lambda_new(ao_poly cons);
-
-void
-ao_lisp_lambda_print(ao_poly lambda);
-
-ao_poly
-ao_lisp_lambda(struct ao_lisp_cons *cons);
-
-ao_poly
-ao_lisp_lexpr(struct ao_lisp_cons *cons);
-
-ao_poly
-ao_lisp_nlambda(struct ao_lisp_cons *cons);
-
-ao_poly
-ao_lisp_macro(struct ao_lisp_cons *cons);
-
-ao_poly
-ao_lisp_lambda_eval(void);
-
-/* save */
-
-ao_poly
-ao_lisp_save(struct ao_lisp_cons *cons);
-
-ao_poly
-ao_lisp_restore(struct ao_lisp_cons *cons);
-
-/* stack */
-
-extern const struct ao_lisp_type ao_lisp_stack_type;
-extern struct ao_lisp_stack    *ao_lisp_stack;
-extern struct ao_lisp_stack    *ao_lisp_stack_free_list;
-
-void
-ao_lisp_stack_reset(struct ao_lisp_stack *stack);
-
-int
-ao_lisp_stack_push(void);
-
-void
-ao_lisp_stack_pop(void);
-
-void
-ao_lisp_stack_clear(void);
-
-void
-ao_lisp_stack_print(ao_poly stack);
-
-ao_poly
-ao_lisp_stack_eval(void);
-
-ao_poly
-ao_lisp_call_cc(struct ao_lisp_cons *cons);
-
-/* error */
-
-void
-ao_lisp_error_poly(char *name, ao_poly poly, ao_poly last);
-
-void
-ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame);
-
-ao_poly
-ao_lisp_error(int error, char *format, ...);
-
-/* debugging macros */
-
-#if DBG_EVAL
-#define DBG_CODE       1
-int ao_lisp_stack_depth;
-#define DBG_DO(a)      a
-#define DBG_INDENT()   do { int _s; for(_s = 0; _s < ao_lisp_stack_depth; _s++) printf("  "); } while(0)
-#define DBG_IN()       (++ao_lisp_stack_depth)
-#define DBG_OUT()      (--ao_lisp_stack_depth)
-#define DBG_RESET()    (ao_lisp_stack_depth = 0)
-#define DBG(...)       printf(__VA_ARGS__)
-#define DBGI(...)      do { DBG("%4d: ", __LINE__); DBG_INDENT(); DBG(__VA_ARGS__); } while (0)
-#define DBG_CONS(a)    ao_lisp_cons_print(ao_lisp_cons_poly(a))
-#define DBG_POLY(a)    ao_lisp_poly_print(a)
-#define OFFSET(a)      ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1)
-#define DBG_STACK()    ao_lisp_stack_print(ao_lisp_stack_poly(ao_lisp_stack))
-static inline void
-ao_lisp_frames_dump(void)
-{
-       struct ao_lisp_stack *s;
-       DBGI(".. current frame: "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-       for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) {
-               DBGI(".. stack frame: "); DBG_POLY(s->frame); DBG("\n");
-       }
-}
-#define DBG_FRAMES()   ao_lisp_frames_dump()
-#else
-#define DBG_DO(a)
-#define DBG_INDENT()
-#define DBG_IN()
-#define DBG_OUT()
-#define DBG(...)
-#define DBGI(...)
-#define DBG_CONS(a)
-#define DBG_POLY(a)
-#define DBG_RESET()
-#define DBG_STACK()
-#define DBG_FRAMES()
-#endif
-
-#define DBG_MEM_START  1
-
-#if DBG_MEM
-
-#include <assert.h>
-extern int dbg_move_depth;
-#define MDBG_DUMP 1
-#define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool))
-
-extern int dbg_mem;
-
-#define MDBG_DO(a)     a
-#define MDBG_MOVE(...) do { if (dbg_mem) { int d; for (d = 0; d < dbg_move_depth; d++) printf ("  "); printf(__VA_ARGS__); } } while (0)
-#define MDBG_MORE(...) do { if (dbg_mem) printf(__VA_ARGS__); } while (0)
-#define MDBG_MOVE_IN() (dbg_move_depth++)
-#define MDBG_MOVE_OUT()        (assert(--dbg_move_depth >= 0))
-
-#else
-
-#define MDBG_DO(a)
-#define MDBG_MOVE(...)
-#define MDBG_MORE(...)
-#define MDBG_MOVE_IN()
-#define MDBG_MOVE_OUT()
-
-#endif
-
-#endif /* _AO_LISP_H_ */
diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c
deleted file mode 100644 (file)
index 8c9e8ed..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright © 2016 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include "ao_lisp.h"
-
-static int name_size(char *name)
-{
-       return sizeof(struct ao_lisp_atom) + strlen(name) + 1;
-}
-
-static int atom_size(void *addr)
-{
-       struct ao_lisp_atom     *atom = addr;
-       if (!atom)
-               return 0;
-       return name_size(atom->name);
-}
-
-static void atom_mark(void *addr)
-{
-       struct ao_lisp_atom     *atom = addr;
-
-       for (;;) {
-               atom = ao_lisp_poly_atom(atom->next);
-               if (!atom)
-                       break;
-               if (ao_lisp_mark_memory(&ao_lisp_atom_type, atom))
-                       break;
-       }
-}
-
-static void atom_move(void *addr)
-{
-       struct ao_lisp_atom     *atom = addr;
-       int                     ret;
-
-       for (;;) {
-               struct ao_lisp_atom *next = ao_lisp_poly_atom(atom->next);
-
-               if (!next)
-                       break;
-               ret = ao_lisp_move_memory(&ao_lisp_atom_type, (void **) &next);
-               if (next != ao_lisp_poly_atom(atom->next))
-                       atom->next = ao_lisp_atom_poly(next);
-               if (ret)
-                       break;
-               atom = next;
-       }
-}
-
-const struct ao_lisp_type ao_lisp_atom_type = {
-       .mark = atom_mark,
-       .size = atom_size,
-       .move = atom_move,
-       .name = "atom"
-};
-
-struct ao_lisp_atom    *ao_lisp_atoms;
-
-struct ao_lisp_atom *
-ao_lisp_atom_intern(char *name)
-{
-       struct ao_lisp_atom     *atom;
-
-       for (atom = ao_lisp_atoms; atom; atom = ao_lisp_poly_atom(atom->next)) {
-               if (!strcmp(atom->name, name))
-                       return atom;
-       }
-#ifdef ao_builtin_atoms
-       for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) {
-               if (!strcmp(atom->name, name))
-                       return atom;
-       }
-#endif
-       ao_lisp_string_stash(0, name);
-       atom = ao_lisp_alloc(name_size(name));
-       name = ao_lisp_string_fetch(0);
-       if (atom) {
-               atom->type = AO_LISP_ATOM;
-               atom->next = ao_lisp_atom_poly(ao_lisp_atoms);
-               ao_lisp_atoms = atom;
-               strcpy(atom->name, name);
-       }
-       return atom;
-}
-
-struct ao_lisp_frame   *ao_lisp_frame_global;
-struct ao_lisp_frame   *ao_lisp_frame_current;
-
-static void
-ao_lisp_atom_init(void)
-{
-       if (!ao_lisp_frame_global)
-               ao_lisp_frame_global = ao_lisp_frame_new(0);
-}
-
-ao_poly *
-ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom)
-{
-       ao_poly *ref;
-       ao_lisp_atom_init();
-       while (frame) {
-               ref = ao_lisp_frame_ref(frame, atom);
-               if (ref)
-                       return ref;
-               frame = ao_lisp_poly_frame(frame->prev);
-       }
-       if (ao_lisp_frame_global) {
-               ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom);
-               if (ref)
-                       return ref;
-       }
-       return NULL;
-}
-
-ao_poly
-ao_lisp_atom_get(ao_poly atom)
-{
-       ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_current, atom);
-
-       if (!ref && ao_lisp_frame_global)
-               ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom);
-#ifdef ao_builtin_frame
-       if (!ref)
-               ref = ao_lisp_frame_ref(ao_lisp_poly_frame(ao_builtin_frame), atom);
-#endif
-       if (ref)
-               return *ref;
-       return ao_lisp_error(AO_LISP_UNDEFINED, "undefined atom %s", ao_lisp_poly_atom(atom)->name);
-}
-
-ao_poly
-ao_lisp_atom_set(ao_poly atom, ao_poly val)
-{
-       ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_current, atom);
-
-       if (!ref && ao_lisp_frame_global)
-               ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom);
-       if (ref)
-               *ref = val;
-       else
-               ao_lisp_frame_add(&ao_lisp_frame_global, atom, val);
-       return val;
-}
-
-void
-ao_lisp_atom_print(ao_poly a)
-{
-       struct ao_lisp_atom *atom = ao_lisp_poly_atom(a);
-       printf("%s", atom->name);
-}
diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c
deleted file mode 100644 (file)
index 902f60e..0000000
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
-static int
-builtin_size(void *addr)
-{
-       (void) addr;
-       return sizeof (struct ao_lisp_builtin);
-}
-
-static void
-builtin_mark(void *addr)
-{
-       (void) addr;
-}
-
-static void
-builtin_move(void *addr)
-{
-       (void) addr;
-}
-
-const struct ao_lisp_type ao_lisp_builtin_type = {
-       .size = builtin_size,
-       .mark = builtin_mark,
-       .move = builtin_move
-};
-
-#ifdef AO_LISP_MAKE_CONST
-char *ao_lisp_builtin_name(enum ao_lisp_builtin_id b) {
-       (void) b;
-       return "???";
-}
-char *ao_lisp_args_name(uint8_t args) {
-       (void) args;
-       return "???";
-}
-#else
-static const ao_poly builtin_names[] = {
-       [builtin_eval] = _ao_lisp_atom_eval,
-       [builtin_read] = _ao_lisp_atom_read,
-       [builtin_lambda] = _ao_lisp_atom_lambda,
-       [builtin_lexpr] = _ao_lisp_atom_lexpr,
-       [builtin_nlambda] = _ao_lisp_atom_nlambda,
-       [builtin_macro] = _ao_lisp_atom_macro,
-       [builtin_car] = _ao_lisp_atom_car,
-       [builtin_cdr] = _ao_lisp_atom_cdr,
-       [builtin_cons] = _ao_lisp_atom_cons,
-       [builtin_last] = _ao_lisp_atom_last,
-       [builtin_length] = _ao_lisp_atom_length,
-       [builtin_quote] = _ao_lisp_atom_quote,
-       [builtin_set] = _ao_lisp_atom_set,
-       [builtin_setq] = _ao_lisp_atom_setq,
-       [builtin_cond] = _ao_lisp_atom_cond,
-       [builtin_progn] = _ao_lisp_atom_progn,
-       [builtin_while] = _ao_lisp_atom_while,
-       [builtin_print] = _ao_lisp_atom_print,
-       [builtin_patom] = _ao_lisp_atom_patom,
-       [builtin_plus] = _ao_lisp_atom_2b,
-       [builtin_minus] = _ao_lisp_atom_2d,
-       [builtin_times] = _ao_lisp_atom_2a,
-       [builtin_divide] = _ao_lisp_atom_2f,
-       [builtin_mod] = _ao_lisp_atom_25,
-       [builtin_equal] = _ao_lisp_atom_3d,
-       [builtin_less] = _ao_lisp_atom_3c,
-       [builtin_greater] = _ao_lisp_atom_3e,
-       [builtin_less_equal] = _ao_lisp_atom_3c3d,
-       [builtin_greater_equal] = _ao_lisp_atom_3e3d,
-       [builtin_pack] = _ao_lisp_atom_pack,
-       [builtin_unpack] = _ao_lisp_atom_unpack,
-       [builtin_flush] = _ao_lisp_atom_flush,
-       [builtin_delay] = _ao_lisp_atom_delay,
-       [builtin_led] = _ao_lisp_atom_led,
-       [builtin_save] = _ao_lisp_atom_save,
-       [builtin_restore] = _ao_lisp_atom_restore,
-       [builtin_call_cc] = _ao_lisp_atom_call2fcc,
-       [builtin_collect] = _ao_lisp_atom_collect,
-#if 0
-       [builtin_symbolp] = _ao_lisp_atom_symbolp,
-       [builtin_listp] = _ao_lisp_atom_listp,
-       [builtin_stringp] = _ao_lisp_atom_stringp,
-       [builtin_numberp] = _ao_lisp_atom_numberp,
-#endif
-};
-
-static char *
-ao_lisp_builtin_name(enum ao_lisp_builtin_id b) {
-       if (b < _builtin_last)
-               return ao_lisp_poly_atom(builtin_names[b])->name;
-       return "???";
-}
-
-static const ao_poly ao_lisp_args_atoms[] = {
-       [AO_LISP_FUNC_LAMBDA] = _ao_lisp_atom_lambda,
-       [AO_LISP_FUNC_LEXPR] = _ao_lisp_atom_lexpr,
-       [AO_LISP_FUNC_NLAMBDA] = _ao_lisp_atom_nlambda,
-       [AO_LISP_FUNC_MACRO] = _ao_lisp_atom_macro,
-};
-
-char *
-ao_lisp_args_name(uint8_t args)
-{
-       args &= AO_LISP_FUNC_MASK;
-       if (args < sizeof ao_lisp_args_atoms / sizeof ao_lisp_args_atoms[0])
-               return ao_lisp_poly_atom(ao_lisp_args_atoms[args])->name;
-       return "(unknown)";
-}
-#endif
-
-void
-ao_lisp_builtin_print(ao_poly b)
-{
-       struct ao_lisp_builtin *builtin = ao_lisp_poly_builtin(b);
-       printf("%s", ao_lisp_builtin_name(builtin->func));
-}
-
-ao_poly
-ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max)
-{
-       int     argc = 0;
-
-       while (cons && argc <= max) {
-               argc++;
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-       if (argc < min || argc > max)
-               return ao_lisp_error(AO_LISP_INVALID, "%s: invalid arg count", ao_lisp_poly_atom(name)->name);
-       return _ao_lisp_atom_t;
-}
-
-ao_poly
-ao_lisp_arg(struct ao_lisp_cons *cons, int argc)
-{
-       if (!cons)
-               return AO_LISP_NIL;
-       while (argc--) {
-               if (!cons)
-                       return AO_LISP_NIL;
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-       return cons->car;
-}
-
-ao_poly
-ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok)
-{
-       ao_poly car = ao_lisp_arg(cons, argc);
-
-       if ((!car && !nil_ok) || ao_lisp_poly_type(car) != type)
-               return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d", ao_lisp_poly_atom(name)->name, argc);
-       return _ao_lisp_atom_t;
-}
-
-ao_poly
-ao_lisp_car(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_car, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_car, cons, 0, AO_LISP_CONS, 0))
-               return AO_LISP_NIL;
-       return ao_lisp_poly_cons(cons->car)->car;
-}
-
-ao_poly
-ao_lisp_cdr(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_cdr, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_cdr, cons, 0, AO_LISP_CONS, 0))
-               return AO_LISP_NIL;
-       return ao_lisp_poly_cons(cons->car)->cdr;
-}
-
-ao_poly
-ao_lisp_cons(struct ao_lisp_cons *cons)
-{
-       ao_poly car, cdr;
-       if(!ao_lisp_check_argc(_ao_lisp_atom_cons, cons, 2, 2))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_cons, cons, 1, AO_LISP_CONS, 1))
-               return AO_LISP_NIL;
-       car = ao_lisp_arg(cons, 0);
-       cdr = ao_lisp_arg(cons, 1);
-       return ao_lisp_cons_poly(ao_lisp_cons_cons(car, ao_lisp_poly_cons(cdr)));
-}
-
-ao_poly
-ao_lisp_last(struct ao_lisp_cons *cons)
-{
-       ao_poly l;
-       if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1))
-               return AO_LISP_NIL;
-       l = ao_lisp_arg(cons, 0);
-       while (l) {
-               struct ao_lisp_cons *list = ao_lisp_poly_cons(l);
-               if (!list->cdr)
-                       return list->car;
-               l = list->cdr;
-       }
-       return AO_LISP_NIL;
-}
-
-ao_poly
-ao_lisp_length(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_length, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_length, cons, 0, AO_LISP_CONS, 1))
-               return AO_LISP_NIL;
-       return ao_lisp_int_poly(ao_lisp_cons_length(ao_lisp_poly_cons(ao_lisp_arg(cons, 0))));
-}
-
-ao_poly
-ao_lisp_quote(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_quote, cons, 1, 1))
-               return AO_LISP_NIL;
-       return ao_lisp_arg(cons, 0);
-}
-
-ao_poly
-ao_lisp_set(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_set, cons, 2, 2))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_set, cons, 0, AO_LISP_ATOM, 0))
-               return AO_LISP_NIL;
-
-       return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_arg(cons, 1));
-}
-
-ao_poly
-ao_lisp_setq(struct ao_lisp_cons *cons)
-{
-       struct ao_lisp_cons     *expand = 0;
-       if (!ao_lisp_check_argc(_ao_lisp_atom_setq, cons, 2, 2))
-               return AO_LISP_NIL;
-       expand = ao_lisp_cons_cons(_ao_lisp_atom_set,
-                                  ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(_ao_lisp_atom_quote,
-                                                                      ao_lisp_cons_cons(cons->car, NULL))),
-                                                    ao_lisp_poly_cons(cons->cdr)));
-       return ao_lisp_cons_poly(expand);
-}
-
-ao_poly
-ao_lisp_cond(struct ao_lisp_cons *cons)
-{
-       ao_lisp_set_cond(cons);
-       return AO_LISP_NIL;
-}
-
-ao_poly
-ao_lisp_progn(struct ao_lisp_cons *cons)
-{
-       ao_lisp_stack->state = eval_progn;
-       ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
-       return AO_LISP_NIL;
-}
-
-ao_poly
-ao_lisp_while(struct ao_lisp_cons *cons)
-{
-       ao_lisp_stack->state = eval_while;
-       ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
-       return AO_LISP_NIL;
-}
-
-ao_poly
-ao_lisp_print(struct ao_lisp_cons *cons)
-{
-       ao_poly val = AO_LISP_NIL;
-       while (cons) {
-               val = cons->car;
-               ao_lisp_poly_print(val);
-               cons = ao_lisp_poly_cons(cons->cdr);
-               if (cons)
-                       printf(" ");
-       }
-       printf("\n");
-       return val;
-}
-
-ao_poly
-ao_lisp_patom(struct ao_lisp_cons *cons)
-{
-       ao_poly val = AO_LISP_NIL;
-       while (cons) {
-               val = cons->car;
-               ao_lisp_poly_patom(val);
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-       return val;
-}
-
-ao_poly
-ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
-{
-       ao_poly ret = AO_LISP_NIL;
-
-       while (cons) {
-               ao_poly         car = cons->car;
-               uint8_t         rt = ao_lisp_poly_type(ret);
-               uint8_t         ct = ao_lisp_poly_type(car);
-
-               cons = ao_lisp_poly_cons(cons->cdr);
-
-               if (rt == AO_LISP_NIL)
-                       ret = car;
-
-               else if (rt == AO_LISP_INT && ct == AO_LISP_INT) {
-                       int     r = ao_lisp_poly_int(ret);
-                       int     c = ao_lisp_poly_int(car);
-
-                       switch(op) {
-                       case builtin_plus:
-                               r += c;
-                               break;
-                       case builtin_minus:
-                               r -= c;
-                               break;
-                       case builtin_times:
-                               r *= c;
-                               break;
-                       case builtin_divide:
-                               if (c == 0)
-                                       return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
-                               r /= c;
-                               break;
-                       case builtin_mod:
-                               if (c == 0)
-                                       return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "mod by zero");
-                               r %= c;
-                               break;
-                       default:
-                               break;
-                       }
-                       ret = ao_lisp_int_poly(r);
-               }
-
-               else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus)
-                       ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret),
-                                                                    ao_lisp_poly_string(car)));
-               else
-                       return ao_lisp_error(AO_LISP_INVALID, "invalid args");
-       }
-       return ret;
-}
-
-ao_poly
-ao_lisp_plus(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_math(cons, builtin_plus);
-}
-
-ao_poly
-ao_lisp_minus(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_math(cons, builtin_minus);
-}
-
-ao_poly
-ao_lisp_times(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_math(cons, builtin_times);
-}
-
-ao_poly
-ao_lisp_divide(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_math(cons, builtin_divide);
-}
-
-ao_poly
-ao_lisp_mod(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_math(cons, builtin_mod);
-}
-
-ao_poly
-ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
-{
-       ao_poly left;
-
-       if (!cons)
-               return _ao_lisp_atom_t;
-
-       left = cons->car;
-       cons = ao_lisp_poly_cons(cons->cdr);
-       while (cons) {
-               ao_poly right = cons->car;
-
-               if (op == builtin_equal) {
-                       if (left != right)
-                               return AO_LISP_NIL;
-               } else {
-                       uint8_t lt = ao_lisp_poly_type(left);
-                       uint8_t rt = ao_lisp_poly_type(right);
-                       if (lt == AO_LISP_INT && rt == AO_LISP_INT) {
-                               int l = ao_lisp_poly_int(left);
-                               int r = ao_lisp_poly_int(right);
-
-                               switch (op) {
-                               case builtin_less:
-                                       if (!(l < r))
-                                               return AO_LISP_NIL;
-                                       break;
-                               case builtin_greater:
-                                       if (!(l > r))
-                                               return AO_LISP_NIL;
-                                       break;
-                               case builtin_less_equal:
-                                       if (!(l <= r))
-                                               return AO_LISP_NIL;
-                                       break;
-                               case builtin_greater_equal:
-                                       if (!(l >= r))
-                                               return AO_LISP_NIL;
-                                       break;
-                               default:
-                                       break;
-                               }
-                       } else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) {
-                               int c = strcmp(ao_lisp_poly_string(left),
-                                              ao_lisp_poly_string(right));
-                               switch (op) {
-                               case builtin_less:
-                                       if (!(c < 0))
-                                               return AO_LISP_NIL;
-                                       break;
-                               case builtin_greater:
-                                       if (!(c > 0))
-                                               return AO_LISP_NIL;
-                                       break;
-                               case builtin_less_equal:
-                                       if (!(c <= 0))
-                                               return AO_LISP_NIL;
-                                       break;
-                               case builtin_greater_equal:
-                                       if (!(c >= 0))
-                                               return AO_LISP_NIL;
-                                       break;
-                               default:
-                                       break;
-                               }
-                       }
-               }
-               left = right;
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-       return _ao_lisp_atom_t;
-}
-
-ao_poly
-ao_lisp_equal(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_compare(cons, builtin_equal);
-}
-
-ao_poly
-ao_lisp_less(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_compare(cons, builtin_less);
-}
-
-ao_poly
-ao_lisp_greater(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_compare(cons, builtin_greater);
-}
-
-ao_poly
-ao_lisp_less_equal(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_compare(cons, builtin_less_equal);
-}
-
-ao_poly
-ao_lisp_greater_equal(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_compare(cons, builtin_greater_equal);
-}
-
-ao_poly
-ao_lisp_pack(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_pack, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_pack, cons, 0, AO_LISP_CONS, 1))
-               return AO_LISP_NIL;
-       return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)));
-}
-
-ao_poly
-ao_lisp_unpack(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_unpack, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_unpack, cons, 0, AO_LISP_STRING, 0))
-               return AO_LISP_NIL;
-       return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0)));
-}
-
-ao_poly
-ao_lisp_flush(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_flush, cons, 0, 0))
-               return AO_LISP_NIL;
-       ao_lisp_os_flush();
-       return _ao_lisp_atom_t;
-}
-
-ao_poly
-ao_lisp_led(struct ao_lisp_cons *cons)
-{
-       ao_poly led;
-       if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
-               return AO_LISP_NIL;
-       led = ao_lisp_arg(cons, 0);
-       ao_lisp_os_led(ao_lisp_poly_int(led));
-       return led;
-}
-
-ao_poly
-ao_lisp_delay(struct ao_lisp_cons *cons)
-{
-       ao_poly delay;
-       if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
-               return AO_LISP_NIL;
-       delay = ao_lisp_arg(cons, 0);
-       ao_lisp_os_delay(ao_lisp_poly_int(delay));
-       return delay;
-}
-
-ao_poly
-ao_lisp_do_eval(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1))
-               return AO_LISP_NIL;
-       ao_lisp_stack->state = eval_sexpr;
-       return cons->car;
-}
-
-ao_poly
-ao_lisp_do_read(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0))
-               return AO_LISP_NIL;
-       return ao_lisp_read();
-}
-
-ao_poly
-ao_lisp_do_collect(struct ao_lisp_cons *cons)
-{
-       int     free;
-       (void) cons;
-       free = ao_lisp_collect(AO_LISP_COLLECT_FULL);
-       return ao_lisp_int_poly(free);
-}
-
-const ao_lisp_func_t ao_lisp_builtins[] = {
-       [builtin_eval] = ao_lisp_do_eval,
-       [builtin_read] = ao_lisp_do_read,
-       [builtin_lambda] = ao_lisp_lambda,
-       [builtin_lexpr] = ao_lisp_lexpr,
-       [builtin_nlambda] = ao_lisp_nlambda,
-       [builtin_macro] = ao_lisp_macro,
-       [builtin_car] = ao_lisp_car,
-       [builtin_cdr] = ao_lisp_cdr,
-       [builtin_cons] = ao_lisp_cons,
-       [builtin_last] = ao_lisp_last,
-       [builtin_length] = ao_lisp_length,
-       [builtin_quote] = ao_lisp_quote,
-       [builtin_set] = ao_lisp_set,
-       [builtin_setq] = ao_lisp_setq,
-       [builtin_cond] = ao_lisp_cond,
-       [builtin_progn] = ao_lisp_progn,
-       [builtin_while] = ao_lisp_while,
-       [builtin_print] = ao_lisp_print,
-       [builtin_patom] = ao_lisp_patom,
-       [builtin_plus] = ao_lisp_plus,
-       [builtin_minus] = ao_lisp_minus,
-       [builtin_times] = ao_lisp_times,
-       [builtin_divide] = ao_lisp_divide,
-       [builtin_mod] = ao_lisp_mod,
-       [builtin_equal] = ao_lisp_equal,
-       [builtin_less] = ao_lisp_less,
-       [builtin_greater] = ao_lisp_greater,
-       [builtin_less_equal] = ao_lisp_less_equal,
-       [builtin_greater_equal] = ao_lisp_greater_equal,
-       [builtin_pack] = ao_lisp_pack,
-       [builtin_unpack] = ao_lisp_unpack,
-       [builtin_flush] = ao_lisp_flush,
-       [builtin_led] = ao_lisp_led,
-       [builtin_delay] = ao_lisp_delay,
-       [builtin_save] = ao_lisp_save,
-       [builtin_restore] = ao_lisp_restore,
-       [builtin_call_cc] = ao_lisp_call_cc,
-       [builtin_collect] = ao_lisp_do_collect,
-};
-
diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c
deleted file mode 100644 (file)
index d2b60c9..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
-static void cons_mark(void *addr)
-{
-       struct ao_lisp_cons     *cons = addr;
-
-       for (;;) {
-               ao_lisp_poly_mark(cons->car, 1);
-               cons = ao_lisp_poly_cons(cons->cdr);
-               if (!cons)
-                       break;
-               if (ao_lisp_mark_memory(&ao_lisp_cons_type, cons))
-                       break;
-       }
-}
-
-static int cons_size(void *addr)
-{
-       (void) addr;
-       return sizeof (struct ao_lisp_cons);
-}
-
-static void cons_move(void *addr)
-{
-       struct ao_lisp_cons     *cons = addr;
-
-       if (!cons)
-               return;
-
-       for (;;) {
-               struct ao_lisp_cons     *cdr;
-               int                     ret;
-
-               MDBG_MOVE("cons_move start %d (%d, %d)\n",
-                         MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr)));
-               (void) ao_lisp_poly_move(&cons->car, 1);
-               cdr = ao_lisp_poly_cons(cons->cdr);
-               if (!cdr)
-                       break;
-               ret = ao_lisp_move_memory(&ao_lisp_cons_type, (void **) &cdr);
-               if (cdr != ao_lisp_poly_cons(cons->cdr))
-                       cons->cdr = ao_lisp_cons_poly(cdr);
-               MDBG_MOVE("cons_move end %d (%d, %d)\n",
-                         MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr)));
-               if (ret)
-                       break;
-               cons = cdr;
-       }
-}
-
-const struct ao_lisp_type ao_lisp_cons_type = {
-       .mark = cons_mark,
-       .size = cons_size,
-       .move = cons_move,
-       .name = "cons",
-};
-
-struct ao_lisp_cons *ao_lisp_cons_free_list;
-
-struct ao_lisp_cons *
-ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr)
-{
-       struct ao_lisp_cons     *cons;
-
-       if (ao_lisp_cons_free_list) {
-               cons = ao_lisp_cons_free_list;
-               ao_lisp_cons_free_list = ao_lisp_poly_cons(cons->cdr);
-       } else {
-               ao_lisp_poly_stash(0, car);
-               ao_lisp_cons_stash(0, cdr);
-               cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons));
-               car = ao_lisp_poly_fetch(0);
-               cdr = ao_lisp_cons_fetch(0);
-               if (!cons)
-                       return NULL;
-       }
-       cons->car = car;
-       cons->cdr = ao_lisp_cons_poly(cdr);
-       return cons;
-}
-
-void
-ao_lisp_cons_free(struct ao_lisp_cons *cons)
-{
-       while (cons) {
-               ao_poly cdr = cons->cdr;
-               cons->cdr = ao_lisp_cons_poly(ao_lisp_cons_free_list);
-               ao_lisp_cons_free_list = cons;
-               cons = ao_lisp_poly_cons(cdr);
-       }
-}
-
-void
-ao_lisp_cons_print(ao_poly c)
-{
-       struct ao_lisp_cons *cons = ao_lisp_poly_cons(c);
-       int     first = 1;
-       printf("(");
-       while (cons) {
-               if (!first)
-                       printf(" ");
-               ao_lisp_poly_print(cons->car);
-               cons = ao_lisp_poly_cons(cons->cdr);
-               first = 0;
-       }
-       printf(")");
-}
-
-void
-ao_lisp_cons_patom(ao_poly c)
-{
-       struct ao_lisp_cons *cons = ao_lisp_poly_cons(c);
-
-       while (cons) {
-               ao_lisp_poly_patom(cons->car);
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-}
-
-int
-ao_lisp_cons_length(struct ao_lisp_cons *cons)
-{
-       int     len = 0;
-       while (cons) {
-               len++;
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-       return len;
-}
diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp
deleted file mode 100644 (file)
index 3c8fd21..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-;
-; 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.
-;
-; Lisp code placed in ROM
-
-                                       ; return a list containing all of the arguments
-
-(set (quote list) (lexpr (l) l))
-
-                                       ;
-                                       ; Define a variable without returning the value
-                                       ; Useful when defining functions to avoid
-                                       ; having lots of output generated
-                                       ;
-
-(setq def (macro (name val rest)
-                (list
-                 'progn
-                 (list
-                  'set
-                  (list 'quote name)
-                  val)
-                 (list 'quote name)
-                 )
-                )
-      )
-
-                                       ;
-                                       ; A slightly more convenient form
-                                       ; for defining lambdas.
-                                       ;
-                                       ; (defun <name> (<params>) s-exprs)
-                                       ;
-
-(def defun (macro (name args exprs)
-                 (list
-                  def
-                  name
-                  (cons 'lambda (cons args exprs))
-                  )
-                 )
-     )
-
-                                       ; basic list accessors
-
-
-(defun cadr (l) (car (cdr l)))
-
-(defun caddr (l) (car (cdr (cdr l))))
-
-(defun nth (list n)
-  (cond ((= n 0) (car list))
-       ((nth (cdr list) (1- n)))
-       )
-  )
-
-                                       ; simple math operators
-
-(defun 1+ (x) (+ x 1))
-(defun 1- (x) (- x 1))
-
-                                       ; define a set of local
-                                       ; variables and then evaluate
-                                       ; a list of sexprs
-                                       ;
-                                       ; (let (var-defines) sexprs)
-                                       ;
-                                       ; where var-defines are either
-                                       ;
-                                       ; (name value)
-                                       ;
-                                       ; or
-                                       ;
-                                       ; (name)
-                                       ;
-                                       ; e.g.
-                                       ;
-                                       ; (let ((x 1) (y)) (setq y (+ x 1)) y)
-
-(def let (macro (vars exprs)
-               ((lambda (make-names make-exprs make-nils)
-
-                                       ;
-                                       ; make the list of names in the let
-                                       ;
-
-                  (setq make-names (lambda (vars)
-                                     (cond (vars
-                                            (cons (car (car vars))
-                                                  (make-names (cdr vars))))
-                                           )
-                                     )
-                        )
-
-                                       ; the set of expressions is
-                                       ; the list of set expressions
-                                       ; pre-pended to the
-                                       ; expressions to evaluate
-
-                  (setq make-exprs (lambda (vars exprs)
-                                     (cond (vars (cons
-                                                  (list set
-                                                        (list quote
-                                                              (car (car vars))
-                                                              )
-                                                        (cadr (car vars))
-                                                        )
-                                                  (make-exprs (cdr vars) exprs)
-                                                  )
-                                                 )
-                                           (exprs)
-                                           )
-                                     )
-                        )
-
-                                       ; the parameters to the lambda is a list
-                                       ; of nils of the right length
-
-                  (setq make-nils (lambda (vars)
-                                    (cond (vars (cons nil (make-nils (cdr vars))))
-                                          )
-                                    )
-                        )
-                                       ; prepend the set operations
-                                       ; to the expressions
-
-                  (setq exprs (make-exprs vars exprs))
-
-                                       ; build the lambda.
-
-                  (cons (cons 'lambda (cons (make-names vars) exprs))
-                        (make-nils vars)
-                        )
-                  )
-                ()
-                ()
-                ()
-                )
-               )
-     )
-
-                                       ; boolean operators
-
-(def or (lexpr (l)
-              (let ((ret nil))
-                (while l
-                  (cond ((setq ret (car l))
-                         (setq l nil))
-                        ((setq l (cdr l)))))
-                ret
-                )
-              )
-     )
-
-                                       ; execute to resolve macros
-
-(or nil t)
-
-(def and (lexpr (l)
-              (let ((ret t))
-                (while l
-                  (cond ((setq ret (car l))
-                         (setq l (cdr l)))
-                        ((setq ret (setq l nil)))
-                        )
-                  )
-                ret
-                )
-              )
-     )
-
-                                       ; execute to resolve macros
-
-(and t nil)
diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c
deleted file mode 100644 (file)
index 54a9be1..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-#include <stdarg.h>
-
-void
-ao_lisp_error_poly(char *name, ao_poly poly, ao_poly last)
-{
-       int first = 1;
-       printf("\t\t%s(", name);
-       if (ao_lisp_poly_type(poly) == AO_LISP_CONS) {
-               if (poly) {
-                       while (poly) {
-                               struct ao_lisp_cons *cons = ao_lisp_poly_cons(poly);
-                               if (!first)
-                                       printf("\t\t         ");
-                               else
-                                       first = 0;
-                               ao_lisp_poly_print(cons->car);
-                               printf("\n");
-                               if (poly == last)
-                                       break;
-                               poly = cons->cdr;
-                       }
-                       printf("\t\t         )\n");
-               } else
-                       printf(")\n");
-       } else {
-               ao_lisp_poly_print(poly);
-               printf("\n");
-       }
-}
-
-static void tabs(int indent)
-{
-       while (indent--)
-               printf("\t");
-}
-
-void
-ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame)
-{
-       int                     f;
-
-       tabs(indent);
-       printf ("%s{", name);
-       if (frame) {
-               if (frame->type & AO_LISP_FRAME_PRINT)
-                       printf("recurse...");
-               else {
-                       frame->type |= AO_LISP_FRAME_PRINT;
-                       for (f = 0; f < frame->num; f++) {
-                               if (f != 0) {
-                                       tabs(indent);
-                                       printf("         ");
-                               }
-                               ao_lisp_poly_print(frame->vals[f].atom);
-                               printf(" = ");
-                               ao_lisp_poly_print(frame->vals[f].val);
-                               printf("\n");
-                       }
-                       if (frame->prev)
-                               ao_lisp_error_frame(indent + 1, "prev:   ", ao_lisp_poly_frame(frame->prev));
-                       frame->type &= ~AO_LISP_FRAME_PRINT;
-               }
-               tabs(indent);
-               printf("        }\n");
-       } else
-               printf ("}\n");
-}
-
-
-ao_poly
-ao_lisp_error(int error, char *format, ...)
-{
-       va_list args;
-
-       ao_lisp_exception |= error;
-       va_start(args, format);
-       vprintf(format, args);
-       va_end(args);
-       printf("\n");
-       printf("Value: "); ao_lisp_poly_print(ao_lisp_v); printf("\n");
-       printf("Stack:\n");
-       ao_lisp_stack_print(ao_lisp_stack_poly(ao_lisp_stack));
-       printf("Globals:\n\t");
-       ao_lisp_frame_print(ao_lisp_frame_poly(ao_lisp_frame_global));
-       printf("\n");
-       return AO_LISP_NIL;
-}
diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c
deleted file mode 100644 (file)
index 3be7c9c..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-#include <assert.h>
-
-struct ao_lisp_stack           *ao_lisp_stack;
-ao_poly                                ao_lisp_v;
-
-ao_poly
-ao_lisp_set_cond(struct ao_lisp_cons *c)
-{
-       ao_lisp_stack->state = eval_cond;
-       ao_lisp_stack->sexprs = ao_lisp_cons_poly(c);
-       return AO_LISP_NIL;
-}
-
-static int
-func_type(ao_poly func)
-{
-       if (func == AO_LISP_NIL)
-               return ao_lisp_error(AO_LISP_INVALID, "func is nil");
-       switch (ao_lisp_poly_type(func)) {
-       case AO_LISP_BUILTIN:
-               return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK;
-       case AO_LISP_LAMBDA:
-               return ao_lisp_poly_lambda(func)->args;
-       case AO_LISP_STACK:
-               return AO_LISP_FUNC_LAMBDA;
-       default:
-               ao_lisp_error(AO_LISP_INVALID, "not a func");
-               return -1;
-       }
-}
-
-/*
- * Flattened eval to avoid stack issues
- */
-
-/*
- * Evaluate an s-expression
- *
- * For a list, evaluate all of the elements and
- * then execute the resulting function call.
- *
- * Each element of the list is evaluated in
- * a clean stack context.
- *
- * The current stack state is set to 'formal' so that
- * when the evaluation is complete, the value
- * will get appended to the values list.
- *
- * For other types, compute the value directly.
- */
-
-static int
-ao_lisp_eval_sexpr(void)
-{
-       DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n");
-       switch (ao_lisp_poly_type(ao_lisp_v)) {
-       case AO_LISP_CONS:
-               if (ao_lisp_v == AO_LISP_NIL) {
-                       if (!ao_lisp_stack->values) {
-                               /*
-                                * empty list evaluates to empty list
-                                */
-                               ao_lisp_v = AO_LISP_NIL;
-                               ao_lisp_stack->state = eval_val;
-                       } else {
-                               /*
-                                * done with arguments, go execute it
-                                */
-                               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->values)->car;
-                               ao_lisp_stack->state = eval_exec;
-                       }
-               } else {
-                       if (!ao_lisp_stack->values)
-                               ao_lisp_stack->list = ao_lisp_v;
-                       /*
-                        * Evaluate another argument and then switch
-                        * to 'formal' to add the value to the values
-                        * list
-                        */
-                       ao_lisp_stack->sexprs = ao_lisp_v;
-                       ao_lisp_stack->state = eval_formal;
-                       if (!ao_lisp_stack_push())
-                               return 0;
-                       /*
-                        * push will reset the state to 'sexpr', which
-                        * will evaluate the expression
-                        */
-                       ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
-               }
-               break;
-       case AO_LISP_ATOM:
-               DBGI("..frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               ao_lisp_v = ao_lisp_atom_get(ao_lisp_v);
-               /* fall through */
-       case AO_LISP_INT:
-       case AO_LISP_STRING:
-       case AO_LISP_BUILTIN:
-       case AO_LISP_LAMBDA:
-               ao_lisp_stack->state = eval_val;
-               break;
-       }
-       DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG("\n");
-       return 1;
-}
-
-/*
- * A value has been computed.
- *
- * If the value was computed from a macro,
- * then we want to reset the current context
- * to evaluate the macro result again.
- *
- * If not a macro, then pop the stack.
- * If the stack is empty, we're done.
- * Otherwise, the stack will contain
- * the next state.
- */
-
-static int
-ao_lisp_eval_val(void)
-{
-       DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n");
-       /*
-        * Value computed, pop the stack
-        * to figure out what to do with the value
-        */
-       ao_lisp_stack_pop();
-       DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1);
-       return 1;
-}
-
-/*
- * A formal has been computed.
- *
- * If this is the first formal, then check to see if we've got a
- * lamda/lexpr or macro/nlambda.
- *
- * For lambda/lexpr, go compute another formal.  This will terminate
- * when the sexpr state sees nil.
- *
- * For macro/nlambda, we're done, so move the sexprs into the values
- * and go execute it.
- *
- * Macros have an additional step of saving a stack frame holding the
- * macro value execution context, which then gets the result of the
- * macro to run
- */
-
-static int
-ao_lisp_eval_formal(void)
-{
-       ao_poly                 formal;
-       struct ao_lisp_stack    *prev;
-
-       DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n");
-
-       /* Check what kind of function we've got */
-       if (!ao_lisp_stack->values) {
-               switch (func_type(ao_lisp_v)) {
-               case AO_LISP_FUNC_LAMBDA:
-               case AO_LISP_FUNC_LEXPR:
-                       DBGI(".. lambda or lexpr\n");
-                       break;
-               case AO_LISP_FUNC_MACRO:
-                       /* Evaluate the result once more */
-                       ao_lisp_stack->state = eval_macro;
-                       if (!ao_lisp_stack_push())
-                               return 0;
-
-                       /* After the function returns, take that
-                        * value and re-evaluate it
-                        */
-                       prev = ao_lisp_poly_stack(ao_lisp_stack->prev);
-                       ao_lisp_stack->sexprs = prev->sexprs;
-
-                       DBGI(".. start macro\n");
-                       DBGI(".. sexprs       "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-                       DBGI(".. values       "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
-                       DBG_FRAMES();
-
-                       /* fall through ... */
-               case AO_LISP_FUNC_NLAMBDA:
-                       DBGI(".. nlambda or macro\n");
-
-                       /* use the raw sexprs as values */
-                       ao_lisp_stack->values = ao_lisp_stack->sexprs;
-                       ao_lisp_stack->values_tail = AO_LISP_NIL;
-                       ao_lisp_stack->state = eval_exec;
-
-                       /* ready to execute now */
-                       return 1;
-               case -1:
-                       return 0;
-               }
-       }
-
-       /* Append formal to list of values */
-       formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL));
-       if (!formal)
-               return 0;
-
-       if (ao_lisp_stack->values_tail)
-               ao_lisp_poly_cons(ao_lisp_stack->values_tail)->cdr = formal;
-       else
-               ao_lisp_stack->values = formal;
-       ao_lisp_stack->values_tail = formal;
-
-       DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
-
-       /*
-        * Step to the next argument, if this is last, then
-        * 'sexpr' will end up switching to 'exec'
-        */
-       ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
-
-       ao_lisp_stack->state = eval_sexpr;
-
-       DBGI(".. "); DBG_POLY(ao_lisp_v); DBG("\n");
-       return 1;
-}
-
-/*
- * Start executing a function call
- *
- * Most builtins are easy, just call the function.
- * 'cond' is magic; it sticks the list of clauses
- * in 'sexprs' and switches to 'cond' state. That
- * bit of magic is done in ao_lisp_set_cond.
- *
- * Lambdas build a new frame to hold the locals and
- * then re-use the current stack context to evaluate
- * the s-expression from the lambda.
- */
-
-static int
-ao_lisp_eval_exec(void)
-{
-       ao_poly v;
-       struct ao_lisp_builtin  *builtin;
-
-       DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n");
-       ao_lisp_stack->sexprs = AO_LISP_NIL;
-       switch (ao_lisp_poly_type(ao_lisp_v)) {
-       case AO_LISP_BUILTIN:
-               ao_lisp_stack->state = eval_val;
-               builtin = ao_lisp_poly_builtin(ao_lisp_v);
-               v = ao_lisp_func(builtin) (
-                       ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr));
-               DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) {
-                               struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values);
-                               ao_poly atom = ao_lisp_arg(cons, 1);
-                               ao_poly val = ao_lisp_arg(cons, 2);
-                               DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n");
-                       });
-               builtin = ao_lisp_poly_builtin(ao_lisp_v);
-               if (builtin->args & AO_LISP_FUNC_FREE_ARGS && !ao_lisp_stack_marked(ao_lisp_stack))
-                       ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values));
-
-               ao_lisp_v = v;
-               ao_lisp_stack->values = AO_LISP_NIL;
-               ao_lisp_stack->values_tail = AO_LISP_NIL;
-               DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n");
-               DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               break;
-       case AO_LISP_LAMBDA:
-               DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               ao_lisp_stack->state = eval_progn;
-               v = ao_lisp_lambda_eval();
-               ao_lisp_stack->sexprs = v;
-               ao_lisp_stack->values = AO_LISP_NIL;
-               ao_lisp_stack->values_tail = AO_LISP_NIL;
-               DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-               DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               break;
-       case AO_LISP_STACK:
-               DBGI(".. stack "); DBG_POLY(ao_lisp_v); DBG("\n");
-               ao_lisp_v = ao_lisp_stack_eval();
-               DBGI(".. value "); DBG_POLY(ao_lisp_v); DBG("\n");
-               DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               break;
-       }
-       return 1;
-}
-
-/*
- * Start evaluating the next cond clause
- *
- * If the list of clauses is empty, then
- * the result of the cond is nil.
- *
- * Otherwise, set the current stack state to 'cond_test' and create a
- * new stack context to evaluate the test s-expression. Once that's
- * complete, we'll land in 'cond_test' to finish the clause.
- */
-static int
-ao_lisp_eval_cond(void)
-{
-       DBGI("cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-       DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-       DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
-       if (!ao_lisp_stack->sexprs) {
-               ao_lisp_v = AO_LISP_NIL;
-               ao_lisp_stack->state = eval_val;
-       } else {
-               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
-               if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) {
-                       ao_lisp_error(AO_LISP_INVALID, "invalid cond clause");
-                       return 0;
-               }
-               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
-               ao_lisp_stack->state = eval_cond_test;
-               if (!ao_lisp_stack_push())
-                       return 0;
-       }
-       return 1;
-}
-
-/*
- * Finish a cond clause.
- *
- * Check the value from the test expression, if
- * non-nil, then set up to evaluate the value expression.
- *
- * Otherwise, step to the next clause and go back to the 'cond'
- * state
- */
-static int
-ao_lisp_eval_cond_test(void)
-{
-       DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-       DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-       DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
-       if (ao_lisp_v) {
-               struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car);
-               ao_poly c = car->cdr;
-
-               if (c) {
-                       ao_lisp_stack->state = eval_progn;
-                       ao_lisp_stack->sexprs = c;
-               } else
-                       ao_lisp_stack->state = eval_val;
-       } else {
-               ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
-               DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-               ao_lisp_stack->state = eval_cond;
-       }
-       return 1;
-}
-
-/*
- * Evaluate a list of sexprs, returning the value from the last one.
- *
- * ao_lisp_progn records the list in stack->sexprs, so we just need to
- * walk that list. Set ao_lisp_v to the car of the list and jump to
- * eval_sexpr. When that's done, it will land in eval_val. For all but
- * the last, leave a stack frame with eval_progn set so that we come
- * back here. For the last, don't add a stack frame so that we can
- * just continue on.
- */
-static int
-ao_lisp_eval_progn(void)
-{
-       DBGI("progn: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-       DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-       DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
-
-       if (!ao_lisp_stack->sexprs) {
-               ao_lisp_v = AO_LISP_NIL;
-               ao_lisp_stack->state = eval_val;
-       } else {
-               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
-               ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
-
-               /* If there are more sexprs to do, then come back here, otherwise
-                * return the value of the last one by just landing in eval_sexpr
-                */
-               if (ao_lisp_stack->sexprs) {
-                       ao_lisp_stack->state = eval_progn;
-                       if (!ao_lisp_stack_push())
-                               return 0;
-               }
-               ao_lisp_stack->state = eval_sexpr;
-       }
-       return 1;
-}
-
-/*
- * Conditionally execute a list of sexprs while the first is true
- */
-static int
-ao_lisp_eval_while(void)
-{
-       DBGI("while: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-       DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-       DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
-
-       ao_lisp_stack->values = ao_lisp_v;
-       if (!ao_lisp_stack->sexprs) {
-               ao_lisp_v = AO_LISP_NIL;
-               ao_lisp_stack->state = eval_val;
-       } else {
-               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
-               ao_lisp_stack->state = eval_while_test;
-               if (!ao_lisp_stack_push())
-                       return 0;
-       }
-       return 1;
-}
-
-/*
- * Check the while condition, terminate the loop if nil. Otherwise keep going
- */
-static int
-ao_lisp_eval_while_test(void)
-{
-       DBGI("while_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-       DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-       DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
-
-       if (ao_lisp_v) {
-               ao_lisp_stack->values = ao_lisp_v;
-               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
-               ao_lisp_stack->state = eval_while;
-               if (!ao_lisp_stack_push())
-                       return 0;
-               ao_lisp_stack->state = eval_progn;
-               ao_lisp_stack->sexprs = ao_lisp_v;
-       }
-       else
-       {
-               ao_lisp_stack->state = eval_val;
-               ao_lisp_v = ao_lisp_stack->values;
-       }
-       return 1;
-}
-
-/*
- * Replace the original sexpr with the macro expansion, then
- * execute that
- */
-static int
-ao_lisp_eval_macro(void)
-{
-       DBGI("macro: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-
-       if (ao_lisp_v == AO_LISP_NIL)
-               ao_lisp_abort();
-       if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_CONS) {
-               *ao_lisp_poly_cons(ao_lisp_stack->sexprs) = *ao_lisp_poly_cons(ao_lisp_v);
-               ao_lisp_v = ao_lisp_stack->sexprs;
-               DBGI("sexprs rewritten to: "); DBG_POLY(ao_lisp_v); DBG("\n");
-       }
-       ao_lisp_stack->sexprs = AO_LISP_NIL;
-       ao_lisp_stack->state = eval_sexpr;
-       return 1;
-}
-
-static int (*const evals[])(void) = {
-       [eval_sexpr] = ao_lisp_eval_sexpr,
-       [eval_val] = ao_lisp_eval_val,
-       [eval_formal] = ao_lisp_eval_formal,
-       [eval_exec] = ao_lisp_eval_exec,
-       [eval_cond] = ao_lisp_eval_cond,
-       [eval_cond_test] = ao_lisp_eval_cond_test,
-       [eval_progn] = ao_lisp_eval_progn,
-       [eval_while] = ao_lisp_eval_while,
-       [eval_while_test] = ao_lisp_eval_while_test,
-       [eval_macro] = ao_lisp_eval_macro,
-};
-
-const char *ao_lisp_state_names[] = {
-       "sexpr",
-       "val",
-       "formal",
-       "exec",
-       "cond",
-       "cond_test",
-       "progn",
-};
-
-/*
- * Called at restore time to reset all execution state
- */
-
-void
-ao_lisp_eval_clear_globals(void)
-{
-       ao_lisp_stack = NULL;
-       ao_lisp_frame_current = NULL;
-       ao_lisp_v = AO_LISP_NIL;
-}
-
-int
-ao_lisp_eval_restart(void)
-{
-       return ao_lisp_stack_push();
-}
-
-ao_poly
-ao_lisp_eval(ao_poly _v)
-{
-       ao_lisp_v = _v;
-
-       if (!ao_lisp_stack_push())
-               return AO_LISP_NIL;
-
-       while (ao_lisp_stack) {
-               if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) {
-                       ao_lisp_stack_clear();
-                       return AO_LISP_NIL;
-               }
-       }
-       DBG_DO(if (ao_lisp_frame_current) {DBGI("frame left as "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");});
-       ao_lisp_frame_current = NULL;
-       return ao_lisp_v;
-}
diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c
deleted file mode 100644 (file)
index 05f6d25..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
-static inline int
-frame_num_size(int num)
-{
-       return sizeof (struct ao_lisp_frame) + num * sizeof (struct ao_lisp_val);
-}
-
-static int
-frame_size(void *addr)
-{
-       struct ao_lisp_frame    *frame = addr;
-       return frame_num_size(frame->num);
-}
-
-static void
-frame_mark(void *addr)
-{
-       struct ao_lisp_frame    *frame = addr;
-       int                     f;
-
-       for (;;) {
-               MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame));
-               if (!AO_LISP_IS_POOL(frame))
-                       break;
-               for (f = 0; f < frame->num; f++) {
-                       struct ao_lisp_val      *v = &frame->vals[f];
-
-                       ao_lisp_poly_mark(v->val, 0);
-                       MDBG_MOVE("frame mark atom %s %d val %d at %d\n",
-                                 ao_lisp_poly_atom(v->atom)->name,
-                                 MDBG_OFFSET(ao_lisp_ref(v->atom)),
-                                 MDBG_OFFSET(ao_lisp_ref(v->val)), f);
-               }
-               frame = ao_lisp_poly_frame(frame->prev);
-               MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame));
-               if (!frame)
-                       break;
-               if (ao_lisp_mark_memory(&ao_lisp_frame_type, frame))
-                       break;
-       }
-}
-
-static void
-frame_move(void *addr)
-{
-       struct ao_lisp_frame    *frame = addr;
-       int                     f;
-
-       for (;;) {
-               struct ao_lisp_frame    *prev;
-               int                     ret;
-
-               MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame));
-               if (!AO_LISP_IS_POOL(frame))
-                       break;
-               for (f = 0; f < frame->num; f++) {
-                       struct ao_lisp_val      *v = &frame->vals[f];
-
-                       ao_lisp_poly_move(&v->atom, 0);
-                       ao_lisp_poly_move(&v->val, 0);
-                       MDBG_MOVE("frame move atom %s %d val %d at %d\n",
-                                 ao_lisp_poly_atom(v->atom)->name,
-                                 MDBG_OFFSET(ao_lisp_ref(v->atom)),
-                                 MDBG_OFFSET(ao_lisp_ref(v->val)), f);
-               }
-               prev = ao_lisp_poly_frame(frame->prev);
-               if (!prev)
-                       break;
-               ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &prev);
-               if (prev != ao_lisp_poly_frame(frame->prev)) {
-                       MDBG_MOVE("frame prev moved from %d to %d\n",
-                                 MDBG_OFFSET(ao_lisp_poly_frame(frame->prev)),
-                                 MDBG_OFFSET(prev));
-                       frame->prev = ao_lisp_frame_poly(prev);
-               }
-               if (ret)
-                       break;
-               frame = prev;
-       }
-}
-
-const struct ao_lisp_type ao_lisp_frame_type = {
-       .mark = frame_mark,
-       .size = frame_size,
-       .move = frame_move,
-       .name = "frame",
-};
-
-void
-ao_lisp_frame_print(ao_poly p)
-{
-       struct ao_lisp_frame    *frame = ao_lisp_poly_frame(p);
-       int                     f;
-
-       printf ("{");
-       if (frame) {
-               if (frame->type & AO_LISP_FRAME_PRINT)
-                       printf("recurse...");
-               else {
-                       frame->type |= AO_LISP_FRAME_PRINT;
-                       for (f = 0; f < frame->num; f++) {
-                               if (f != 0)
-                                       printf(", ");
-                               ao_lisp_poly_print(frame->vals[f].atom);
-                               printf(" = ");
-                               ao_lisp_poly_print(frame->vals[f].val);
-                       }
-                       if (frame->prev)
-                               ao_lisp_poly_print(frame->prev);
-                       frame->type &= ~AO_LISP_FRAME_PRINT;
-               }
-       }
-       printf("}");
-}
-
-static int
-ao_lisp_frame_find(struct ao_lisp_frame *frame, int top, ao_poly atom)
-{
-       int l = 0;
-       int r = top - 1;
-       while (l <= r) {
-               int m = (l + r) >> 1;
-               if (frame->vals[m].atom < atom)
-                       l = m + 1;
-               else
-                       r = m - 1;
-       }
-       return l;
-}
-
-ao_poly *
-ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom)
-{
-       int l = ao_lisp_frame_find(frame, frame->num, atom);
-
-       if (l >= frame->num)
-               return NULL;
-
-       if (frame->vals[l].atom != atom)
-               return NULL;
-       return &frame->vals[l].val;
-}
-
-int
-ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val)
-{
-       while (frame) {
-               if (!AO_LISP_IS_CONST(frame)) {
-                       ao_poly *ref = ao_lisp_frame_ref(frame, atom);
-                       if (ref) {
-                               *ref = val;
-                               return 1;
-                       }
-               }
-               frame = ao_lisp_poly_frame(frame->prev);
-       }
-       return 0;
-}
-
-ao_poly
-ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom)
-{
-       while (frame) {
-               ao_poly *ref = ao_lisp_frame_ref(frame, atom);
-               if (ref)
-                       return *ref;
-               frame = ao_lisp_poly_frame(frame->prev);
-       }
-       return AO_LISP_NIL;
-}
-
-struct ao_lisp_frame   *ao_lisp_frame_free_list[AO_LISP_FRAME_FREE];
-
-struct ao_lisp_frame *
-ao_lisp_frame_new(int num)
-{
-       struct ao_lisp_frame    *frame;
-
-       if (num < AO_LISP_FRAME_FREE && (frame = ao_lisp_frame_free_list[num]))
-               ao_lisp_frame_free_list[num] = ao_lisp_poly_frame(frame->prev);
-       else {
-               frame = ao_lisp_alloc(frame_num_size(num));
-               if (!frame)
-                       return NULL;
-       }
-       frame->type = AO_LISP_FRAME;
-       frame->num = num;
-       frame->prev = AO_LISP_NIL;
-       memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val));
-       return frame;
-}
-
-ao_poly
-ao_lisp_frame_mark(struct ao_lisp_frame *frame)
-{
-       if (!frame)
-               return AO_LISP_NIL;
-       frame->type |= AO_LISP_FRAME_MARK;
-       return ao_lisp_frame_poly(frame);
-}
-
-void
-ao_lisp_frame_free(struct ao_lisp_frame *frame)
-{
-       if (!ao_lisp_frame_marked(frame)) {
-               int     num = frame->num;
-               if (num < AO_LISP_FRAME_FREE) {
-                       frame->prev = ao_lisp_frame_poly(ao_lisp_frame_free_list[num]);
-                       ao_lisp_frame_free_list[num] = frame;
-               }
-       }
-}
-
-static struct ao_lisp_frame *
-ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num)
-{
-       struct ao_lisp_frame    *frame = *frame_ref;
-       struct ao_lisp_frame    *new;
-       int                     copy;
-
-       if (new_num == frame->num)
-               return frame;
-       new = ao_lisp_frame_new(new_num);
-       if (!new)
-               return NULL;
-       /*
-        * Re-fetch the frame as it may have moved
-        * during the allocation
-        */
-       frame = *frame_ref;
-       copy = new_num;
-       if (copy > frame->num)
-               copy = frame->num;
-       memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val));
-       new->prev = frame->prev;
-       ao_lisp_frame_free(frame);
-       return new;
-}
-
-void
-ao_lisp_frame_bind(struct ao_lisp_frame *frame, int num, ao_poly atom, ao_poly val)
-{
-       int l = ao_lisp_frame_find(frame, num, atom);
-
-       memmove(&frame->vals[l+1],
-               &frame->vals[l],
-               (num - l) * sizeof (struct ao_lisp_val));
-       frame->vals[l].atom = atom;
-       frame->vals[l].val = val;
-}
-
-int
-ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val)
-{
-       struct ao_lisp_frame *frame = *frame_ref;
-       ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL;
-
-       if (!ref) {
-               int f;
-               ao_lisp_poly_stash(0, atom);
-               ao_lisp_poly_stash(1, val);
-               if (frame) {
-                       f = frame->num;
-                       frame = ao_lisp_frame_realloc(frame_ref, f + 1);
-               } else {
-                       f = 0;
-                       frame = ao_lisp_frame_new(1);
-               }
-               if (!frame)
-                       return 0;
-               *frame_ref = frame;
-               atom = ao_lisp_poly_fetch(0);
-               val = ao_lisp_poly_fetch(1);
-               ao_lisp_frame_bind(frame, frame->num - 1, atom, val);
-       } else
-               *ref = val;
-       return 1;
-}
diff --git a/src/lisp/ao_lisp_int.c b/src/lisp/ao_lisp_int.c
deleted file mode 100644 (file)
index 77f65e9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
-void
-ao_lisp_int_print(ao_poly p)
-{
-       int i = ao_lisp_poly_int(p);
-       printf("%d", i);
-}
diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c
deleted file mode 100644 (file)
index 526863c..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright © 2016 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include "ao_lisp.h"
-
-int
-lambda_size(void *addr)
-{
-       (void) addr;
-       return sizeof (struct ao_lisp_lambda);
-}
-
-void
-lambda_mark(void *addr)
-{
-       struct ao_lisp_lambda   *lambda = addr;
-
-       ao_lisp_poly_mark(lambda->code, 0);
-       ao_lisp_poly_mark(lambda->frame, 0);
-}
-
-void
-lambda_move(void *addr)
-{
-       struct ao_lisp_lambda   *lambda = addr;
-
-       ao_lisp_poly_move(&lambda->code, 0);
-       ao_lisp_poly_move(&lambda->frame, 0);
-}
-
-const struct ao_lisp_type ao_lisp_lambda_type = {
-       .size = lambda_size,
-       .mark = lambda_mark,
-       .move = lambda_move,
-       .name = "lambda",
-};
-
-void
-ao_lisp_lambda_print(ao_poly poly)
-{
-       struct ao_lisp_lambda   *lambda = ao_lisp_poly_lambda(poly);
-       struct ao_lisp_cons     *cons = ao_lisp_poly_cons(lambda->code);
-
-       printf("(");
-       printf("%s", ao_lisp_args_name(lambda->args));
-       while (cons) {
-               printf(" ");
-               ao_lisp_poly_print(cons->car);
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-       printf(")");
-}
-
-ao_poly
-ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args)
-{
-       ao_lisp_cons_stash(0, code);
-       struct ao_lisp_lambda   *lambda = ao_lisp_alloc(sizeof (struct ao_lisp_lambda));
-       code = ao_lisp_cons_fetch(0);
-       struct ao_lisp_cons     *arg;
-       int                     f;
-
-       if (!lambda)
-               return AO_LISP_NIL;
-
-       if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, code, 0, AO_LISP_CONS, 1))
-               return AO_LISP_NIL;
-       f = 0;
-       arg = ao_lisp_poly_cons(ao_lisp_arg(code, 0));
-       while (arg) {
-               if (ao_lisp_poly_type(arg->car) != AO_LISP_ATOM)
-                       return ao_lisp_error(AO_LISP_INVALID, "formal %d is not an atom", f);
-               arg = ao_lisp_poly_cons(arg->cdr);
-               f++;
-       }
-
-       lambda->type = AO_LISP_LAMBDA;
-       lambda->args = args;
-       lambda->code = ao_lisp_cons_poly(code);
-       lambda->frame = ao_lisp_frame_mark(ao_lisp_frame_current);
-       DBGI("build frame: "); DBG_POLY(lambda->frame); DBG("\n");
-       DBG_STACK();
-       return ao_lisp_lambda_poly(lambda);
-}
-
-ao_poly
-ao_lisp_lambda(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_LAMBDA);
-}
-
-ao_poly
-ao_lisp_lexpr(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_LEXPR);
-}
-
-ao_poly
-ao_lisp_nlambda(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_NLAMBDA);
-}
-
-ao_poly
-ao_lisp_macro(struct ao_lisp_cons *cons)
-{
-       return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_MACRO);
-}
-
-ao_poly
-ao_lisp_lambda_eval(void)
-{
-       struct ao_lisp_lambda   *lambda = ao_lisp_poly_lambda(ao_lisp_v);
-       struct ao_lisp_cons     *cons = ao_lisp_poly_cons(ao_lisp_stack->values);
-       struct ao_lisp_cons     *code = ao_lisp_poly_cons(lambda->code);
-       struct ao_lisp_cons     *args = ao_lisp_poly_cons(ao_lisp_arg(code, 0));
-       struct ao_lisp_frame    *next_frame;
-       int                     args_wanted;
-       int                     args_provided;
-       int                     f;
-       struct ao_lisp_cons     *vals;
-
-       DBGI("lambda "); DBG_POLY(ao_lisp_lambda_poly(lambda)); DBG("\n");
-
-       args_wanted = ao_lisp_cons_length(args);
-
-       /* Create a frame to hold the variables
-        */
-       args_provided = ao_lisp_cons_length(cons) - 1;
-       if (lambda->args == AO_LISP_FUNC_LAMBDA) {
-               if (args_wanted != args_provided)
-                       return ao_lisp_error(AO_LISP_INVALID, "need %d args, got %d", args_wanted, args_provided);
-       } else {
-               if (args_provided < args_wanted - 1)
-                       return ao_lisp_error(AO_LISP_INVALID, "need at least %d args, got %d", args_wanted, args_provided);
-       }
-
-       next_frame = ao_lisp_frame_new(args_wanted);
-
-       /* Re-fetch all of the values in case something moved */
-       lambda = ao_lisp_poly_lambda(ao_lisp_v);
-       cons = ao_lisp_poly_cons(ao_lisp_stack->values);
-       code = ao_lisp_poly_cons(lambda->code);
-       args = ao_lisp_poly_cons(ao_lisp_arg(code, 0));
-       vals = ao_lisp_poly_cons(cons->cdr);
-
-       next_frame->prev = lambda->frame;
-       ao_lisp_frame_current = next_frame;
-       ao_lisp_stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current);
-
-       switch (lambda->args) {
-       case AO_LISP_FUNC_LAMBDA:
-               for (f = 0; f < args_wanted; f++) {
-                       DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n");
-                       ao_lisp_frame_bind(next_frame, f, args->car, vals->car);
-                       args = ao_lisp_poly_cons(args->cdr);
-                       vals = ao_lisp_poly_cons(vals->cdr);
-               }
-               if (!ao_lisp_stack_marked(ao_lisp_stack))
-                       ao_lisp_cons_free(cons);
-               cons = NULL;
-               break;
-       case AO_LISP_FUNC_LEXPR:
-       case AO_LISP_FUNC_NLAMBDA:
-       case AO_LISP_FUNC_MACRO:
-               for (f = 0; f < args_wanted - 1; f++) {
-                       DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n");
-                       ao_lisp_frame_bind(next_frame, f, args->car, vals->car);
-                       args = ao_lisp_poly_cons(args->cdr);
-                       vals = ao_lisp_poly_cons(vals->cdr);
-               }
-               DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(ao_lisp_cons_poly(vals)); DBG("\n");
-               ao_lisp_frame_bind(next_frame, f, args->car, ao_lisp_cons_poly(vals));
-               break;
-       default:
-               break;
-       }
-       DBGI("eval frame: "); DBG_POLY(ao_lisp_frame_poly(next_frame)); DBG("\n");
-       DBG_STACK();
-       DBGI("eval code: "); DBG_POLY(code->cdr); DBG("\n");
-       return code->cdr;
-}
diff --git a/src/lisp/ao_lisp_lex.c b/src/lisp/ao_lisp_lex.c
deleted file mode 100644 (file)
index fe7c47f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c
deleted file mode 100644 (file)
index 49f989e..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-#include <stdlib.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <getopt.h>
-
-static struct ao_lisp_builtin *
-ao_lisp_make_builtin(enum ao_lisp_builtin_id func, int args) {
-       struct ao_lisp_builtin *b = ao_lisp_alloc(sizeof (struct ao_lisp_builtin));
-
-       b->type = AO_LISP_BUILTIN;
-       b->func = func;
-       b->args = args;
-       return b;
-}
-
-struct builtin_func {
-       char    *name;
-       int     args;
-       int     func;
-};
-
-struct builtin_func funcs[] = {
-       { .name = "eval",       .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_eval },
-       { .name = "read",       .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_read },
-       { .name = "lambda",     .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_lambda },
-       { .name = "lexpr",      .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_lexpr },
-       { .name = "nlambda",    .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_nlambda },
-       { .name = "macro",      .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_macro },
-       { .name = "car",        .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_car },
-       { .name = "cdr",        .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_cdr },
-       { .name = "cons",       .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_cons },
-       { .name = "last",       .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_last },
-       { .name = "length",     .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_length },
-       { .name = "quote",      .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_quote },
-       { .name = "set",        .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_set },
-       { .name = "setq",       .args = AO_LISP_FUNC_MACRO,     .func = builtin_setq },
-       { .name = "cond",       .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_cond },
-       { .name = "progn",      .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_progn },
-       { .name = "while",      .args = AO_LISP_FUNC_NLAMBDA,   .func = builtin_while },
-       { .name = "print",      .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_print },
-       { .name = "patom",      .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_patom },
-       { .name = "+",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_plus },
-       { .name = "-",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_minus },
-       { .name = "*",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_times },
-       { .name = "/",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_divide },
-       { .name = "%",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_mod },
-       { .name = "=",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_equal },
-       { .name = "<",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_less },
-       { .name = ">",          .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_greater },
-       { .name = "<=",         .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_less_equal },
-       { .name = ">=",         .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_greater_equal },
-       { .name = "pack",       .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_pack },
-       { .name = "unpack",     .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_unpack },
-       { .name = "flush",      .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_flush },
-       { .name = "delay",      .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_delay },
-       { .name = "led",        .args = AO_LISP_FUNC_F_LEXPR,   .func = builtin_led },
-       { .name = "save",       .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_save },
-       { .name = "restore",    .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_restore },
-       { .name = "call/cc",    .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_call_cc },
-       { .name = "collect",    .args = AO_LISP_FUNC_F_LAMBDA,  .func = builtin_collect },
-};
-
-#define N_FUNC (sizeof funcs / sizeof funcs[0])
-
-struct ao_lisp_frame   *globals;
-
-static int
-is_atom(int offset)
-{
-       struct ao_lisp_atom *a;
-
-       for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next))
-               if (((uint8_t *) a->name - ao_lisp_const) == offset)
-                       return strlen(a->name);
-       return 0;
-}
-
-#define AO_FEC_CRC_INIT        0xffff
-
-static inline uint16_t
-ao_fec_crc_byte(uint8_t byte, uint16_t crc)
-{
-       uint8_t bit;
-
-       for (bit = 0; bit < 8; bit++) {
-               if (((crc & 0x8000) >> 8) ^ (byte & 0x80))
-                       crc = (crc << 1) ^ 0x8005;
-               else
-                       crc = (crc << 1);
-               byte <<= 1;
-       }
-       return crc;
-}
-
-uint16_t
-ao_fec_crc(const uint8_t *bytes, uint8_t len)
-{
-       uint16_t        crc = AO_FEC_CRC_INIT;
-
-       while (len--)
-               crc = ao_fec_crc_byte(*bytes++, crc);
-       return crc;
-}
-
-struct ao_lisp_macro_stack {
-       struct ao_lisp_macro_stack *next;
-       ao_poly p;
-};
-
-struct ao_lisp_macro_stack *macro_stack;
-
-int
-ao_lisp_macro_push(ao_poly p)
-{
-       struct ao_lisp_macro_stack *m = macro_stack;
-
-       while (m) {
-               if (m->p == p)
-                       return 1;
-               m = m->next;
-       }
-       m = malloc (sizeof (struct ao_lisp_macro_stack));
-       m->p = p;
-       m->next = macro_stack;
-       macro_stack = m;
-       return 0;
-}
-
-void
-ao_lisp_macro_pop(void)
-{
-       struct ao_lisp_macro_stack *m = macro_stack;
-
-       macro_stack = m->next;
-       free(m);
-}
-
-#define DBG_MACRO 0
-#if DBG_MACRO
-int macro_scan_depth;
-
-void indent(void)
-{
-       int i;
-       for (i = 0; i < macro_scan_depth; i++)
-               printf("  ");
-}
-#define MACRO_DEBUG(a) a
-#else
-#define MACRO_DEBUG(a)
-#endif
-
-ao_poly
-ao_has_macro(ao_poly p);
-
-ao_poly
-ao_macro_test_get(ao_poly atom)
-{
-       ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_global, atom);
-       if (ref)
-               return *ref;
-       return AO_LISP_NIL;
-}
-
-ao_poly
-ao_is_macro(ao_poly p)
-{
-       struct ao_lisp_builtin  *builtin;
-       struct ao_lisp_lambda   *lambda;
-       ao_poly ret;
-
-       MACRO_DEBUG(indent(); printf ("is macro "); ao_lisp_poly_print(p); printf("\n"); ++macro_scan_depth);
-       switch (ao_lisp_poly_type(p)) {
-       case AO_LISP_ATOM:
-               if (ao_lisp_macro_push(p))
-                       ret = AO_LISP_NIL;
-               else {
-                       if (ao_is_macro(ao_macro_test_get(p)))
-                               ret = p;
-                       else
-                               ret = AO_LISP_NIL;
-                       ao_lisp_macro_pop();
-               }
-               break;
-       case AO_LISP_CONS:
-               ret = ao_has_macro(p);
-               break;
-       case AO_LISP_BUILTIN:
-               builtin = ao_lisp_poly_builtin(p);
-               if ((builtin->args & AO_LISP_FUNC_MASK) == AO_LISP_FUNC_MACRO)
-                       ret = p;
-               else
-                       ret = 0;
-               break;
-
-       case AO_LISP_LAMBDA:
-               lambda = ao_lisp_poly_lambda(p);
-               if (lambda->args == AO_LISP_FUNC_MACRO)
-                       ret = p;
-               else
-                       ret = ao_has_macro(lambda->code);
-               break;
-       default:
-               ret = AO_LISP_NIL;
-               break;
-       }
-       MACRO_DEBUG(--macro_scan_depth; indent(); printf ("... "); ao_lisp_poly_print(ret); printf("\n"));
-       return ret;
-}
-
-ao_poly
-ao_has_macro(ao_poly p)
-{
-       struct ao_lisp_cons     *cons;
-       struct ao_lisp_lambda   *lambda;
-       ao_poly                 m;
-
-       if (p == AO_LISP_NIL)
-               return AO_LISP_NIL;
-
-       MACRO_DEBUG(indent(); printf("has macro "); ao_lisp_poly_print(p); printf("\n"); ++macro_scan_depth);
-       switch (ao_lisp_poly_type(p)) {
-       case AO_LISP_LAMBDA:
-               lambda = ao_lisp_poly_lambda(p);
-               p = ao_has_macro(lambda->code);
-               break;
-       case AO_LISP_CONS:
-               cons = ao_lisp_poly_cons(p);
-               if ((p = ao_is_macro(cons->car)))
-                       break;
-
-               cons = ao_lisp_poly_cons(cons->cdr);
-               p = AO_LISP_NIL;
-               while (cons) {
-                       m = ao_has_macro(cons->car);
-                       if (m) {
-                               p = m;
-                               break;
-                       }
-                       cons = ao_lisp_poly_cons(cons->cdr);
-               }
-               break;
-
-       default:
-               p = AO_LISP_NIL;
-               break;
-       }
-       MACRO_DEBUG(--macro_scan_depth; indent(); printf("... "); ao_lisp_poly_print(p); printf("\n"));
-       return p;
-}
-
-int
-ao_lisp_read_eval_abort(void)
-{
-       ao_poly in, out = AO_LISP_NIL;
-       for(;;) {
-               in = ao_lisp_read();
-               if (in == _ao_lisp_atom_eof)
-                       break;
-               out = ao_lisp_eval(in);
-               if (ao_lisp_exception)
-                       return 0;
-               ao_lisp_poly_print(out);
-               putchar ('\n');
-       }
-       return 1;
-}
-
-static FILE    *in;
-static FILE    *out;
-
-int
-ao_lisp_getc(void)
-{
-       return getc(in);
-}
-
-static const struct option options[] = {
-       { .name = "out", .has_arg = 1, .val = 'o' },
-       { 0, 0, 0, 0 }
-};
-
-static void usage(char *program)
-{
-       fprintf(stderr, "usage: %s [--out=<output>] [input]\n", program);
-       exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
-       int     f, o;
-       ao_poly val;
-       struct ao_lisp_atom     *a;
-       struct ao_lisp_builtin  *b;
-       int     in_atom = 0;
-       char    *out_name = NULL;
-       int     c;
-
-       in = stdin;
-       out = stdout;
-
-       while ((c = getopt_long(argc, argv, "o:", options, NULL)) != -1) {
-               switch (c) {
-               case 'o':
-                       out_name = optarg;
-                       break;
-               default:
-                       usage(argv[0]);
-                       break;
-               }
-       }
-
-       for (f = 0; f < (int) N_FUNC; f++) {
-               b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args);
-               a = ao_lisp_atom_intern(funcs[f].name);
-               ao_lisp_atom_set(ao_lisp_atom_poly(a),
-                                ao_lisp_builtin_poly(b));
-       }
-
-       /* boolean constants */
-       ao_lisp_atom_set(ao_lisp_atom_poly(ao_lisp_atom_intern("nil")),
-                        AO_LISP_NIL);
-       a = ao_lisp_atom_intern("t");
-       ao_lisp_atom_set(ao_lisp_atom_poly(a),
-                        ao_lisp_atom_poly(a));
-
-       /* end of file value */
-       a = ao_lisp_atom_intern("eof");
-       ao_lisp_atom_set(ao_lisp_atom_poly(a),
-                        ao_lisp_atom_poly(a));
-
-       if (argv[optind]){
-               in = fopen(argv[optind], "r");
-               if (!in) {
-                       perror(argv[optind]);
-                       exit(1);
-               }
-       }
-       if (!ao_lisp_read_eval_abort()) {
-               fprintf(stderr, "eval failed\n");
-               exit(1);
-       }
-
-       /* Reduce to referenced values */
-       ao_lisp_collect(AO_LISP_COLLECT_FULL);
-
-       for (f = 0; f < ao_lisp_frame_global->num; f++) {
-               val = ao_has_macro(ao_lisp_frame_global->vals[f].val);
-               if (val != AO_LISP_NIL) {
-                       printf("error: function %s contains unresolved macro: ",
-                              ao_lisp_poly_atom(ao_lisp_frame_global->vals[f].atom)->name);
-                       ao_lisp_poly_print(val);
-                       printf("\n");
-                       exit(1);
-               }
-       }
-
-       if (out_name) {
-               out = fopen(out_name, "w");
-               if (!out) {
-                       perror(out_name);
-                       exit(1);
-               }
-       }
-
-       fprintf(out, "/* Generated file, do not edit */\n\n");
-
-       fprintf(out, "#define AO_LISP_POOL_CONST %d\n", ao_lisp_top);
-       fprintf(out, "extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n");
-       fprintf(out, "#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms));
-       fprintf(out, "#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(ao_lisp_frame_global));
-       fprintf(out, "#define ao_lisp_const_checksum ((uint16_t) 0x%04x)\n", ao_fec_crc(ao_lisp_const, ao_lisp_top));
-
-
-       for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) {
-               char    *n = a->name, c;
-               fprintf(out, "#define _ao_lisp_atom_");
-               while ((c = *n++)) {
-                       if (isalnum(c))
-                               fprintf(out, "%c", c);
-                       else
-                               fprintf(out, "%02x", c);
-               }
-               fprintf(out, "  0x%04x\n", ao_lisp_atom_poly(a));
-       }
-       fprintf(out, "#ifdef AO_LISP_CONST_BITS\n");
-       fprintf(out, "const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute((aligned(4))) = {");
-       for (o = 0; o < ao_lisp_top; o++) {
-               uint8_t c;
-               if ((o & 0xf) == 0)
-                       fprintf(out, "\n\t");
-               else
-                       fprintf(out, " ");
-               c = ao_lisp_const[o];
-               if (!in_atom)
-                       in_atom = is_atom(o);
-               if (in_atom) {
-                       fprintf(out, " '%c',", c);
-                       in_atom--;
-               } else {
-                       fprintf(out, "0x%02x,", c);
-               }
-       }
-       fprintf(out, "\n};\n");
-       fprintf(out, "#endif /* AO_LISP_CONST_BITS */\n");
-       exit(0);
-}
diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c
deleted file mode 100644 (file)
index d067ea0..0000000
+++ /dev/null
@@ -1,880 +0,0 @@
-/*
- * 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.
- */
-
-#define AO_LISP_CONST_BITS
-
-#include "ao_lisp.h"
-#include <stdio.h>
-
-#ifdef AO_LISP_MAKE_CONST
-
-/*
- * When building the constant table, it is the
- * pool for allocations.
- */
-
-#include <stdlib.h>
-uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));
-#define ao_lisp_pool ao_lisp_const
-#undef AO_LISP_POOL
-#define AO_LISP_POOL AO_LISP_POOL_CONST
-
-#else
-
-uint8_t        ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4)));
-
-#endif
-
-#ifndef DBG_MEM_STATS
-#define DBG_MEM_STATS  DBG_MEM
-#endif
-
-#if DBG_MEM
-int dbg_move_depth;
-int dbg_mem = DBG_MEM_START;
-int dbg_validate = 0;
-
-struct ao_lisp_record {
-       struct ao_lisp_record           *next;
-       const struct ao_lisp_type       *type;
-       void                            *addr;
-       int                             size;
-};
-
-static struct ao_lisp_record   *record_head, **record_tail;
-
-static void
-ao_lisp_record_free(struct ao_lisp_record *record)
-{
-       while (record) {
-               struct ao_lisp_record *next = record->next;
-               free(record);
-               record = next;
-       }
-}
-
-static void
-ao_lisp_record_reset(void)
-{
-       ao_lisp_record_free(record_head);
-       record_head = NULL;
-       record_tail = &record_head;
-}
-
-static void
-ao_lisp_record(const struct ao_lisp_type       *type,
-              void                             *addr,
-              int                              size)
-{
-       struct ao_lisp_record   *r = malloc(sizeof (struct ao_lisp_record));
-
-       r->next = NULL;
-       r->type = type;
-       r->addr = addr;
-       r->size = size;
-       *record_tail = r;
-       record_tail = &r->next;
-}
-
-static struct ao_lisp_record *
-ao_lisp_record_save(void)
-{
-       struct ao_lisp_record *r = record_head;
-
-       record_head = NULL;
-       record_tail = &record_head;
-       return r;
-}
-
-static void
-ao_lisp_record_compare(char *where,
-                      struct ao_lisp_record *a,
-                      struct ao_lisp_record *b)
-{
-       while (a && b) {
-               if (a->type != b->type || a->size != b->size) {
-                       printf("%s record difers %d %s %d -> %d %s %d\n",
-                              where,
-                              MDBG_OFFSET(a->addr),
-                              a->type->name,
-                              a->size,
-                              MDBG_OFFSET(b->addr),
-                              b->type->name,
-                              b->size);
-                       ao_lisp_abort();
-               }
-               a = a->next;
-               b = b->next;
-       }
-       if (a) {
-               printf("%s record differs %d %s %d -> NULL\n",
-                      where,
-                      MDBG_OFFSET(a->addr),
-                      a->type->name,
-                      a->size);
-               ao_lisp_abort();
-       }
-       if (b) {
-               printf("%s record differs NULL -> %d %s %d\n",
-                      where,
-                      MDBG_OFFSET(b->addr),
-                      b->type->name,
-                      b->size);
-               ao_lisp_abort();
-       }
-}
-
-#else
-#define ao_lisp_record_reset()
-#endif
-
-uint8_t        ao_lisp_exception;
-
-struct ao_lisp_root {
-       const struct ao_lisp_type       *type;
-       void                            **addr;
-};
-
-static struct ao_lisp_cons     *save_cons[2];
-static char                    *save_string[2];
-static ao_poly                 save_poly[3];
-
-static const struct ao_lisp_root       ao_lisp_root[] = {
-       {
-               .type = &ao_lisp_cons_type,
-               .addr = (void **) &save_cons[0],
-       },
-       {
-               .type = &ao_lisp_cons_type,
-               .addr = (void **) &save_cons[1],
-       },
-       {
-               .type = &ao_lisp_string_type,
-               .addr = (void **) &save_string[0],
-       },
-       {
-               .type = &ao_lisp_string_type,
-               .addr = (void **) &save_string[1],
-       },
-       {
-               .type = NULL,
-               .addr = (void **) (void *) &save_poly[0]
-       },
-       {
-               .type = NULL,
-               .addr = (void **) (void *) &save_poly[1]
-       },
-       {
-               .type = NULL,
-               .addr = (void **) (void *) &save_poly[2]
-       },
-       {
-               .type = &ao_lisp_atom_type,
-               .addr = (void **) &ao_lisp_atoms
-       },
-       {
-               .type = &ao_lisp_frame_type,
-               .addr = (void **) &ao_lisp_frame_global,
-       },
-       {
-               .type = &ao_lisp_frame_type,
-               .addr = (void **) &ao_lisp_frame_current,
-       },
-       {
-               .type = &ao_lisp_stack_type,
-               .addr = (void **) &ao_lisp_stack,
-       },
-       {
-               .type = NULL,
-               .addr = (void **) (void *) &ao_lisp_v,
-       },
-       {
-               .type = &ao_lisp_cons_type,
-               .addr = (void **) &ao_lisp_read_cons,
-       },
-       {
-               .type = &ao_lisp_cons_type,
-               .addr = (void **) &ao_lisp_read_cons_tail,
-       },
-       {
-               .type = &ao_lisp_cons_type,
-               .addr = (void **) &ao_lisp_read_stack,
-       },
-};
-
-#define AO_LISP_ROOT   (sizeof (ao_lisp_root) / sizeof (ao_lisp_root[0]))
-
-static const void ** const ao_lisp_cache[] = {
-       (const void **) &ao_lisp_cons_free_list,
-       (const void **) &ao_lisp_stack_free_list,
-       (const void **) &ao_lisp_frame_free_list[0],
-       (const void **) &ao_lisp_frame_free_list[1],
-       (const void **) &ao_lisp_frame_free_list[2],
-       (const void **) &ao_lisp_frame_free_list[3],
-       (const void **) &ao_lisp_frame_free_list[4],
-       (const void **) &ao_lisp_frame_free_list[5],
-};
-
-#if AO_LISP_FRAME_FREE != 6
-#error Unexpected AO_LISP_FRAME_FREE value
-#endif
-
-#define AO_LISP_CACHE  (sizeof (ao_lisp_cache) / sizeof (ao_lisp_cache[0]))
-
-#define AO_LISP_BUSY_SIZE      ((AO_LISP_POOL + 31) / 32)
-
-static uint8_t ao_lisp_busy[AO_LISP_BUSY_SIZE];
-static uint8_t ao_lisp_cons_note[AO_LISP_BUSY_SIZE];
-static uint8_t ao_lisp_cons_last[AO_LISP_BUSY_SIZE];
-static uint8_t ao_lisp_cons_noted;
-
-uint16_t       ao_lisp_top;
-
-struct ao_lisp_chunk {
-       uint16_t                old_offset;
-       union {
-               uint16_t        size;
-               uint16_t        new_offset;
-       };
-};
-
-#define AO_LISP_NCHUNK 64
-
-static struct ao_lisp_chunk ao_lisp_chunk[AO_LISP_NCHUNK];
-
-/* Offset of an address within the pool. */
-static inline uint16_t pool_offset(void *addr) {
-#if DBG_MEM
-       if (!AO_LISP_IS_POOL(addr))
-               ao_lisp_abort();
-#endif
-       return ((uint8_t *) addr) - ao_lisp_pool;
-}
-
-static inline void mark(uint8_t *tag, int offset) {
-       int     byte = offset >> 5;
-       int     bit = (offset >> 2) & 7;
-       tag[byte] |= (1 << bit);
-}
-
-static inline void clear(uint8_t *tag, int offset) {
-       int     byte = offset >> 5;
-       int     bit = (offset >> 2) & 7;
-       tag[byte] &= ~(1 << bit);
-}
-
-static inline int busy(uint8_t *tag, int offset) {
-       int     byte = offset >> 5;
-       int     bit = (offset >> 2) & 7;
-       return (tag[byte] >> bit) & 1;
-}
-
-static inline int min(int a, int b) { return a < b ? a : b; }
-static inline int max(int a, int b) { return a > b ? a : b; }
-
-static inline int limit(int offset) {
-       return min(AO_LISP_POOL, max(offset, 0));
-}
-
-static void
-note_cons(uint16_t offset)
-{
-       MDBG_MOVE("note cons %d\n", offset);
-       ao_lisp_cons_noted = 1;
-       mark(ao_lisp_cons_note, offset);
-}
-
-static uint16_t        chunk_low, chunk_high;
-static uint16_t        chunk_first, chunk_last;
-
-static int
-find_chunk(uint16_t offset)
-{
-       int l, r;
-       /* Binary search for the location */
-       l = chunk_first;
-       r = chunk_last - 1;
-       while (l <= r) {
-               int m = (l + r) >> 1;
-               if (ao_lisp_chunk[m].old_offset < offset)
-                       l = m + 1;
-               else
-                       r = m - 1;
-       }
-       return l;
-}
-
-static void
-note_chunk(uint16_t offset, uint16_t size)
-{
-       int l;
-
-       if (offset < chunk_low || chunk_high <= offset)
-               return;
-
-       l = find_chunk(offset);
-
-       /*
-        * The correct location is always in 'l', with r = l-1 being
-        * the entry before the right one
-        */
-
-#if DBG_MEM
-       /* Off the right side */
-       if (l >= AO_LISP_NCHUNK)
-               ao_lisp_abort();
-
-       /* Off the left side */
-       if (l == 0 && chunk_last && offset > ao_lisp_chunk[0].old_offset)
-               ao_lisp_abort();
-#endif
-
-       /* Shuffle existing entries right */
-       int end = min(AO_LISP_NCHUNK, chunk_last + 1);
-
-       memmove(&ao_lisp_chunk[l+1],
-               &ao_lisp_chunk[l],
-               (end - (l+1)) * sizeof (struct ao_lisp_chunk));
-
-       /* Add new entry */
-       ao_lisp_chunk[l].old_offset = offset;
-       ao_lisp_chunk[l].size = size;
-
-       /* Increment the number of elements up to the size of the array */
-       if (chunk_last < AO_LISP_NCHUNK)
-               chunk_last++;
-
-       /* Set the top address if the array is full */
-       if (chunk_last == AO_LISP_NCHUNK)
-               chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_offset +
-                       ao_lisp_chunk[AO_LISP_NCHUNK-1].size;
-}
-
-static void
-reset_chunks(void)
-{
-       chunk_high = ao_lisp_top;
-       chunk_last = 0;
-       chunk_first = 0;
-}
-
-/*
- * Walk all referenced objects calling functions on each one
- */
-
-static void
-walk(int (*visit_addr)(const struct ao_lisp_type *type, void **addr),
-     int (*visit_poly)(ao_poly *p, uint8_t do_note_cons))
-{
-       int i;
-
-       ao_lisp_record_reset();
-       memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy));
-       memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note));
-       ao_lisp_cons_noted = 0;
-       for (i = 0; i < (int) AO_LISP_ROOT; i++) {
-               if (ao_lisp_root[i].type) {
-                       void **a = ao_lisp_root[i].addr, *v;
-                       if (a && (v = *a)) {
-                               MDBG_MOVE("root ptr %d\n", MDBG_OFFSET(v));
-                               visit_addr(ao_lisp_root[i].type, a);
-                       }
-               } else {
-                       ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p;
-                       if (a && (p = *a)) {
-                               MDBG_MOVE("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p)));
-                               visit_poly(a, 0);
-                       }
-               }
-       }
-       while (ao_lisp_cons_noted) {
-               memcpy(ao_lisp_cons_last, ao_lisp_cons_note, sizeof (ao_lisp_cons_note));
-               memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note));
-               ao_lisp_cons_noted = 0;
-               for (i = 0; i < AO_LISP_POOL; i += 4) {
-                       if (busy(ao_lisp_cons_last, i)) {
-                               void *v = ao_lisp_pool + i;
-                               MDBG_MOVE("root cons %d\n", MDBG_OFFSET(v));
-                               visit_addr(&ao_lisp_cons_type, &v);
-                       }
-               }
-       }
-}
-
-#if MDBG_DUMP
-static void
-dump_busy(void)
-{
-       int     i;
-       MDBG_MOVE("busy:");
-       for (i = 0; i < ao_lisp_top; i += 4) {
-               if ((i & 0xff) == 0) {
-                       MDBG_MORE("\n");
-                       MDBG_MOVE("%s", "");
-               }
-               else if ((i & 0x1f) == 0)
-                       MDBG_MORE(" ");
-               if (busy(ao_lisp_busy, i))
-                       MDBG_MORE("*");
-               else
-                       MDBG_MORE("-");
-       }
-       MDBG_MORE ("\n");
-}
-#define DUMP_BUSY()    dump_busy()
-#else
-#define DUMP_BUSY()
-#endif
-
-static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = {
-       [AO_LISP_CONS] = &ao_lisp_cons_type,
-       [AO_LISP_INT] = NULL,
-       [AO_LISP_STRING] = &ao_lisp_string_type,
-       [AO_LISP_OTHER] = (void *) 0x1,
-       [AO_LISP_ATOM] = &ao_lisp_atom_type,
-       [AO_LISP_BUILTIN] = &ao_lisp_builtin_type,
-       [AO_LISP_FRAME] = &ao_lisp_frame_type,
-       [AO_LISP_LAMBDA] = &ao_lisp_lambda_type,
-       [AO_LISP_STACK] = &ao_lisp_stack_type,
-};
-
-static int
-ao_lisp_mark_ref(const struct ao_lisp_type *type, void **ref)
-{
-       return ao_lisp_mark(type, *ref);
-}
-
-static int
-ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons)
-{
-       return ao_lisp_poly_mark(*p, do_note_cons);
-}
-
-#if DBG_MEM_STATS
-int ao_lisp_collects[2];
-int ao_lisp_freed[2];
-int ao_lisp_loops[2];
-#endif
-
-int ao_lisp_last_top;
-
-int
-ao_lisp_collect(uint8_t style)
-{
-       int     i;
-       int     top;
-#if DBG_MEM_STATS
-       int     loops = 0;
-#endif
-#if DBG_MEM
-       struct ao_lisp_record   *mark_record = NULL, *move_record = NULL;
-
-       MDBG_MOVE("collect %d\n", ao_lisp_collects[style]);
-#endif
-
-       /* The first time through, we're doing a full collect */
-       if (ao_lisp_last_top == 0)
-               style = AO_LISP_COLLECT_FULL;
-
-       /* Clear references to all caches */
-       for (i = 0; i < (int) AO_LISP_CACHE; i++)
-               *ao_lisp_cache[i] = NULL;
-       if (style == AO_LISP_COLLECT_FULL) {
-               chunk_low = top = 0;
-       } else {
-               chunk_low = top = ao_lisp_last_top;
-       }
-       for (;;) {
-#if DBG_MEM_STATS
-               loops++;
-#endif
-               MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top);
-               /* Find the sizes of the first chunk of objects to move */
-               reset_chunks();
-               walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref);
-#if DBG_MEM
-
-               ao_lisp_record_free(mark_record);
-               mark_record = ao_lisp_record_save();
-               if (mark_record && move_record)
-                       ao_lisp_record_compare("mark", move_record, mark_record);
-#endif
-
-               DUMP_BUSY();
-
-               /* Find the first moving object */
-               for (i = 0; i < chunk_last; i++) {
-                       uint16_t        size = ao_lisp_chunk[i].size;
-
-#if DBG_MEM
-                       if (!size)
-                               ao_lisp_abort();
-#endif
-
-                       if (ao_lisp_chunk[i].old_offset > top)
-                               break;
-
-                       MDBG_MOVE("chunk %d %d not moving\n",
-                                 ao_lisp_chunk[i].old_offset,
-                                 ao_lisp_chunk[i].size);
-#if DBG_MEM
-                       if (ao_lisp_chunk[i].old_offset != top)
-                               ao_lisp_abort();
-#endif
-                       top += size;
-               }
-
-               /*
-                * Limit amount of chunk array used in mapping moves
-                * to the active region
-                */
-               chunk_first = i;
-               chunk_low = ao_lisp_chunk[i].old_offset;
-
-               /* Copy all of the objects */
-               for (; i < chunk_last; i++) {
-                       uint16_t        size = ao_lisp_chunk[i].size;
-
-#if DBG_MEM
-                       if (!size)
-                               ao_lisp_abort();
-#endif
-
-                       MDBG_MOVE("chunk %d %d -> %d\n",
-                                 ao_lisp_chunk[i].old_offset,
-                                 size,
-                                 top);
-                       ao_lisp_chunk[i].new_offset = top;
-
-                       memmove(&ao_lisp_pool[top],
-                               &ao_lisp_pool[ao_lisp_chunk[i].old_offset],
-                               size);
-
-                       top += size;
-               }
-
-               if (chunk_first < chunk_last) {
-                       /* Relocate all references to the objects */
-                       walk(ao_lisp_move, ao_lisp_poly_move);
-
-#if DBG_MEM
-                       ao_lisp_record_free(move_record);
-                       move_record = ao_lisp_record_save();
-                       if (mark_record && move_record)
-                               ao_lisp_record_compare("move", mark_record, move_record);
-#endif
-               }
-
-               /* If we ran into the end of the heap, then
-                * there's no need to keep walking
-                */
-               if (chunk_last != AO_LISP_NCHUNK)
-                       break;
-
-               /* Next loop starts right above this loop */
-               chunk_low = chunk_high;
-       }
-
-#if DBG_MEM_STATS
-       /* Collect stats */
-       ++ao_lisp_collects[style];
-       ao_lisp_freed[style] += ao_lisp_top - top;
-       ao_lisp_loops[style] += loops;
-#endif
-
-       ao_lisp_top = top;
-       if (style == AO_LISP_COLLECT_FULL)
-               ao_lisp_last_top = top;
-
-       MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk));
-               walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref));
-
-       return AO_LISP_POOL - ao_lisp_top;
-}
-
-/*
- * Mark interfaces for objects
- */
-
-/*
- * Note a reference to memory and collect information about a few
- * object sizes at a time
- */
-
-int
-ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr)
-{
-       int offset;
-       if (!AO_LISP_IS_POOL(addr))
-               return 1;
-
-       offset = pool_offset(addr);
-       MDBG_MOVE("mark memory %d\n", MDBG_OFFSET(addr));
-       if (busy(ao_lisp_busy, offset)) {
-               MDBG_MOVE("already marked\n");
-               return 1;
-       }
-       mark(ao_lisp_busy, offset);
-       note_chunk(offset, ao_lisp_size(type, addr));
-       return 0;
-}
-
-/*
- * Mark an object and all that it refereces
- */
-int
-ao_lisp_mark(const struct ao_lisp_type *type, void *addr)
-{
-       int ret;
-       MDBG_MOVE("mark %d\n", MDBG_OFFSET(addr));
-       MDBG_MOVE_IN();
-       ret = ao_lisp_mark_memory(type, addr);
-       if (!ret) {
-               MDBG_MOVE("mark recurse\n");
-               type->mark(addr);
-       }
-       MDBG_MOVE_OUT();
-       return ret;
-}
-
-/*
- * Mark an object, unless it is a cons cell and
- * do_note_cons is set. In that case, just
- * set a bit in the cons note array; those
- * will be marked in a separate pass to avoid
- * deep recursion in the collector
- */
-int
-ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons)
-{
-       uint8_t type;
-       void    *addr;
-
-       type = ao_lisp_poly_base_type(p);
-
-       if (type == AO_LISP_INT)
-               return 1;
-
-       addr = ao_lisp_ref(p);
-       if (!AO_LISP_IS_POOL(addr))
-               return 1;
-
-       if (type == AO_LISP_CONS && do_note_cons) {
-               note_cons(pool_offset(addr));
-               return 1;
-       } else {
-               if (type == AO_LISP_OTHER)
-                       type = ao_lisp_other_type(addr);
-
-               const struct ao_lisp_type *lisp_type = ao_lisp_types[type];
-#if DBG_MEM
-               if (!lisp_type)
-                       ao_lisp_abort();
-#endif
-
-               return ao_lisp_mark(lisp_type, addr);
-       }
-}
-
-/*
- * Find the current location of an object
- * based on the original location. For unmoved
- * objects, this is simple. For moved objects,
- * go search for it
- */
-
-static uint16_t
-move_map(uint16_t offset)
-{
-       int             l;
-
-       if (offset < chunk_low || chunk_high <= offset)
-               return offset;
-
-       l = find_chunk(offset);
-
-#if DBG_MEM
-       if (ao_lisp_chunk[l].old_offset != offset)
-               ao_lisp_abort();
-#endif
-       return ao_lisp_chunk[l].new_offset;
-}
-
-int
-ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref)
-{
-       void            *addr = *ref;
-       uint16_t        offset, orig_offset;
-
-       if (!AO_LISP_IS_POOL(addr))
-               return 1;
-
-       (void) type;
-
-       MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr));
-       orig_offset = pool_offset(addr);
-       offset = move_map(orig_offset);
-       if (offset != orig_offset) {
-               MDBG_MOVE("update ref %d %d -> %d\n",
-                         AO_LISP_IS_POOL(ref) ? MDBG_OFFSET(ref) : -1,
-                         orig_offset, offset);
-               *ref = ao_lisp_pool + offset;
-       }
-       if (busy(ao_lisp_busy, offset)) {
-               MDBG_MOVE("already moved\n");
-               return 1;
-       }
-       mark(ao_lisp_busy, offset);
-       MDBG_DO(ao_lisp_record(type, addr, ao_lisp_size(type, addr)));
-       return 0;
-}
-
-int
-ao_lisp_move(const struct ao_lisp_type *type, void **ref)
-{
-       int ret;
-       MDBG_MOVE("move object %d\n", MDBG_OFFSET(*ref));
-       MDBG_MOVE_IN();
-       ret = ao_lisp_move_memory(type, ref);
-       if (!ret) {
-               MDBG_MOVE("move recurse\n");
-               type->move(*ref);
-       }
-       MDBG_MOVE_OUT();
-       return ret;
-}
-
-int
-ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons)
-{
-       uint8_t         type;
-       ao_poly         p = *ref;
-       int             ret;
-       void            *addr;
-       uint16_t        offset, orig_offset;
-       uint8_t         base_type;
-
-       base_type = type = ao_lisp_poly_base_type(p);
-
-       if (type == AO_LISP_INT)
-               return 1;
-
-       addr = ao_lisp_ref(p);
-       if (!AO_LISP_IS_POOL(addr))
-               return 1;
-
-       orig_offset = pool_offset(addr);
-       offset = move_map(orig_offset);
-
-       if (type == AO_LISP_CONS && do_note_cons) {
-               note_cons(orig_offset);
-               ret = 1;
-       } else {
-               if (type == AO_LISP_OTHER)
-                       type = ao_lisp_other_type(ao_lisp_pool + offset);
-
-               const struct ao_lisp_type *lisp_type = ao_lisp_types[type];
-#if DBG_MEM
-               if (!lisp_type)
-                       ao_lisp_abort();
-#endif
-
-               ret = ao_lisp_move(lisp_type, &addr);
-       }
-
-       /* Re-write the poly value */
-       if (offset != orig_offset) {
-               ao_poly np = ao_lisp_poly(ao_lisp_pool + offset, base_type);
-               MDBG_MOVE("poly %d moved %d -> %d\n",
-                         type, orig_offset, offset);
-               *ref = np;
-       }
-       return ret;
-}
-
-#if DBG_MEM
-void
-ao_lisp_validate(void)
-{
-       chunk_low = 0;
-       memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk));
-       walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref);
-}
-
-int dbg_allocs;
-
-#endif
-
-void *
-ao_lisp_alloc(int size)
-{
-       void    *addr;
-
-       MDBG_DO(++dbg_allocs);
-       MDBG_DO(if (dbg_validate) ao_lisp_validate());
-       size = ao_lisp_size_round(size);
-       if (AO_LISP_POOL - ao_lisp_top < size &&
-           ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) < size &&
-           ao_lisp_collect(AO_LISP_COLLECT_FULL) < size)
-       {
-               ao_lisp_error(AO_LISP_OOM, "out of memory");
-               return NULL;
-       }
-       addr = ao_lisp_pool + ao_lisp_top;
-       ao_lisp_top += size;
-       return addr;
-}
-
-void
-ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons)
-{
-       save_cons[id] = cons;
-}
-
-struct ao_lisp_cons *
-ao_lisp_cons_fetch(int id)
-{
-       struct ao_lisp_cons *cons = save_cons[id];
-       save_cons[id] = NULL;
-       return cons;
-}
-
-void
-ao_lisp_poly_stash(int id, ao_poly poly)
-{
-       save_poly[id] = poly;
-}
-
-ao_poly
-ao_lisp_poly_fetch(int id)
-{
-       ao_poly poly = save_poly[id];
-       save_poly[id] = AO_LISP_NIL;
-       return poly;
-}
-
-void
-ao_lisp_string_stash(int id, char *string)
-{
-       save_string[id] = string;
-}
-
-char *
-ao_lisp_string_fetch(int id)
-{
-       char *string = save_string[id];
-       save_string[id] = NULL;
-       return string;
-}
-
diff --git a/src/lisp/ao_lisp_os.h b/src/lisp/ao_lisp_os.h
deleted file mode 100644 (file)
index 5fa3686..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright © 2016 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_LISP_OS_H_
-#define _AO_LISP_OS_H_
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-extern int ao_lisp_getc(void);
-
-static inline void
-ao_lisp_os_flush(void) {
-       fflush(stdout);
-}
-
-static inline void
-ao_lisp_abort(void)
-{
-       abort();
-}
-
-static inline void
-ao_lisp_os_led(int led)
-{
-       printf("leds set to 0x%x\n", led);
-}
-
-static inline void
-ao_lisp_os_delay(int delay)
-{
-       struct timespec ts = {
-               .tv_sec = delay / 1000,
-               .tv_nsec = (delay % 1000) * 1000000,
-       };
-       nanosleep(&ts, NULL);
-}
-#endif
diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c
deleted file mode 100644 (file)
index fb3b06f..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
-struct ao_lisp_funcs {
-       void (*print)(ao_poly);
-       void (*patom)(ao_poly);
-};
-
-static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = {
-       [AO_LISP_CONS] = {
-               .print = ao_lisp_cons_print,
-               .patom = ao_lisp_cons_patom,
-       },
-       [AO_LISP_STRING] = {
-               .print = ao_lisp_string_print,
-               .patom = ao_lisp_string_patom,
-       },
-       [AO_LISP_INT] = {
-               .print = ao_lisp_int_print,
-               .patom = ao_lisp_int_print,
-       },
-       [AO_LISP_ATOM] = {
-               .print = ao_lisp_atom_print,
-               .patom = ao_lisp_atom_print,
-       },
-       [AO_LISP_BUILTIN] = {
-               .print = ao_lisp_builtin_print,
-               .patom = ao_lisp_builtin_print,
-       },
-       [AO_LISP_FRAME] = {
-               .print = ao_lisp_frame_print,
-               .patom = ao_lisp_frame_print,
-       },
-       [AO_LISP_LAMBDA] = {
-               .print = ao_lisp_lambda_print,
-               .patom = ao_lisp_lambda_print,
-       },
-       [AO_LISP_STACK] = {
-               .print = ao_lisp_stack_print,
-               .patom = ao_lisp_stack_print,
-       },
-};
-
-static const struct ao_lisp_funcs *
-funcs(ao_poly p)
-{
-       uint8_t type = ao_lisp_poly_type(p);
-
-       if (type < AO_LISP_NUM_TYPE)
-               return &ao_lisp_funcs[type];
-       return NULL;
-}
-
-void
-ao_lisp_poly_print(ao_poly p)
-{
-       const struct ao_lisp_funcs *f = funcs(p);
-
-       if (f && f->print)
-               f->print(p);
-}
-
-void
-ao_lisp_poly_patom(ao_poly p)
-{
-       const struct ao_lisp_funcs *f = funcs(p);
-
-       if (f && f->patom)
-               f->patom(p);
-}
-
-void *
-ao_lisp_ref(ao_poly poly) {
-       if (poly == AO_LISP_NIL)
-               return NULL;
-       if (poly & AO_LISP_CONST)
-               return (void *) (ao_lisp_const + (poly & AO_LISP_REF_MASK) - 4);
-       return (void *) (ao_lisp_pool + (poly & AO_LISP_REF_MASK) - 4);
-}
-
-ao_poly
-ao_lisp_poly(const void *addr, ao_poly type) {
-       const uint8_t   *a = addr;
-       if (a == NULL)
-               return AO_LISP_NIL;
-       if (AO_LISP_IS_CONST(a))
-               return AO_LISP_CONST | (a - ao_lisp_const + 4) | type;
-       return (a - ao_lisp_pool + 4) | type;
-}
diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c
deleted file mode 100644 (file)
index 84ef2a6..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-#include "ao_lisp_read.h"
-
-static const uint16_t  lex_classes[128] = {
-       IGNORE,         /* ^@ */
-       IGNORE,         /* ^A */
-       IGNORE,         /* ^B */
-       IGNORE,         /* ^C */
-       IGNORE,         /* ^D */
-       IGNORE,         /* ^E */
-       IGNORE,         /* ^F */
-       IGNORE,         /* ^G */
-       IGNORE,         /* ^H */
-       WHITE,          /* ^I */
-       WHITE,          /* ^J */
-       WHITE,          /* ^K */
-       WHITE,          /* ^L */
-       WHITE,          /* ^M */
-       IGNORE,         /* ^N */
-       IGNORE,         /* ^O */
-       IGNORE,         /* ^P */
-       IGNORE,         /* ^Q */
-       IGNORE,         /* ^R */
-       IGNORE,         /* ^S */
-       IGNORE,         /* ^T */
-       IGNORE,         /* ^U */
-       IGNORE,         /* ^V */
-       IGNORE,         /* ^W */
-       IGNORE,         /* ^X */
-       IGNORE,         /* ^Y */
-       IGNORE,         /* ^Z */
-       IGNORE,         /* ^[ */
-       IGNORE,         /* ^\ */
-       IGNORE,         /* ^] */
-       IGNORE,         /* ^^ */
-       IGNORE,         /* ^_ */
-       PRINTABLE|WHITE,        /*    */
-       PRINTABLE,              /* ! */
-       PRINTABLE|STRINGC,      /* " */
-       PRINTABLE|COMMENT,      /* # */
-       PRINTABLE,              /* $ */
-       PRINTABLE,              /* % */
-       PRINTABLE,              /* & */
-       PRINTABLE|QUOTEC,       /* ' */
-       PRINTABLE|BRA,          /* ( */
-       PRINTABLE|KET,          /* ) */
-       PRINTABLE,              /* * */
-       PRINTABLE|SIGN,         /* + */
-       PRINTABLE,              /* , */
-       PRINTABLE|SIGN,         /* - */
-       PRINTABLE,              /* . */
-       PRINTABLE,              /* / */
-       PRINTABLE|DIGIT,        /* 0 */
-       PRINTABLE|DIGIT,        /* 1 */
-       PRINTABLE|DIGIT,        /* 2 */
-       PRINTABLE|DIGIT,        /* 3 */
-       PRINTABLE|DIGIT,        /* 4 */
-       PRINTABLE|DIGIT,        /* 5 */
-       PRINTABLE|DIGIT,        /* 6 */
-       PRINTABLE|DIGIT,        /* 7 */
-       PRINTABLE|DIGIT,        /* 8 */
-       PRINTABLE|DIGIT,        /* 9 */
-       PRINTABLE,              /* : */
-       PRINTABLE|COMMENT,      /* ; */
-       PRINTABLE,              /* < */
-       PRINTABLE,              /* = */
-       PRINTABLE,              /* > */
-       PRINTABLE,              /* ? */
-       PRINTABLE,              /*  @ */
-       PRINTABLE,              /*  A */
-       PRINTABLE,              /*  B */
-       PRINTABLE,              /*  C */
-       PRINTABLE,              /*  D */
-       PRINTABLE,              /*  E */
-       PRINTABLE,              /*  F */
-       PRINTABLE,              /*  G */
-       PRINTABLE,              /*  H */
-       PRINTABLE,              /*  I */
-       PRINTABLE,              /*  J */
-       PRINTABLE,              /*  K */
-       PRINTABLE,              /*  L */
-       PRINTABLE,              /*  M */
-       PRINTABLE,              /*  N */
-       PRINTABLE,              /*  O */
-       PRINTABLE,              /*  P */
-       PRINTABLE,              /*  Q */
-       PRINTABLE,              /*  R */
-       PRINTABLE,              /*  S */
-       PRINTABLE,              /*  T */
-       PRINTABLE,              /*  U */
-       PRINTABLE,              /*  V */
-       PRINTABLE,              /*  W */
-       PRINTABLE,              /*  X */
-       PRINTABLE,              /*  Y */
-       PRINTABLE,              /*  Z */
-       PRINTABLE,              /*  [ */
-       PRINTABLE|BACKSLASH,    /*  \ */
-       PRINTABLE,              /*  ] */
-       PRINTABLE,              /*  ^ */
-       PRINTABLE,              /*  _ */
-       PRINTABLE,              /*  ` */
-       PRINTABLE,              /*  a */
-       PRINTABLE,              /*  b */
-       PRINTABLE,              /*  c */
-       PRINTABLE,              /*  d */
-       PRINTABLE,              /*  e */
-       PRINTABLE,              /*  f */
-       PRINTABLE,              /*  g */
-       PRINTABLE,              /*  h */
-       PRINTABLE,              /*  i */
-       PRINTABLE,              /*  j */
-       PRINTABLE,              /*  k */
-       PRINTABLE,              /*  l */
-       PRINTABLE,              /*  m */
-       PRINTABLE,              /*  n */
-       PRINTABLE,              /*  o */
-       PRINTABLE,              /*  p */
-       PRINTABLE,              /*  q */
-       PRINTABLE,              /*  r */
-       PRINTABLE,              /*  s */
-       PRINTABLE,              /*  t */
-       PRINTABLE,              /*  u */
-       PRINTABLE,              /*  v */
-       PRINTABLE,              /*  w */
-       PRINTABLE,              /*  x */
-       PRINTABLE,              /*  y */
-       PRINTABLE,              /*  z */
-       PRINTABLE,              /*  { */
-       PRINTABLE|VBAR,         /*  | */
-       PRINTABLE,              /*  } */
-       PRINTABLE|TWIDDLE,      /*  ~ */
-       IGNORE,                 /*  ^? */
-};
-
-static int lex_unget_c;
-
-static inline int
-lex_get()
-{
-       int     c;
-       if (lex_unget_c) {
-               c = lex_unget_c;
-               lex_unget_c = 0;
-       } else {
-               c = ao_lisp_getc();
-       }
-       return c;
-}
-
-static inline void
-lex_unget(int c)
-{
-       if (c != EOF)
-               lex_unget_c = c;
-}
-
-static int
-lex_quoted (void)
-{
-       int     c;
-       int     v;
-       int     count;
-
-       c = lex_get();
-       if (c == EOF)
-               return EOF;
-       c &= 0x7f;
-       switch (c) {
-       case 'n':
-               return '\n';
-       case 'f':
-               return '\f';
-       case 'b':
-               return '\b';
-       case 'r':
-               return '\r';
-       case 'v':
-               return '\v';
-       case 't':
-               return '\t';
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-               v = c - '0';
-               count = 1;
-               while (count <= 3) {
-                       c = lex_get();
-                       if (c == EOF)
-                               return EOF;
-                       c &= 0x7f;
-                       if (c < '0' || '7' < c) {
-                               lex_unget(c);
-                               break;
-                       }
-                       v = (v << 3) + c - '0';
-                       ++count;
-               }
-               return v;
-       default:
-               return c;
-       }
-}
-
-static uint16_t        lex_class;
-
-static int
-lexc(void)
-{
-       int     c;
-       do {
-               c = lex_get();
-               if (c == EOF) {
-                       lex_class = ENDOFFILE;
-                       c = 0;
-               } else {
-                       c &= 0x7f;
-                       lex_class = lex_classes[c];
-                       if (lex_class & BACKSLASH) {
-                               c = lex_quoted();
-                               if (c == EOF)
-                                       lex_class = ENDOFFILE;
-                               else
-                                       lex_class = PRINTABLE;
-                       }
-               }
-       } while (lex_class & IGNORE);
-       return c;
-}
-
-#define AO_LISP_TOKEN_MAX      32
-
-static char    token_string[AO_LISP_TOKEN_MAX];
-static int     token_int;
-static int     token_len;
-
-static inline void add_token(int c) {
-       if (c && token_len < AO_LISP_TOKEN_MAX - 1)
-               token_string[token_len++] = c;
-}
-
-static inline void end_token(void) {
-       token_string[token_len] = '\0';
-}
-
-static int
-lex(void)
-{
-       int     c;
-
-       token_len = 0;
-       for (;;) {
-               c = lexc();
-               if (lex_class & ENDOFFILE)
-                       return END;
-
-               if (lex_class & WHITE)
-                       continue;
-
-               if (lex_class & COMMENT) {
-                       while ((c = lexc()) != '\n') {
-                               if (lex_class & ENDOFFILE)
-                                       return END;
-                       }
-                       continue;
-               }
-
-               if (lex_class & (BRA|KET|QUOTEC)) {
-                       add_token(c);
-                       end_token();
-                       switch (c) {
-                       case '(':
-                               return OPEN;
-                       case ')':
-                               return CLOSE;
-                       case '\'':
-                               return QUOTE;
-                       }
-               }
-               if (lex_class & TWIDDLE) {
-                       token_int = lexc();
-                       return NUM;
-               }
-               if (lex_class & STRINGC) {
-                       for (;;) {
-                               c = lexc();
-                               if (lex_class & (STRINGC|ENDOFFILE)) {
-                                       end_token();
-                                       return STRING;
-                               }
-                               add_token(c);
-                       }
-               }
-               if (lex_class & PRINTABLE) {
-                       int     isnum;
-                       int     hasdigit;
-                       int     isneg;
-
-                       isnum = 1;
-                       hasdigit = 0;
-                       token_int = 0;
-                       isneg = 0;
-                       for (;;) {
-                               if (!(lex_class & NUMBER)) {
-                                       isnum = 0;
-                               } else {
-                                       if (token_len != 0 &&
-                                           (lex_class & SIGN))
-                                       {
-                                               isnum = 0;
-                                       }
-                                       if (c == '-')
-                                               isneg = 1;
-                                       if (lex_class & DIGIT) {
-                                               hasdigit = 1;
-                                               if (isnum)
-                                                       token_int = token_int * 10 + c - '0';
-                                       }
-                               }
-                               add_token (c);
-                               c = lexc ();
-                               if (lex_class & (NOTNAME)) {
-//                                     if (lex_class & ENDOFFILE)
-//                                             clearerr (f);
-                                       lex_unget(c);
-                                       end_token ();
-                                       if (isnum && hasdigit) {
-                                               if (isneg)
-                                                       token_int = -token_int;
-                                               return NUM;
-                                       }
-                                       return NAME;
-                               }
-                       }
-
-               }
-       }
-}
-
-static int parse_token;
-
-struct ao_lisp_cons    *ao_lisp_read_cons;
-struct ao_lisp_cons    *ao_lisp_read_cons_tail;
-struct ao_lisp_cons    *ao_lisp_read_stack;
-
-static int
-push_read_stack(int cons, int in_quote)
-{
-       DBGI("push read stack %p %d\n", ao_lisp_read_cons, in_quote);
-       DBG_IN();
-       if (cons) {
-               ao_lisp_read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_read_cons),
-                                              ao_lisp_cons_cons(ao_lisp_int_poly(in_quote),
-                                                                ao_lisp_read_stack));
-               if (!ao_lisp_read_stack)
-                       return 0;
-       }
-       ao_lisp_read_cons = NULL;
-       ao_lisp_read_cons_tail = NULL;
-       return 1;
-}
-
-static int
-pop_read_stack(int cons)
-{
-       int     in_quote = 0;
-       if (cons) {
-               ao_lisp_read_cons = ao_lisp_poly_cons(ao_lisp_read_stack->car);
-               ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr);
-               in_quote = ao_lisp_poly_int(ao_lisp_read_stack->car);
-               ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr);
-               for (ao_lisp_read_cons_tail = ao_lisp_read_cons;
-                    ao_lisp_read_cons_tail && ao_lisp_read_cons_tail->cdr;
-                    ao_lisp_read_cons_tail = ao_lisp_poly_cons(ao_lisp_read_cons_tail->cdr))
-                       ;
-       } else {
-               ao_lisp_read_cons = 0;
-               ao_lisp_read_cons_tail = 0;
-               ao_lisp_read_stack = 0;
-       }
-       DBG_OUT();
-       DBGI("pop read stack %p %d\n", ao_lisp_read_cons, in_quote);
-       return in_quote;
-}
-
-ao_poly
-ao_lisp_read(void)
-{
-       struct ao_lisp_atom     *atom;
-       char                    *string;
-       int                     cons;
-       int                     in_quote;
-       ao_poly                 v;
-
-       parse_token = lex();
-       DBGI("token %d (%s)\n", parse_token, token_string);
-
-       cons = 0;
-       in_quote = 0;
-       ao_lisp_read_cons = ao_lisp_read_cons_tail = ao_lisp_read_stack = 0;
-       for (;;) {
-               while (parse_token == OPEN) {
-                       if (!push_read_stack(cons, in_quote))
-                               return AO_LISP_NIL;
-                       cons++;
-                       in_quote = 0;
-                       parse_token = lex();
-                       DBGI("token %d (%s)\n", parse_token, token_string);
-               }
-
-               switch (parse_token) {
-               case END:
-               default:
-                       if (cons)
-                               ao_lisp_error(AO_LISP_EOF, "unexpected end of file");
-                       return _ao_lisp_atom_eof;
-                       break;
-               case NAME:
-                       atom = ao_lisp_atom_intern(token_string);
-                       if (atom)
-                               v = ao_lisp_atom_poly(atom);
-                       else
-                               v = AO_LISP_NIL;
-                       break;
-               case NUM:
-                       v = ao_lisp_int_poly(token_int);
-                       break;
-               case STRING:
-                       string = ao_lisp_string_copy(token_string);
-                       if (string)
-                               v = ao_lisp_string_poly(string);
-                       else
-                               v = AO_LISP_NIL;
-                       break;
-               case QUOTE:
-                       if (!push_read_stack(cons, in_quote))
-                               return AO_LISP_NIL;
-                       cons++;
-                       in_quote = 1;
-                       v = _ao_lisp_atom_quote;
-                       break;
-               case CLOSE:
-                       if (!cons) {
-                               v = AO_LISP_NIL;
-                               break;
-                       }
-                       v = ao_lisp_cons_poly(ao_lisp_read_cons);
-                       --cons;
-                       in_quote = pop_read_stack(cons);
-                       break;
-               }
-
-               /* loop over QUOTE ends */
-               for (;;) {
-                       if (!cons)
-                               return v;
-
-                       struct ao_lisp_cons     *read = ao_lisp_cons_cons(v, NULL);
-                       if (!read)
-                               return AO_LISP_NIL;
-
-                       if (ao_lisp_read_cons_tail)
-                               ao_lisp_read_cons_tail->cdr = ao_lisp_cons_poly(read);
-                       else
-                               ao_lisp_read_cons = read;
-                       ao_lisp_read_cons_tail = read;
-
-                       if (!in_quote || !ao_lisp_read_cons->cdr)
-                               break;
-
-                       v = ao_lisp_cons_poly(ao_lisp_read_cons);
-                       --cons;
-                       in_quote = pop_read_stack(cons);
-               }
-
-               parse_token = lex();
-               DBGI("token %d (%s)\n", parse_token, token_string);
-       }
-       return v;
-}
diff --git a/src/lisp/ao_lisp_read.h b/src/lisp/ao_lisp_read.h
deleted file mode 100644 (file)
index 1c994d5..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _AO_LISP_READ_H_
-#define _AO_LISP_READ_H_
-
-# define END   0
-# define NAME  1
-# define OPEN          2
-# define CLOSE 3
-# define QUOTE 4
-# define STRING        5
-# define NUM   6
-
-/*
- * character classes
- */
-
-# define PRINTABLE     0x00000001      /* \t \n ' ' - '~' */
-# define QUOTED                0x00000002      /* \ anything */
-# define BRA           0x00000004      /* ( [ { */
-# define KET           0x00000008      /* ) ] } */
-# define WHITE         0x00000010      /* ' ' \t \n */
-# define DIGIT         0x00000020      /* [0-9] */
-# define SIGN          0x00000040      /* +- */
-# define ENDOFFILE     0x00000080      /* end of file */
-# define COMMENT       0x00000100      /* ; # */
-# define IGNORE                0x00000200      /* \0 - ' ' */
-# define QUOTEC                0x00000400      /* ' */
-# define BACKSLASH     0x00000800      /* \ */
-# define VBAR          0x00001000      /* | */
-# define TWIDDLE       0x00002000      /* ~ */
-# define STRINGC       0x00004000      /* " */
-
-# define NOTNAME       (STRINGC|TWIDDLE|VBAR|QUOTEC|COMMENT|ENDOFFILE|WHITE|KET|BRA)
-# define NUMBER                (DIGIT|SIGN)
-
-#endif /* _AO_LISP_READ_H_ */
diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c
deleted file mode 100644 (file)
index 3be95d4..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
-ao_poly
-ao_lisp_read_eval_print(void)
-{
-       ao_poly in, out = AO_LISP_NIL;
-       for(;;) {
-               in = ao_lisp_read();
-               if (in == _ao_lisp_atom_eof || in == AO_LISP_NIL)
-                       break;
-               out = ao_lisp_eval(in);
-               if (ao_lisp_exception) {
-                       ao_lisp_exception = 0;
-               } else {
-                       ao_lisp_poly_print(out);
-                       putchar ('\n');
-               }
-       }
-       return out;
-}
diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c
deleted file mode 100644 (file)
index 4f850fb..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.
- */
-
-#include <ao_lisp.h>
-
-ao_poly
-ao_lisp_save(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_save, cons, 0, 0))
-               return AO_LISP_NIL;
-
-#ifdef AO_LISP_SAVE
-       struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) (void *) &ao_lisp_pool[AO_LISP_POOL];
-
-       ao_lisp_collect(AO_LISP_COLLECT_FULL);
-       os->atoms = ao_lisp_atom_poly(ao_lisp_atoms);
-       os->globals = ao_lisp_frame_poly(ao_lisp_frame_global);
-       os->const_checksum = ao_lisp_const_checksum;
-       os->const_checksum_inv = (uint16_t) ~ao_lisp_const_checksum;
-
-       if (ao_lisp_os_save())
-               return _ao_lisp_atom_t;
-#endif
-       return AO_LISP_NIL;
-}
-
-ao_poly
-ao_lisp_restore(struct ao_lisp_cons *cons)
-{
-       if (!ao_lisp_check_argc(_ao_lisp_atom_save, cons, 0, 0))
-               return AO_LISP_NIL;
-
-#ifdef AO_LISP_SAVE
-       struct ao_lisp_os_save save;
-       struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) (void *) &ao_lisp_pool[AO_LISP_POOL];
-
-       if (!ao_lisp_os_restore_save(&save, AO_LISP_POOL))
-               return ao_lisp_error(AO_LISP_INVALID, "header restore failed");
-
-       if (save.const_checksum != ao_lisp_const_checksum ||
-           save.const_checksum_inv != (uint16_t) ~ao_lisp_const_checksum)
-       {
-               return ao_lisp_error(AO_LISP_INVALID, "image is corrupted or stale");
-       }
-
-       if (ao_lisp_os_restore()) {
-
-               ao_lisp_atoms = ao_lisp_poly_atom(os->atoms);
-               ao_lisp_frame_global = ao_lisp_poly_frame(os->globals);
-
-               /* Clear the eval global variabls */
-               ao_lisp_eval_clear_globals();
-
-               /* Reset the allocator */
-               ao_lisp_top = AO_LISP_POOL;
-               ao_lisp_collect(AO_LISP_COLLECT_FULL);
-
-               /* Re-create the evaluator stack */
-               if (!ao_lisp_eval_restart())
-                       return AO_LISP_NIL;
-               return _ao_lisp_atom_t;
-       }
-#endif
-       return AO_LISP_NIL;
-}
diff --git a/src/lisp/ao_lisp_stack.c b/src/lisp/ao_lisp_stack.c
deleted file mode 100644 (file)
index 53adf43..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-
-const struct ao_lisp_type ao_lisp_stack_type;
-
-static int
-stack_size(void *addr)
-{
-       (void) addr;
-       return sizeof (struct ao_lisp_stack);
-}
-
-static void
-stack_mark(void *addr)
-{
-       struct ao_lisp_stack    *stack = addr;
-       for (;;) {
-               ao_lisp_poly_mark(stack->sexprs, 0);
-               ao_lisp_poly_mark(stack->values, 0);
-               /* no need to mark values_tail */
-               ao_lisp_poly_mark(stack->frame, 0);
-               ao_lisp_poly_mark(stack->list, 0);
-               stack = ao_lisp_poly_stack(stack->prev);
-               if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack))
-                       break;
-       }
-}
-
-static void
-stack_move(void *addr)
-{
-       struct ao_lisp_stack    *stack = addr;
-
-       while (stack) {
-               struct ao_lisp_stack    *prev;
-               int                     ret;
-               (void) ao_lisp_poly_move(&stack->sexprs, 0);
-               (void) ao_lisp_poly_move(&stack->values, 0);
-               (void) ao_lisp_poly_move(&stack->values_tail, 0);
-               (void) ao_lisp_poly_move(&stack->frame, 0);
-               (void) ao_lisp_poly_move(&stack->list, 0);
-               prev = ao_lisp_poly_stack(stack->prev);
-               if (!prev)
-                       break;
-               ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev);
-               if (prev != ao_lisp_poly_stack(stack->prev))
-                       stack->prev = ao_lisp_stack_poly(prev);
-               if (ret)
-                       break;
-               stack = prev;
-       }
-}
-
-const struct ao_lisp_type ao_lisp_stack_type = {
-       .size = stack_size,
-       .mark = stack_mark,
-       .move = stack_move,
-       .name = "stack"
-};
-
-struct ao_lisp_stack           *ao_lisp_stack_free_list;
-
-void
-ao_lisp_stack_reset(struct ao_lisp_stack *stack)
-{
-       stack->state = eval_sexpr;
-       stack->sexprs = AO_LISP_NIL;
-       stack->values = AO_LISP_NIL;
-       stack->values_tail = AO_LISP_NIL;
-}
-
-static struct ao_lisp_stack *
-ao_lisp_stack_new(void)
-{
-       struct ao_lisp_stack *stack;
-
-       if (ao_lisp_stack_free_list) {
-               stack = ao_lisp_stack_free_list;
-               ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev);
-       } else {
-               stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack));
-               if (!stack)
-                       return 0;
-               stack->type = AO_LISP_STACK;
-       }
-       ao_lisp_stack_reset(stack);
-       return stack;
-}
-
-int
-ao_lisp_stack_push(void)
-{
-       struct ao_lisp_stack    *stack = ao_lisp_stack_new();
-
-       if (!stack)
-               return 0;
-
-       stack->prev = ao_lisp_stack_poly(ao_lisp_stack);
-       stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current);
-       stack->list = AO_LISP_NIL;
-
-       ao_lisp_stack = stack;
-
-       DBGI("stack push\n");
-       DBG_FRAMES();
-       DBG_IN();
-       return 1;
-}
-
-void
-ao_lisp_stack_pop(void)
-{
-       ao_poly                 prev;
-       struct ao_lisp_frame    *prev_frame;
-
-       if (!ao_lisp_stack)
-               return;
-       prev = ao_lisp_stack->prev;
-       if (!ao_lisp_stack_marked(ao_lisp_stack)) {
-               ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list);
-               ao_lisp_stack_free_list = ao_lisp_stack;
-       }
-
-       ao_lisp_stack = ao_lisp_poly_stack(prev);
-       prev_frame = ao_lisp_frame_current;
-       if (ao_lisp_stack)
-               ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
-       else
-               ao_lisp_frame_current = NULL;
-       if (ao_lisp_frame_current != prev_frame)
-               ao_lisp_frame_free(prev_frame);
-       DBG_OUT();
-       DBGI("stack pop\n");
-       DBG_FRAMES();
-}
-
-void
-ao_lisp_stack_clear(void)
-{
-       ao_lisp_stack = NULL;
-       ao_lisp_frame_current = NULL;
-       ao_lisp_v = AO_LISP_NIL;
-}
-
-void
-ao_lisp_stack_print(ao_poly poly)
-{
-       struct ao_lisp_stack *s = ao_lisp_poly_stack(poly);
-
-       while (s) {
-               if (s->type & AO_LISP_STACK_PRINT) {
-                       printf("[recurse...]");
-                       return;
-               }
-               s->type |= AO_LISP_STACK_PRINT;
-               printf("\t[\n");
-               printf("\t\texpr:   "); ao_lisp_poly_print(s->list); printf("\n");
-               printf("\t\tstate:  %s\n", ao_lisp_state_names[s->state]);
-               ao_lisp_error_poly ("values: ", s->values, s->values_tail);
-               ao_lisp_error_poly ("sexprs: ", s->sexprs, AO_LISP_NIL);
-               ao_lisp_error_frame(2, "frame:  ", ao_lisp_poly_frame(s->frame));
-               printf("\t]\n");
-               s->type &= ~AO_LISP_STACK_PRINT;
-               s = ao_lisp_poly_stack(s->prev);
-       }
-}
-
-/*
- * Copy a stack, being careful to keep everybody referenced
- */
-static struct ao_lisp_stack *
-ao_lisp_stack_copy(struct ao_lisp_stack *old)
-{
-       struct ao_lisp_stack *new = NULL;
-       struct ao_lisp_stack *n, *prev = NULL;
-
-       while (old) {
-               ao_lisp_stack_stash(0, old);
-               ao_lisp_stack_stash(1, new);
-               ao_lisp_stack_stash(2, prev);
-               n = ao_lisp_stack_new();
-               prev = ao_lisp_stack_fetch(2);
-               new = ao_lisp_stack_fetch(1);
-               old = ao_lisp_stack_fetch(0);
-               if (!n)
-                       return NULL;
-
-               ao_lisp_stack_mark(old);
-               ao_lisp_frame_mark(ao_lisp_poly_frame(old->frame));
-               *n = *old;
-
-               if (prev)
-                       prev->prev = ao_lisp_stack_poly(n);
-               else
-                       new = n;
-               prev = n;
-
-               old = ao_lisp_poly_stack(old->prev);
-       }
-       return new;
-}
-
-/*
- * Evaluate a continuation invocation
- */
-ao_poly
-ao_lisp_stack_eval(void)
-{
-       struct ao_lisp_stack    *new = ao_lisp_stack_copy(ao_lisp_poly_stack(ao_lisp_v));
-       if (!new)
-               return AO_LISP_NIL;
-
-       struct ao_lisp_cons     *cons = ao_lisp_poly_cons(ao_lisp_stack->values);
-
-       if (!cons || !cons->cdr)
-               return ao_lisp_error(AO_LISP_INVALID, "continuation requires a value");
-
-       new->state = eval_val;
-
-       ao_lisp_stack = new;
-       ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
-
-       return ao_lisp_poly_cons(cons->cdr)->car;
-}
-
-/*
- * Call with current continuation. This calls a lambda, passing
- * it a single argument which is the current continuation
- */
-ao_poly
-ao_lisp_call_cc(struct ao_lisp_cons *cons)
-{
-       struct ao_lisp_stack    *new;
-       ao_poly                 v;
-
-       /* Make sure the single parameter is a lambda */
-       if (!ao_lisp_check_argc(_ao_lisp_atom_call2fcc, cons, 1, 1))
-               return AO_LISP_NIL;
-       if (!ao_lisp_check_argt(_ao_lisp_atom_call2fcc, cons, 0, AO_LISP_LAMBDA, 0))
-               return AO_LISP_NIL;
-
-       /* go get the lambda */
-       ao_lisp_v = ao_lisp_arg(cons, 0);
-
-       /* Note that the whole call chain now has
-        * a reference to it which may escape
-        */
-       new = ao_lisp_stack_copy(ao_lisp_stack);
-       if (!new)
-               return AO_LISP_NIL;
-
-       /* re-fetch cons after the allocation */
-       cons = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr);
-
-       /* Reset the arg list to the current stack,
-        * and call the lambda
-        */
-
-       cons->car = ao_lisp_stack_poly(new);
-       cons->cdr = AO_LISP_NIL;
-       v = ao_lisp_lambda_eval();
-       ao_lisp_stack->sexprs = v;
-       ao_lisp_stack->state = eval_progn;
-       return AO_LISP_NIL;
-}
diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c
deleted file mode 100644 (file)
index cd7b27a..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright © 2016 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include "ao_lisp.h"
-
-static void string_mark(void *addr)
-{
-       (void) addr;
-}
-
-static int string_size(void *addr)
-{
-       if (!addr)
-               return 0;
-       return strlen(addr) + 1;
-}
-
-static void string_move(void *addr)
-{
-       (void) addr;
-}
-
-const struct ao_lisp_type ao_lisp_string_type = {
-       .mark = string_mark,
-       .size = string_size,
-       .move = string_move,
-       .name = "string",
-};
-
-char *
-ao_lisp_string_copy(char *a)
-{
-       int     alen = strlen(a);
-
-       ao_lisp_string_stash(0, a);
-       char    *r = ao_lisp_alloc(alen + 1);
-       a = ao_lisp_string_fetch(0);
-       if (!r)
-               return NULL;
-       strcpy(r, a);
-       return r;
-}
-
-char *
-ao_lisp_string_cat(char *a, char *b)
-{
-       int     alen = strlen(a);
-       int     blen = strlen(b);
-
-       ao_lisp_string_stash(0, a);
-       ao_lisp_string_stash(1, b);
-       char    *r = ao_lisp_alloc(alen + blen + 1);
-       a = ao_lisp_string_fetch(0);
-       b = ao_lisp_string_fetch(1);
-       if (!r)
-               return NULL;
-       strcpy(r, a);
-       strcpy(r+alen, b);
-       return r;
-}
-
-ao_poly
-ao_lisp_string_pack(struct ao_lisp_cons *cons)
-{
-       int     len = ao_lisp_cons_length(cons);
-       ao_lisp_cons_stash(0, cons);
-       char    *r = ao_lisp_alloc(len + 1);
-       cons = ao_lisp_cons_fetch(0);
-       char    *s = r;
-
-       while (cons) {
-               if (ao_lisp_poly_type(cons->car) != AO_LISP_INT)
-                       return ao_lisp_error(AO_LISP_INVALID, "non-int passed to pack");
-               *s++ = ao_lisp_poly_int(cons->car);
-               cons = ao_lisp_poly_cons(cons->cdr);
-       }
-       *s++ = 0;
-       return ao_lisp_string_poly(r);
-}
-
-ao_poly
-ao_lisp_string_unpack(char *a)
-{
-       struct ao_lisp_cons     *cons = NULL, *tail = NULL;
-       int                     c;
-       int                     i;
-
-       for (i = 0; (c = a[i]); i++) {
-               ao_lisp_cons_stash(0, cons);
-               ao_lisp_cons_stash(1, tail);
-               ao_lisp_string_stash(0, a);
-               struct ao_lisp_cons     *n = ao_lisp_cons_cons(ao_lisp_int_poly(c), NULL);
-               a = ao_lisp_string_fetch(0);
-               cons = ao_lisp_cons_fetch(0);
-               tail = ao_lisp_cons_fetch(1);
-
-               if (!n) {
-                       cons = NULL;
-                       break;
-               }
-               if (tail)
-                       tail->cdr = ao_lisp_cons_poly(n);
-               else
-                       cons = n;
-               tail = n;
-       }
-       return ao_lisp_cons_poly(cons);
-}
-
-void
-ao_lisp_string_print(ao_poly p)
-{
-       char    *s = ao_lisp_poly_string(p);
-       char    c;
-
-       putchar('"');
-       while ((c = *s++)) {
-               switch (c) {
-               case '\n':
-                       printf ("\\n");
-                       break;
-               case '\r':
-                       printf ("\\r");
-                       break;
-               case '\t':
-                       printf ("\\t");
-                       break;
-               default:
-                       putchar(c);
-                       break;
-               }
-       }
-       putchar('"');
-}
-
-void
-ao_lisp_string_patom(ao_poly p)
-{
-       char    *s = ao_lisp_poly_string(p);
-       char    c;
-
-       while ((c = *s++))
-               putchar(c);
-}
index 261c48129651743ca5b823f7f58deb7922d733f9..1573ca9f629dac4c68e22de930b2d712b5b8e16a 100644 (file)
@@ -77,7 +77,8 @@ twon8  =  3.9062500000e-03; /* 0x3b800000 */
 
     /* compute q[0],q[1],...q[jk] */
        for (i=0;i<=jk;i++) {
-           for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+           for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+           q[i] = fw;
        }
 
        jz = jk;
index 4c0a9a53569ada72f1449517297d116af32534aa..2f46ec32744b0aa664a32010a9301236a67b72b4 100644 (file)
 
 #include "fdlibm.h"
 
-#ifdef __STDC__
-static const float one=1.0;
-#else
-static float one=1.0;
-#endif
-
 #ifdef __STDC__
        float cosf(float x)
 #else
diff --git a/src/scheme/.gitignore b/src/scheme/.gitignore
new file mode 100644 (file)
index 0000000..ee72cb9
--- /dev/null
@@ -0,0 +1,2 @@
+ao_scheme_const.h
+ao_scheme_builtin.h
diff --git a/src/scheme/Makefile b/src/scheme/Makefile
new file mode 100644 (file)
index 0000000..dc36dde
--- /dev/null
@@ -0,0 +1,20 @@
+all: ao_scheme_builtin.h ao_scheme_const.h test/ao_scheme_test
+
+clean:
+       +cd make-const && make clean
+       +cd test && make clean
+       rm -f ao_scheme_const.h ao_scheme_builtin.h
+
+ao_scheme_const.h: ao_scheme_const.scheme make-const/ao_scheme_make_const
+       make-const/ao_scheme_make_const -o $@ ao_scheme_const.scheme
+
+ao_scheme_builtin.h: ao_scheme_make_builtin ao_scheme_builtin.txt
+       nickle ao_scheme_make_builtin ao_scheme_builtin.txt > $@
+
+make-const/ao_scheme_make_const: FRC ao_scheme_builtin.h
+       +cd make-const && make ao_scheme_make_const
+
+test/ao_scheme_test: FRC ao_scheme_const.h ao_scheme_builtin.h
+       +cd test && make ao_scheme_test
+
+FRC:
diff --git a/src/scheme/Makefile-inc b/src/scheme/Makefile-inc
new file mode 100644 (file)
index 0000000..1a080a4
--- /dev/null
@@ -0,0 +1,25 @@
+SCHEME_SRCS=\
+       ao_scheme_mem.c \
+       ao_scheme_cons.c \
+       ao_scheme_string.c \
+       ao_scheme_atom.c \
+       ao_scheme_int.c \
+       ao_scheme_poly.c \
+       ao_scheme_bool.c \
+       ao_scheme_float.c \
+       ao_scheme_builtin.c \
+       ao_scheme_read.c \
+       ao_scheme_frame.c \
+       ao_scheme_lambda.c \
+       ao_scheme_eval.c \
+       ao_scheme_rep.c \
+       ao_scheme_save.c \
+       ao_scheme_stack.c \
+       ao_scheme_error.c \
+       ao_scheme_vector.c
+
+SCHEME_HDRS=\
+       ao_scheme.h \
+       ao_scheme_os.h \
+       ao_scheme_read.h \
+       ao_scheme_builtin.h
diff --git a/src/scheme/Makefile-scheme b/src/scheme/Makefile-scheme
new file mode 100644 (file)
index 0000000..b9018e1
--- /dev/null
@@ -0,0 +1,4 @@
+include ../scheme/Makefile-inc
+
+ao_scheme_const.h: $(SCHEME_SRCS) $(SCHEME_HDRS)
+       +cd ../scheme && make $@
diff --git a/src/scheme/README b/src/scheme/README
new file mode 100644 (file)
index 0000000..a18457f
--- /dev/null
@@ -0,0 +1,10 @@
+This follows the R7RS with the following known exceptions:
+
+* No vectors or bytevectors
+* Characters are just numbers
+* No dynamic-wind or exceptions
+* No environments
+* No ports
+* No syntax-rules
+* No record types
+* No libraries
diff --git a/src/scheme/ao_scheme.h b/src/scheme/ao_scheme.h
new file mode 100644 (file)
index 0000000..2fa1ed6
--- /dev/null
@@ -0,0 +1,981 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_SCHEME_H_
+#define _AO_SCHEME_H_
+
+#define DBG_MEM                0
+#define DBG_EVAL       0
+#define DBG_READ       0
+#define DBG_FREE_CONS  0
+#define NDEBUG         1
+
+#include <stdint.h>
+#include <string.h>
+#include <ao_scheme_os.h>
+#ifndef __BYTE_ORDER
+#include <endian.h>
+#endif
+
+typedef uint16_t       ao_poly;
+typedef int16_t                ao_signed_poly;
+
+#if AO_SCHEME_SAVE
+
+struct ao_scheme_os_save {
+       ao_poly         atoms;
+       ao_poly         globals;
+       uint16_t        const_checksum;
+       uint16_t        const_checksum_inv;
+};
+
+#define AO_SCHEME_POOL_EXTRA   (sizeof(struct ao_scheme_os_save))
+#define AO_SCHEME_POOL ((int) (AO_SCHEME_POOL_TOTAL - AO_SCHEME_POOL_EXTRA))
+
+int
+ao_scheme_os_save(void);
+
+int
+ao_scheme_os_restore_save(struct ao_scheme_os_save *save, int offset);
+
+int
+ao_scheme_os_restore(void);
+
+#endif
+
+#ifdef AO_SCHEME_MAKE_CONST
+#define AO_SCHEME_POOL_CONST   16384
+extern uint8_t ao_scheme_const[AO_SCHEME_POOL_CONST] __attribute__((aligned(4)));
+#define ao_scheme_pool ao_scheme_const
+#define AO_SCHEME_POOL AO_SCHEME_POOL_CONST
+
+#define _atom(n) ao_scheme_atom_poly(ao_scheme_atom_intern(n))
+#define _bool(v) ao_scheme_bool_poly(ao_scheme_bool_get(v))
+
+#define _ao_scheme_bool_true   _bool(1)
+#define _ao_scheme_bool_false  _bool(0)
+
+#define _ao_scheme_atom_eof    _atom("eof")
+#define _ao_scheme_atom_else   _atom("else")
+
+#define AO_SCHEME_BUILTIN_ATOMS
+#include "ao_scheme_builtin.h"
+
+#else
+#include "ao_scheme_const.h"
+#ifndef AO_SCHEME_POOL
+#define AO_SCHEME_POOL 3072
+#endif
+#ifndef AO_SCHEME_POOL_EXTRA
+#define AO_SCHEME_POOL_EXTRA 0
+#endif
+extern uint8_t         ao_scheme_pool[AO_SCHEME_POOL + AO_SCHEME_POOL_EXTRA] __attribute__((aligned(4)));
+#endif
+
+/* Primitive types */
+#define AO_SCHEME_CONS         0
+#define AO_SCHEME_INT          1
+#define AO_SCHEME_STRING       2
+#define AO_SCHEME_OTHER                3
+
+#define AO_SCHEME_TYPE_MASK    0x0003
+#define AO_SCHEME_TYPE_SHIFT   2
+#define AO_SCHEME_REF_MASK     0x7ffc
+#define AO_SCHEME_CONST                0x8000
+
+/* These have a type value at the start of the struct */
+#define AO_SCHEME_ATOM         4
+#define AO_SCHEME_BUILTIN      5
+#define AO_SCHEME_FRAME                6
+#define AO_SCHEME_FRAME_VALS   7
+#define AO_SCHEME_LAMBDA       8
+#define AO_SCHEME_STACK                9
+#define AO_SCHEME_BOOL         10
+#define AO_SCHEME_BIGINT       11
+#define AO_SCHEME_FLOAT                12
+#define AO_SCHEME_VECTOR       13
+#define AO_SCHEME_NUM_TYPE     14
+
+/* Leave two bits for types to use as they please */
+#define AO_SCHEME_OTHER_TYPE_MASK      0x3f
+
+#define AO_SCHEME_NIL  0
+
+extern uint16_t                ao_scheme_top;
+
+#define AO_SCHEME_OOM                  0x01
+#define AO_SCHEME_DIVIDE_BY_ZERO       0x02
+#define AO_SCHEME_INVALID              0x04
+#define AO_SCHEME_UNDEFINED            0x08
+#define AO_SCHEME_REDEFINED            0x10
+#define AO_SCHEME_EOF                  0x20
+#define AO_SCHEME_EXIT                 0x40
+
+extern uint8_t         ao_scheme_exception;
+
+static inline int
+ao_scheme_is_const(ao_poly poly) {
+       return poly & AO_SCHEME_CONST;
+}
+
+#define AO_SCHEME_IS_CONST(a)  (ao_scheme_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_scheme_const + AO_SCHEME_POOL_CONST)
+#define AO_SCHEME_IS_POOL(a)   (ao_scheme_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_scheme_pool + AO_SCHEME_POOL)
+#define AO_SCHEME_IS_INT(p)    (ao_scheme_poly_base_type(p) == AO_SCHEME_INT)
+
+void *
+ao_scheme_ref(ao_poly poly);
+
+ao_poly
+ao_scheme_poly(const void *addr, ao_poly type);
+
+struct ao_scheme_type {
+       int     (*size)(void *addr);
+       void    (*mark)(void *addr);
+       void    (*move)(void *addr);
+       char    name[];
+};
+
+struct ao_scheme_cons {
+       ao_poly         car;
+       ao_poly         cdr;
+};
+
+struct ao_scheme_atom {
+       uint8_t         type;
+       uint8_t         pad[1];
+       ao_poly         next;
+       char            name[];
+};
+
+struct ao_scheme_val {
+       ao_poly         atom;
+       ao_poly         val;
+};
+
+struct ao_scheme_frame_vals {
+       uint8_t                 type;
+       uint8_t                 size;
+       struct ao_scheme_val    vals[];
+};
+
+struct ao_scheme_frame {
+       uint8_t                 type;
+       uint8_t                 num;
+       ao_poly                 prev;
+       ao_poly                 vals;
+};
+
+struct ao_scheme_bool {
+       uint8_t                 type;
+       uint8_t                 value;
+       uint16_t                pad;
+};
+
+struct ao_scheme_bigint {
+       uint32_t                value;
+};
+
+struct ao_scheme_float {
+       uint8_t                 type;
+       uint8_t                 pad1;
+       uint16_t                pad2;
+       float                   value;
+};
+
+struct ao_scheme_vector {
+       uint8_t                 type;
+       uint8_t                 pad1;
+       uint16_t                length;
+       ao_poly                 vals[];
+};
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline uint32_t
+ao_scheme_int_bigint(int32_t i) {
+       return AO_SCHEME_BIGINT | (i << 8);
+}
+static inline int32_t
+ao_scheme_bigint_int(uint32_t bi) {
+       return (int32_t) bi >> 8;
+}
+#else
+static inline uint32_t
+ao_scheme_int_bigint(int32_t i) {
+       return (uint32_t) (i & 0xffffff) | (AO_SCHEME_BIGINT << 24);
+}
+static inlint int32_t
+ao_scheme_bigint_int(uint32_t bi) {
+       return (int32_t) (bi << 8) >> 8;
+}
+#endif
+
+#define AO_SCHEME_MIN_INT      (-(1 << (15 - AO_SCHEME_TYPE_SHIFT)))
+#define AO_SCHEME_MAX_INT      ((1 << (15 - AO_SCHEME_TYPE_SHIFT)) - 1)
+#define AO_SCHEME_MIN_BIGINT   (-(1 << 24))
+#define AO_SCHEME_MAX_BIGINT   ((1 << 24) - 1)
+
+#define AO_SCHEME_NOT_INTEGER  0x7fffffff
+
+/* Set on type when the frame escapes the lambda */
+#define AO_SCHEME_FRAME_MARK   0x80
+#define AO_SCHEME_FRAME_PRINT  0x40
+
+static inline int ao_scheme_frame_marked(struct ao_scheme_frame *f) {
+       return f->type & AO_SCHEME_FRAME_MARK;
+}
+
+static inline struct ao_scheme_frame *
+ao_scheme_poly_frame(ao_poly poly) {
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_frame_poly(struct ao_scheme_frame *frame) {
+       return ao_scheme_poly(frame, AO_SCHEME_OTHER);
+}
+
+static inline struct ao_scheme_frame_vals *
+ao_scheme_poly_frame_vals(ao_poly poly) {
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_frame_vals_poly(struct ao_scheme_frame_vals *vals) {
+       return ao_scheme_poly(vals, AO_SCHEME_OTHER);
+}
+
+enum eval_state {
+       eval_sexpr,             /* Evaluate an sexpr */
+       eval_val,               /* Value computed */
+       eval_formal,            /* Formal computed */
+       eval_exec,              /* Start a lambda evaluation */
+       eval_apply,             /* Execute apply */
+       eval_cond,              /* Start next cond clause */
+       eval_cond_test,         /* Check cond condition */
+       eval_begin,             /* Start next begin entry */
+       eval_while,             /* Start while condition */
+       eval_while_test,        /* Check while condition */
+       eval_macro,             /* Finished with macro generation */
+};
+
+struct ao_scheme_stack {
+       uint8_t                 type;           /* AO_SCHEME_STACK */
+       uint8_t                 state;          /* enum eval_state */
+       ao_poly                 prev;           /* previous stack frame */
+       ao_poly                 sexprs;         /* expressions to evaluate */
+       ao_poly                 values;         /* values computed */
+       ao_poly                 values_tail;    /* end of the values list for easy appending */
+       ao_poly                 frame;          /* current lookup frame */
+       ao_poly                 list;           /* most recent function call */
+};
+
+#define AO_SCHEME_STACK_MARK   0x80    /* set on type when a reference has been taken */
+#define AO_SCHEME_STACK_PRINT  0x40    /* stack is being printed */
+
+static inline int ao_scheme_stack_marked(struct ao_scheme_stack *s) {
+       return s->type & AO_SCHEME_STACK_MARK;
+}
+
+static inline void ao_scheme_stack_mark(struct ao_scheme_stack *s) {
+       s->type |= AO_SCHEME_STACK_MARK;
+}
+
+static inline struct ao_scheme_stack *
+ao_scheme_poly_stack(ao_poly p)
+{
+       return ao_scheme_ref(p);
+}
+
+static inline ao_poly
+ao_scheme_stack_poly(struct ao_scheme_stack *stack)
+{
+       return ao_scheme_poly(stack, AO_SCHEME_OTHER);
+}
+
+extern ao_poly                 ao_scheme_v;
+
+#define AO_SCHEME_FUNC_LAMBDA          0
+#define AO_SCHEME_FUNC_NLAMBDA         1
+#define AO_SCHEME_FUNC_MACRO           2
+
+#define AO_SCHEME_FUNC_FREE_ARGS       0x80
+#define AO_SCHEME_FUNC_MASK            0x7f
+
+#define AO_SCHEME_FUNC_F_LAMBDA                (AO_SCHEME_FUNC_FREE_ARGS | AO_SCHEME_FUNC_LAMBDA)
+#define AO_SCHEME_FUNC_F_NLAMBDA       (AO_SCHEME_FUNC_FREE_ARGS | AO_SCHEME_FUNC_NLAMBDA)
+#define AO_SCHEME_FUNC_F_MACRO         (AO_SCHEME_FUNC_FREE_ARGS | AO_SCHEME_FUNC_MACRO)
+
+struct ao_scheme_builtin {
+       uint8_t         type;
+       uint8_t         args;
+       uint16_t        func;
+};
+
+#define AO_SCHEME_BUILTIN_ID
+#include "ao_scheme_builtin.h"
+
+typedef ao_poly (*ao_scheme_func_t)(struct ao_scheme_cons *cons);
+
+extern const ao_scheme_func_t  ao_scheme_builtins[];
+
+static inline ao_scheme_func_t
+ao_scheme_func(struct ao_scheme_builtin *b)
+{
+       return ao_scheme_builtins[b->func];
+}
+
+struct ao_scheme_lambda {
+       uint8_t         type;
+       uint8_t         args;
+       ao_poly         code;
+       ao_poly         frame;
+};
+
+static inline struct ao_scheme_lambda *
+ao_scheme_poly_lambda(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_lambda_poly(struct ao_scheme_lambda *lambda)
+{
+       return ao_scheme_poly(lambda, AO_SCHEME_OTHER);
+}
+
+static inline void *
+ao_scheme_poly_other(ao_poly poly) {
+       return ao_scheme_ref(poly);
+}
+
+static inline uint8_t
+ao_scheme_other_type(void *other) {
+#if DBG_MEM
+       if ((*((uint8_t *) other) & AO_SCHEME_OTHER_TYPE_MASK) >= AO_SCHEME_NUM_TYPE)
+               ao_scheme_abort();
+#endif
+       return *((uint8_t *) other) & AO_SCHEME_OTHER_TYPE_MASK;
+}
+
+static inline ao_poly
+ao_scheme_other_poly(const void *other)
+{
+       return ao_scheme_poly(other, AO_SCHEME_OTHER);
+}
+
+static inline int
+ao_scheme_size_round(int size)
+{
+       return (size + 3) & ~3;
+}
+
+static inline int
+ao_scheme_size(const struct ao_scheme_type *type, void *addr)
+{
+       return ao_scheme_size_round(type->size(addr));
+}
+
+#define AO_SCHEME_OTHER_POLY(other) ((ao_poly)(other) + AO_SCHEME_OTHER)
+
+static inline int ao_scheme_poly_base_type(ao_poly poly) {
+       return poly & AO_SCHEME_TYPE_MASK;
+}
+
+static inline int ao_scheme_poly_type(ao_poly poly) {
+       int     type = poly & AO_SCHEME_TYPE_MASK;
+       if (type == AO_SCHEME_OTHER)
+               return ao_scheme_other_type(ao_scheme_poly_other(poly));
+       return type;
+}
+
+static inline int
+ao_scheme_is_cons(ao_poly poly) {
+       return (ao_scheme_poly_base_type(poly) == AO_SCHEME_CONS);
+}
+
+static inline int
+ao_scheme_is_pair(ao_poly poly) {
+       return poly != AO_SCHEME_NIL && (ao_scheme_poly_base_type(poly) == AO_SCHEME_CONS);
+}
+
+static inline struct ao_scheme_cons *
+ao_scheme_poly_cons(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_cons_poly(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_poly(cons, AO_SCHEME_CONS);
+}
+
+static inline int32_t
+ao_scheme_poly_int(ao_poly poly)
+{
+       return (int32_t) ((ao_signed_poly) poly >> AO_SCHEME_TYPE_SHIFT);
+}
+
+static inline ao_poly
+ao_scheme_int_poly(int32_t i)
+{
+       return ((ao_poly) i << 2) | AO_SCHEME_INT;
+}
+
+static inline struct ao_scheme_bigint *
+ao_scheme_poly_bigint(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_bigint_poly(struct ao_scheme_bigint *bi)
+{
+       return ao_scheme_poly(bi, AO_SCHEME_OTHER);
+}
+
+static inline char *
+ao_scheme_poly_string(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_string_poly(char *s)
+{
+       return ao_scheme_poly(s, AO_SCHEME_STRING);
+}
+
+static inline struct ao_scheme_atom *
+ao_scheme_poly_atom(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_atom_poly(struct ao_scheme_atom *a)
+{
+       return ao_scheme_poly(a, AO_SCHEME_OTHER);
+}
+
+static inline struct ao_scheme_builtin *
+ao_scheme_poly_builtin(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_builtin_poly(struct ao_scheme_builtin *b)
+{
+       return ao_scheme_poly(b, AO_SCHEME_OTHER);
+}
+
+static inline ao_poly
+ao_scheme_bool_poly(struct ao_scheme_bool *b)
+{
+       return ao_scheme_poly(b, AO_SCHEME_OTHER);
+}
+
+static inline struct ao_scheme_bool *
+ao_scheme_poly_bool(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+static inline ao_poly
+ao_scheme_float_poly(struct ao_scheme_float *f)
+{
+       return ao_scheme_poly(f, AO_SCHEME_OTHER);
+}
+
+static inline struct ao_scheme_float *
+ao_scheme_poly_float(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+float
+ao_scheme_poly_number(ao_poly p);
+
+static inline ao_poly
+ao_scheme_vector_poly(struct ao_scheme_vector *v)
+{
+       return ao_scheme_poly(v, AO_SCHEME_OTHER);
+}
+
+static inline struct ao_scheme_vector *
+ao_scheme_poly_vector(ao_poly poly)
+{
+       return ao_scheme_ref(poly);
+}
+
+/* memory functions */
+
+extern uint64_t ao_scheme_collects[2];
+extern uint64_t ao_scheme_freed[2];
+extern uint64_t ao_scheme_loops[2];
+
+/* returns 1 if the object was already marked */
+int
+ao_scheme_mark(const struct ao_scheme_type *type, void *addr);
+
+/* returns 1 if the object was already marked */
+int
+ao_scheme_mark_memory(const struct ao_scheme_type *type, void *addr);
+
+void *
+ao_scheme_move_map(void *addr);
+
+/* returns 1 if the object was already moved */
+int
+ao_scheme_move(const struct ao_scheme_type *type, void **ref);
+
+/* returns 1 if the object was already moved */
+int
+ao_scheme_move_memory(const struct ao_scheme_type *type, void **ref);
+
+void *
+ao_scheme_alloc(int size);
+
+#define AO_SCHEME_COLLECT_FULL         1
+#define AO_SCHEME_COLLECT_INCREMENTAL  0
+
+int
+ao_scheme_collect(uint8_t style);
+
+#if DBG_FREE_CONS
+void
+ao_scheme_cons_check(struct ao_scheme_cons *cons);
+#endif
+
+void
+ao_scheme_cons_stash(int id, struct ao_scheme_cons *cons);
+
+struct ao_scheme_cons *
+ao_scheme_cons_fetch(int id);
+
+void
+ao_scheme_poly_stash(int id, ao_poly poly);
+
+ao_poly
+ao_scheme_poly_fetch(int id);
+
+void
+ao_scheme_string_stash(int id, char *string);
+
+char *
+ao_scheme_string_fetch(int id);
+
+static inline void
+ao_scheme_stack_stash(int id, struct ao_scheme_stack *stack) {
+       ao_scheme_poly_stash(id, ao_scheme_stack_poly(stack));
+}
+
+static inline struct ao_scheme_stack *
+ao_scheme_stack_fetch(int id) {
+       return ao_scheme_poly_stack(ao_scheme_poly_fetch(id));
+}
+
+void
+ao_scheme_frame_stash(int id, struct ao_scheme_frame *frame);
+
+struct ao_scheme_frame *
+ao_scheme_frame_fetch(int id);
+
+/* bool */
+
+extern const struct ao_scheme_type ao_scheme_bool_type;
+
+void
+ao_scheme_bool_write(ao_poly v);
+
+#ifdef AO_SCHEME_MAKE_CONST
+struct ao_scheme_bool  *ao_scheme_true, *ao_scheme_false;
+
+struct ao_scheme_bool *
+ao_scheme_bool_get(uint8_t value);
+#endif
+
+/* cons */
+extern const struct ao_scheme_type ao_scheme_cons_type;
+
+struct ao_scheme_cons *
+ao_scheme_cons_cons(ao_poly car, ao_poly cdr);
+
+/* Return a cons or NULL for a proper list, else error */
+struct ao_scheme_cons *
+ao_scheme_cons_cdr(struct ao_scheme_cons *cons);
+
+ao_poly
+ao_scheme__cons(ao_poly car, ao_poly cdr);
+
+extern struct ao_scheme_cons *ao_scheme_cons_free_list;
+
+void
+ao_scheme_cons_free(struct ao_scheme_cons *cons);
+
+void
+ao_scheme_cons_write(ao_poly);
+
+void
+ao_scheme_cons_display(ao_poly);
+
+int
+ao_scheme_cons_length(struct ao_scheme_cons *cons);
+
+struct ao_scheme_cons *
+ao_scheme_cons_copy(struct ao_scheme_cons *cons);
+
+/* string */
+extern const struct ao_scheme_type ao_scheme_string_type;
+
+char *
+ao_scheme_string_copy(char *a);
+
+char *
+ao_scheme_string_cat(char *a, char *b);
+
+ao_poly
+ao_scheme_string_pack(struct ao_scheme_cons *cons);
+
+ao_poly
+ao_scheme_string_unpack(char *a);
+
+void
+ao_scheme_string_write(ao_poly s);
+
+void
+ao_scheme_string_display(ao_poly s);
+
+/* atom */
+extern const struct ao_scheme_type ao_scheme_atom_type;
+
+extern struct ao_scheme_atom   *ao_scheme_atoms;
+extern struct ao_scheme_frame  *ao_scheme_frame_global;
+extern struct ao_scheme_frame  *ao_scheme_frame_current;
+
+void
+ao_scheme_atom_write(ao_poly a);
+
+struct ao_scheme_atom *
+ao_scheme_atom_intern(char *name);
+
+ao_poly *
+ao_scheme_atom_ref(ao_poly atom, struct ao_scheme_frame **frame_ref);
+
+ao_poly
+ao_scheme_atom_get(ao_poly atom);
+
+ao_poly
+ao_scheme_atom_set(ao_poly atom, ao_poly val);
+
+ao_poly
+ao_scheme_atom_def(ao_poly atom, ao_poly val);
+
+/* int */
+void
+ao_scheme_int_write(ao_poly i);
+
+int32_t
+ao_scheme_poly_integer(ao_poly p);
+
+ao_poly
+ao_scheme_integer_poly(int32_t i);
+
+static inline int
+ao_scheme_integer_typep(uint8_t t)
+{
+       return (t == AO_SCHEME_INT) || (t == AO_SCHEME_BIGINT);
+}
+
+void
+ao_scheme_bigint_write(ao_poly i);
+
+extern const struct ao_scheme_type     ao_scheme_bigint_type;
+
+/* vector */
+
+void
+ao_scheme_vector_write(ao_poly v);
+
+void
+ao_scheme_vector_display(ao_poly v);
+
+struct ao_scheme_vector *
+ao_scheme_vector_alloc(uint16_t length, ao_poly fill);
+
+ao_poly
+ao_scheme_vector_get(ao_poly v, ao_poly i);
+
+ao_poly
+ao_scheme_vector_set(ao_poly v, ao_poly i, ao_poly p);
+
+struct ao_scheme_vector *
+ao_scheme_list_to_vector(struct ao_scheme_cons *cons);
+
+struct ao_scheme_cons *
+ao_scheme_vector_to_list(struct ao_scheme_vector *vector);
+
+extern const struct ao_scheme_type     ao_scheme_vector_type;
+
+/* prim */
+void
+ao_scheme_poly_write(ao_poly p);
+
+void
+ao_scheme_poly_display(ao_poly p);
+
+int
+ao_scheme_poly_mark(ao_poly p, uint8_t note_cons);
+
+/* returns 1 if the object has already been moved */
+int
+ao_scheme_poly_move(ao_poly *p, uint8_t note_cons);
+
+/* eval */
+
+void
+ao_scheme_eval_clear_globals(void);
+
+int
+ao_scheme_eval_restart(void);
+
+ao_poly
+ao_scheme_eval(ao_poly p);
+
+ao_poly
+ao_scheme_set_cond(struct ao_scheme_cons *cons);
+
+/* float */
+extern const struct ao_scheme_type ao_scheme_float_type;
+
+void
+ao_scheme_float_write(ao_poly p);
+
+ao_poly
+ao_scheme_float_get(float value);
+
+static inline uint8_t
+ao_scheme_number_typep(uint8_t t)
+{
+       return ao_scheme_integer_typep(t) || (t == AO_SCHEME_FLOAT);
+}
+
+float
+ao_scheme_poly_number(ao_poly p);
+
+/* builtin */
+void
+ao_scheme_builtin_write(ao_poly b);
+
+extern const struct ao_scheme_type ao_scheme_builtin_type;
+
+/* Check argument count */
+ao_poly
+ao_scheme_check_argc(ao_poly name, struct ao_scheme_cons *cons, int min, int max);
+
+/* Check argument type */
+ao_poly
+ao_scheme_check_argt(ao_poly name, struct ao_scheme_cons *cons, int argc, int type, int nil_ok);
+
+/* Fetch an arg (nil if off the end) */
+ao_poly
+ao_scheme_arg(struct ao_scheme_cons *cons, int argc);
+
+char *
+ao_scheme_args_name(uint8_t args);
+
+/* read */
+extern int                     ao_scheme_read_list;
+extern struct ao_scheme_cons   *ao_scheme_read_cons;
+extern struct ao_scheme_cons   *ao_scheme_read_cons_tail;
+extern struct ao_scheme_cons   *ao_scheme_read_stack;
+
+ao_poly
+ao_scheme_read(void);
+
+/* rep */
+ao_poly
+ao_scheme_read_eval_print(void);
+
+/* frame */
+extern const struct ao_scheme_type ao_scheme_frame_type;
+extern const struct ao_scheme_type ao_scheme_frame_vals_type;
+
+#define AO_SCHEME_FRAME_FREE   6
+
+extern struct ao_scheme_frame  *ao_scheme_frame_free_list[AO_SCHEME_FRAME_FREE];
+
+ao_poly
+ao_scheme_frame_mark(struct ao_scheme_frame *frame);
+
+ao_poly *
+ao_scheme_frame_ref(struct ao_scheme_frame *frame, ao_poly atom);
+
+struct ao_scheme_frame *
+ao_scheme_frame_new(int num);
+
+void
+ao_scheme_frame_free(struct ao_scheme_frame *frame);
+
+void
+ao_scheme_frame_bind(struct ao_scheme_frame *frame, int num, ao_poly atom, ao_poly val);
+
+ao_poly
+ao_scheme_frame_add(struct ao_scheme_frame *frame, ao_poly atom, ao_poly val);
+
+void
+ao_scheme_frame_write(ao_poly p);
+
+void
+ao_scheme_frame_init(void);
+
+/* lambda */
+extern const struct ao_scheme_type ao_scheme_lambda_type;
+
+extern const char * const ao_scheme_state_names[];
+
+struct ao_scheme_lambda *
+ao_scheme_lambda_new(ao_poly cons);
+
+void
+ao_scheme_lambda_write(ao_poly lambda);
+
+ao_poly
+ao_scheme_lambda_eval(void);
+
+/* stack */
+
+extern const struct ao_scheme_type ao_scheme_stack_type;
+extern struct ao_scheme_stack  *ao_scheme_stack;
+extern struct ao_scheme_stack  *ao_scheme_stack_free_list;
+
+void
+ao_scheme_stack_reset(struct ao_scheme_stack *stack);
+
+int
+ao_scheme_stack_push(void);
+
+void
+ao_scheme_stack_pop(void);
+
+void
+ao_scheme_stack_clear(void);
+
+void
+ao_scheme_stack_write(ao_poly stack);
+
+ao_poly
+ao_scheme_stack_eval(void);
+
+/* error */
+
+void
+ao_scheme_vprintf(char *format, va_list args);
+
+void
+ao_scheme_printf(char *format, ...);
+
+void
+ao_scheme_error_poly(char *name, ao_poly poly, ao_poly last);
+
+void
+ao_scheme_error_frame(int indent, char *name, struct ao_scheme_frame *frame);
+
+ao_poly
+ao_scheme_error(int error, char *format, ...);
+
+/* builtins */
+
+#define AO_SCHEME_BUILTIN_DECLS
+#include "ao_scheme_builtin.h"
+
+/* debugging macros */
+
+#if DBG_EVAL || DBG_READ || DBG_MEM
+#define DBG_CODE       1
+int ao_scheme_stack_depth;
+#define DBG_DO(a)      a
+#define DBG_INDENT()   do { int _s; for(_s = 0; _s < ao_scheme_stack_depth; _s++) printf("  "); } while(0)
+#define DBG_IN()       (++ao_scheme_stack_depth)
+#define DBG_OUT()      (--ao_scheme_stack_depth)
+#define DBG_RESET()    (ao_scheme_stack_depth = 0)
+#define DBG(...)       ao_scheme_printf(__VA_ARGS__)
+#define DBGI(...)      do { printf("%4d: ", __LINE__); DBG_INDENT(); DBG(__VA_ARGS__); } while (0)
+#define DBG_CONS(a)    ao_scheme_cons_write(ao_scheme_cons_poly(a))
+#define DBG_POLY(a)    ao_scheme_poly_write(a)
+#define OFFSET(a)      ((a) ? (int) ((uint8_t *) a - ao_scheme_pool) : -1)
+#define DBG_STACK()    ao_scheme_stack_write(ao_scheme_stack_poly(ao_scheme_stack))
+static inline void
+ao_scheme_frames_dump(void)
+{
+       struct ao_scheme_stack *s;
+       DBGI(".. current frame: "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+       for (s = ao_scheme_stack; s; s = ao_scheme_poly_stack(s->prev)) {
+               DBGI(".. stack frame: "); DBG_POLY(s->frame); DBG("\n");
+       }
+}
+#define DBG_FRAMES()   ao_scheme_frames_dump()
+#else
+#define DBG_DO(a)
+#define DBG_INDENT()
+#define DBG_IN()
+#define DBG_OUT()
+#define DBG(...)
+#define DBGI(...)
+#define DBG_CONS(a)
+#define DBG_POLY(a)
+#define DBG_RESET()
+#define DBG_STACK()
+#define DBG_FRAMES()
+#endif
+
+#if DBG_READ
+#define RDBGI(...)     DBGI(__VA_ARGS__)
+#define RDBG_IN()      DBG_IN()
+#define RDBG_OUT()     DBG_OUT()
+#else
+#define RDBGI(...)
+#define RDBG_IN()
+#define RDBG_OUT()
+#endif
+
+#define DBG_MEM_START  1
+
+#if DBG_MEM
+
+#include <assert.h>
+extern int dbg_move_depth;
+#define MDBG_DUMP 1
+#define MDBG_OFFSET(a) ((a) ? (int) ((uint8_t *) (a) - ao_scheme_pool) : -1)
+
+extern int dbg_mem;
+
+#define MDBG_DO(a)     DBG_DO(a)
+#define MDBG_MOVE(...) do { if (dbg_mem) { int d; for (d = 0; d < dbg_move_depth; d++) printf ("  "); printf(__VA_ARGS__); } } while (0)
+#define MDBG_MORE(...) do { if (dbg_mem) printf(__VA_ARGS__); } while (0)
+#define MDBG_MOVE_IN() (dbg_move_depth++)
+#define MDBG_MOVE_OUT()        (assert(--dbg_move_depth >= 0))
+
+#else
+
+#define MDBG_DO(a)
+#define MDBG_MOVE(...)
+#define MDBG_MORE(...)
+#define MDBG_MOVE_IN()
+#define MDBG_MOVE_OUT()
+
+#endif
+
+#endif /* _AO_SCHEME_H_ */
diff --git a/src/scheme/ao_scheme_atom.c b/src/scheme/ao_scheme_atom.c
new file mode 100644 (file)
index 0000000..cb32b7f
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao_scheme.h"
+
+static int name_size(char *name)
+{
+       return sizeof(struct ao_scheme_atom) + strlen(name) + 1;
+}
+
+static int atom_size(void *addr)
+{
+       struct ao_scheme_atom   *atom = addr;
+       if (!atom)
+               return 0;
+       return name_size(atom->name);
+}
+
+static void atom_mark(void *addr)
+{
+       struct ao_scheme_atom   *atom = addr;
+
+       for (;;) {
+               atom = ao_scheme_poly_atom(atom->next);
+               if (!atom)
+                       break;
+               if (ao_scheme_mark_memory(&ao_scheme_atom_type, atom))
+                       break;
+       }
+}
+
+static void atom_move(void *addr)
+{
+       struct ao_scheme_atom   *atom = addr;
+       int                     ret;
+
+       for (;;) {
+               struct ao_scheme_atom *next = ao_scheme_poly_atom(atom->next);
+
+               if (!next)
+                       break;
+               ret = ao_scheme_move_memory(&ao_scheme_atom_type, (void **) &next);
+               if (next != ao_scheme_poly_atom(atom->next))
+                       atom->next = ao_scheme_atom_poly(next);
+               if (ret)
+                       break;
+               atom = next;
+       }
+}
+
+const struct ao_scheme_type ao_scheme_atom_type = {
+       .mark = atom_mark,
+       .size = atom_size,
+       .move = atom_move,
+       .name = "atom"
+};
+
+struct ao_scheme_atom  *ao_scheme_atoms;
+
+struct ao_scheme_atom *
+ao_scheme_atom_intern(char *name)
+{
+       struct ao_scheme_atom   *atom;
+
+       for (atom = ao_scheme_atoms; atom; atom = ao_scheme_poly_atom(atom->next)) {
+               if (!strcmp(atom->name, name))
+                       return atom;
+       }
+#ifdef ao_builtin_atoms
+       for (atom = ao_scheme_poly_atom(ao_builtin_atoms); atom; atom = ao_scheme_poly_atom(atom->next)) {
+               if (!strcmp(atom->name, name))
+                       return atom;
+       }
+#endif
+       ao_scheme_string_stash(0, name);
+       atom = ao_scheme_alloc(name_size(name));
+       name = ao_scheme_string_fetch(0);
+       if (atom) {
+               atom->type = AO_SCHEME_ATOM;
+               atom->next = ao_scheme_atom_poly(ao_scheme_atoms);
+               ao_scheme_atoms = atom;
+               strcpy(atom->name, name);
+       }
+       return atom;
+}
+
+ao_poly *
+ao_scheme_atom_ref(ao_poly atom, struct ao_scheme_frame **frame_ref)
+{
+       ao_poly *ref;
+       struct ao_scheme_frame *frame;
+
+       for (frame = ao_scheme_frame_current; frame; frame = ao_scheme_poly_frame(frame->prev)) {
+               ref = ao_scheme_frame_ref(frame, atom);
+               if (ref) {
+                       if (frame_ref)
+                               *frame_ref = frame;
+                       return ref;
+               }
+       }
+       ref = ao_scheme_frame_ref(ao_scheme_frame_global, atom);
+       if (ref)
+               if (frame_ref)
+                       *frame_ref = ao_scheme_frame_global;
+       return ref;
+}
+
+ao_poly
+ao_scheme_atom_get(ao_poly atom)
+{
+       ao_poly *ref = ao_scheme_atom_ref(atom, NULL);
+
+#ifdef ao_builtin_frame
+       if (!ref)
+               ref = ao_scheme_frame_ref(ao_scheme_poly_frame(ao_builtin_frame), atom);
+#endif
+       if (ref)
+               return *ref;
+       return ao_scheme_error(AO_SCHEME_UNDEFINED, "undefined atom %s", ao_scheme_poly_atom(atom)->name);
+}
+
+ao_poly
+ao_scheme_atom_set(ao_poly atom, ao_poly val)
+{
+       ao_poly *ref = ao_scheme_atom_ref(atom, NULL);
+
+       if (!ref)
+               return ao_scheme_error(AO_SCHEME_UNDEFINED, "undefined atom %s", ao_scheme_poly_atom(atom)->name);
+       *ref = val;
+       return val;
+}
+
+ao_poly
+ao_scheme_atom_def(ao_poly atom, ao_poly val)
+{
+       struct ao_scheme_frame  *frame;
+       ao_poly *ref = ao_scheme_atom_ref(atom, &frame);
+
+       if (ref) {
+               if (frame == ao_scheme_frame_current)
+                       return ao_scheme_error(AO_SCHEME_REDEFINED, "attempt to redefine atom %s", ao_scheme_poly_atom(atom)->name);
+               *ref = val;
+               return val;
+       }
+       return ao_scheme_frame_add(ao_scheme_frame_current ? ao_scheme_frame_current : ao_scheme_frame_global, atom, val);
+}
+
+void
+ao_scheme_atom_write(ao_poly a)
+{
+       struct ao_scheme_atom *atom = ao_scheme_poly_atom(a);
+       printf("%s", atom->name);
+}
diff --git a/src/scheme/ao_scheme_bool.c b/src/scheme/ao_scheme_bool.c
new file mode 100644 (file)
index 0000000..c1e880c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include "ao_scheme.h"
+
+static void bool_mark(void *addr)
+{
+       (void) addr;
+}
+
+static int bool_size(void *addr)
+{
+       (void) addr;
+       return sizeof (struct ao_scheme_bool);
+}
+
+static void bool_move(void *addr)
+{
+       (void) addr;
+}
+
+const struct ao_scheme_type ao_scheme_bool_type = {
+       .mark = bool_mark,
+       .size = bool_size,
+       .move = bool_move,
+       .name = "bool"
+};
+
+void
+ao_scheme_bool_write(ao_poly v)
+{
+       struct ao_scheme_bool   *b = ao_scheme_poly_bool(v);
+
+       if (b->value)
+               printf("#t");
+       else
+               printf("#f");
+}
+
+#ifdef AO_SCHEME_MAKE_CONST
+
+struct ao_scheme_bool  *ao_scheme_true, *ao_scheme_false;
+
+struct ao_scheme_bool *
+ao_scheme_bool_get(uint8_t value)
+{
+       struct ao_scheme_bool   **b;
+
+       if (value)
+               b = &ao_scheme_true;
+       else
+               b = &ao_scheme_false;
+
+       if (!*b) {
+               *b = ao_scheme_alloc(sizeof (struct ao_scheme_bool));
+               (*b)->type = AO_SCHEME_BOOL;
+               (*b)->value = value;
+       }
+       return *b;
+}
+
+#endif
diff --git a/src/scheme/ao_scheme_builtin.c b/src/scheme/ao_scheme_builtin.c
new file mode 100644 (file)
index 0000000..1754e67
--- /dev/null
@@ -0,0 +1,1096 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+#include <limits.h>
+#include <math.h>
+
+static int
+builtin_size(void *addr)
+{
+       (void) addr;
+       return sizeof (struct ao_scheme_builtin);
+}
+
+static void
+builtin_mark(void *addr)
+{
+       (void) addr;
+}
+
+static void
+builtin_move(void *addr)
+{
+       (void) addr;
+}
+
+const struct ao_scheme_type ao_scheme_builtin_type = {
+       .size = builtin_size,
+       .mark = builtin_mark,
+       .move = builtin_move
+};
+
+#ifdef AO_SCHEME_MAKE_CONST
+
+#define AO_SCHEME_BUILTIN_CASENAME
+#include "ao_scheme_builtin.h"
+
+char *ao_scheme_args_name(uint8_t args) {
+       args &= AO_SCHEME_FUNC_MASK;
+       switch (args) {
+       case AO_SCHEME_FUNC_LAMBDA: return ao_scheme_poly_atom(_ao_scheme_atom_lambda)->name;
+       case AO_SCHEME_FUNC_NLAMBDA: return ao_scheme_poly_atom(_ao_scheme_atom_nlambda)->name;
+       case AO_SCHEME_FUNC_MACRO: return ao_scheme_poly_atom(_ao_scheme_atom_macro)->name;
+       default: return "???";
+       }
+}
+#else
+
+#define AO_SCHEME_BUILTIN_ARRAYNAME
+#include "ao_scheme_builtin.h"
+
+static char *
+ao_scheme_builtin_name(enum ao_scheme_builtin_id b) {
+       if (b < _builtin_last)
+               return ao_scheme_poly_atom(builtin_names[b])->name;
+       return "???";
+}
+
+static const ao_poly ao_scheme_args_atoms[] = {
+       [AO_SCHEME_FUNC_LAMBDA] = _ao_scheme_atom_lambda,
+       [AO_SCHEME_FUNC_NLAMBDA] = _ao_scheme_atom_nlambda,
+       [AO_SCHEME_FUNC_MACRO] = _ao_scheme_atom_macro,
+};
+
+char *
+ao_scheme_args_name(uint8_t args)
+{
+       args &= AO_SCHEME_FUNC_MASK;
+       if (args < sizeof ao_scheme_args_atoms / sizeof ao_scheme_args_atoms[0])
+               return ao_scheme_poly_atom(ao_scheme_args_atoms[args])->name;
+       return "(unknown)";
+}
+#endif
+
+void
+ao_scheme_builtin_write(ao_poly b)
+{
+       struct ao_scheme_builtin *builtin = ao_scheme_poly_builtin(b);
+       printf("%s", ao_scheme_builtin_name(builtin->func));
+}
+
+ao_poly
+ao_scheme_check_argc(ao_poly name, struct ao_scheme_cons *cons, int min, int max)
+{
+       int     argc = 0;
+
+       while (cons && argc <= max) {
+               argc++;
+               cons = ao_scheme_cons_cdr(cons);
+       }
+       if (argc < min || argc > max)
+               return ao_scheme_error(AO_SCHEME_INVALID, "%s: invalid arg count", ao_scheme_poly_atom(name)->name);
+       return _ao_scheme_bool_true;
+}
+
+ao_poly
+ao_scheme_arg(struct ao_scheme_cons *cons, int argc)
+{
+       if (!cons)
+               return AO_SCHEME_NIL;
+       while (argc--) {
+               if (!cons)
+                       return AO_SCHEME_NIL;
+               cons = ao_scheme_cons_cdr(cons);
+       }
+       return cons->car;
+}
+
+ao_poly
+ao_scheme_check_argt(ao_poly name, struct ao_scheme_cons *cons, int argc, int type, int nil_ok)
+{
+       ao_poly car = ao_scheme_arg(cons, argc);
+
+       if ((!car && !nil_ok) || ao_scheme_poly_type(car) != type)
+               return ao_scheme_error(AO_SCHEME_INVALID, "%v: arg %d invalid type %v", name, argc, car);
+       return _ao_scheme_bool_true;
+}
+
+int32_t
+ao_scheme_arg_int(ao_poly name, struct ao_scheme_cons *cons, int argc)
+{
+       ao_poly p = ao_scheme_arg(cons, argc);
+       int32_t i = ao_scheme_poly_integer(p);
+
+       if (i == AO_SCHEME_NOT_INTEGER)
+               (void) ao_scheme_error(AO_SCHEME_INVALID, "%v: arg %d invalid type %v", name, argc, p);
+       return i;
+}
+
+ao_poly
+ao_scheme_do_car(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_car, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_car, cons, 0, AO_SCHEME_CONS, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_poly_cons(cons->car)->car;
+}
+
+ao_poly
+ao_scheme_do_cdr(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_cdr, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_cdr, cons, 0, AO_SCHEME_CONS, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_poly_cons(cons->car)->cdr;
+}
+
+ao_poly
+ao_scheme_do_cons(struct ao_scheme_cons *cons)
+{
+       ao_poly car, cdr;
+       if(!ao_scheme_check_argc(_ao_scheme_atom_cons, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       car = ao_scheme_arg(cons, 0);
+       cdr = ao_scheme_arg(cons, 1);
+       return ao_scheme__cons(car, cdr);
+}
+
+ao_poly
+ao_scheme_do_last(struct ao_scheme_cons *cons)
+{
+       struct ao_scheme_cons   *list;
+       if (!ao_scheme_check_argc(_ao_scheme_atom_last, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_last, cons, 0, AO_SCHEME_CONS, 1))
+               return AO_SCHEME_NIL;
+       for (list = ao_scheme_poly_cons(ao_scheme_arg(cons, 0));
+            list;
+            list = ao_scheme_cons_cdr(list))
+       {
+               if (!list->cdr)
+                       return list->car;
+       }
+       return AO_SCHEME_NIL;
+}
+
+ao_poly
+ao_scheme_do_length(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_length, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_length, cons, 0, AO_SCHEME_CONS, 1))
+               return AO_SCHEME_NIL;
+       return ao_scheme_int_poly(ao_scheme_cons_length(ao_scheme_poly_cons(ao_scheme_arg(cons, 0))));
+}
+
+ao_poly
+ao_scheme_do_list_copy(struct ao_scheme_cons *cons)
+{
+       struct ao_scheme_cons *new;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_length, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_length, cons, 0, AO_SCHEME_CONS, 1))
+               return AO_SCHEME_NIL;
+       new = ao_scheme_cons_copy(ao_scheme_poly_cons(ao_scheme_arg(cons, 0)));
+       return ao_scheme_cons_poly(new);
+}
+
+ao_poly
+ao_scheme_do_quote(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_quote, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       return ao_scheme_arg(cons, 0);
+}
+
+ao_poly
+ao_scheme_do_set(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_set, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_set, cons, 0, AO_SCHEME_ATOM, 0))
+               return AO_SCHEME_NIL;
+
+       return ao_scheme_atom_set(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
+}
+
+ao_poly
+ao_scheme_do_def(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_def, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_def, cons, 0, AO_SCHEME_ATOM, 0))
+               return AO_SCHEME_NIL;
+
+       return ao_scheme_atom_def(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
+}
+
+ao_poly
+ao_scheme_do_setq(struct ao_scheme_cons *cons)
+{
+       ao_poly name;
+       if (!ao_scheme_check_argc(_ao_scheme_atom_set21, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       name = cons->car;
+       if (ao_scheme_poly_type(name) != AO_SCHEME_ATOM)
+               return ao_scheme_error(AO_SCHEME_INVALID, "set! of non-atom %v", name);
+       if (!ao_scheme_atom_ref(name, NULL))
+               return ao_scheme_error(AO_SCHEME_INVALID, "atom %v not defined", name);
+       return ao_scheme__cons(_ao_scheme_atom_set,
+                            ao_scheme__cons(ao_scheme__cons(_ao_scheme_atom_quote,
+                                                        ao_scheme__cons(name, AO_SCHEME_NIL)),
+                                          cons->cdr));
+}
+
+ao_poly
+ao_scheme_do_cond(struct ao_scheme_cons *cons)
+{
+       ao_scheme_set_cond(cons);
+       return AO_SCHEME_NIL;
+}
+
+ao_poly
+ao_scheme_do_begin(struct ao_scheme_cons *cons)
+{
+       ao_scheme_stack->state = eval_begin;
+       ao_scheme_stack->sexprs = ao_scheme_cons_poly(cons);
+       return AO_SCHEME_NIL;
+}
+
+ao_poly
+ao_scheme_do_while(struct ao_scheme_cons *cons)
+{
+       ao_scheme_stack->state = eval_while;
+       ao_scheme_stack->sexprs = ao_scheme_cons_poly(cons);
+       return AO_SCHEME_NIL;
+}
+
+ao_poly
+ao_scheme_do_write(struct ao_scheme_cons *cons)
+{
+       ao_poly val = AO_SCHEME_NIL;
+       while (cons) {
+               val = cons->car;
+               ao_scheme_poly_write(val);
+               cons = ao_scheme_cons_cdr(cons);
+               if (cons)
+                       printf(" ");
+       }
+       return _ao_scheme_bool_true;
+}
+
+ao_poly
+ao_scheme_do_display(struct ao_scheme_cons *cons)
+{
+       ao_poly val = AO_SCHEME_NIL;
+       while (cons) {
+               val = cons->car;
+               ao_scheme_poly_display(val);
+               cons = ao_scheme_cons_cdr(cons);
+       }
+       return _ao_scheme_bool_true;
+}
+
+ao_poly
+ao_scheme_math(struct ao_scheme_cons *orig_cons, enum ao_scheme_builtin_id op)
+{
+       struct ao_scheme_cons *cons = cons;
+       ao_poly ret = AO_SCHEME_NIL;
+
+       for (cons = orig_cons; cons; cons = ao_scheme_cons_cdr(cons)) {
+               ao_poly         car = cons->car;
+               uint8_t         rt = ao_scheme_poly_type(ret);
+               uint8_t         ct = ao_scheme_poly_type(car);
+
+               if (cons == orig_cons) {
+                       ret = car;
+                       ao_scheme_cons_stash(0, cons);
+                       if (cons->cdr == AO_SCHEME_NIL) {
+                               switch (op) {
+                               case builtin_minus:
+                                       if (ao_scheme_integer_typep(ct))
+                                               ret = ao_scheme_integer_poly(-ao_scheme_poly_integer(ret));
+                                       else if (ct == AO_SCHEME_FLOAT)
+                                               ret = ao_scheme_float_get(-ao_scheme_poly_number(ret));
+                                       break;
+                               case builtin_divide:
+                                       if (ao_scheme_integer_typep(ct) && ao_scheme_poly_integer(ret) == 1)
+                                               ;
+                                       else if (ao_scheme_number_typep(ct)) {
+                                               float   v = ao_scheme_poly_number(ret);
+                                               ret = ao_scheme_float_get(1/v);
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       cons = ao_scheme_cons_fetch(0);
+               } else if (ao_scheme_integer_typep(rt) && ao_scheme_integer_typep(ct)) {
+                       int32_t r = ao_scheme_poly_integer(ret);
+                       int32_t c = ao_scheme_poly_integer(car);
+                       int64_t t;
+
+                       switch(op) {
+                       case builtin_plus:
+                               r += c;
+                       check_overflow:
+                               if (r < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < r)
+                                       goto inexact;
+                               break;
+                       case builtin_minus:
+                               r -= c;
+                               goto check_overflow;
+                               break;
+                       case builtin_times:
+                               t = (int64_t) r * (int64_t) c;
+                               if (t < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < t)
+                                       goto inexact;
+                               r = (int32_t) t;
+                               break;
+                       case builtin_divide:
+                               if (c != 0 && (r % c) == 0)
+                                       r /= c;
+                               else
+                                       goto inexact;
+                               break;
+                       case builtin_quotient:
+                               if (c == 0)
+                                       return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "quotient by zero");
+                               if (r % c != 0 && (c < 0) != (r < 0))
+                                       r = r / c - 1;
+                               else
+                                       r = r / c;
+                               break;
+                       case builtin_remainder:
+                               if (c == 0)
+                                       return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "remainder by zero");
+                               r %= c;
+                               break;
+                       case builtin_modulo:
+                               if (c == 0)
+                                       return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "modulo by zero");
+                               r %= c;
+                               if ((r < 0) != (c < 0))
+                                       r += c;
+                               break;
+                       default:
+                               break;
+                       }
+                       ao_scheme_cons_stash(0, cons);
+                       ret = ao_scheme_integer_poly(r);
+                       cons = ao_scheme_cons_fetch(0);
+               } else if (ao_scheme_number_typep(rt) && ao_scheme_number_typep(ct)) {
+                       float r, c;
+               inexact:
+                       r = ao_scheme_poly_number(ret);
+                       c = ao_scheme_poly_number(car);
+                       switch(op) {
+                       case builtin_plus:
+                               r += c;
+                               break;
+                       case builtin_minus:
+                               r -= c;
+                               break;
+                       case builtin_times:
+                               r *= c;
+                               break;
+                       case builtin_divide:
+                               r /= c;
+                               break;
+                       case builtin_quotient:
+                       case builtin_remainder:
+                       case builtin_modulo:
+                               return ao_scheme_error(AO_SCHEME_INVALID, "non-integer value in integer divide");
+                       default:
+                               break;
+                       }
+                       ao_scheme_cons_stash(0, cons);
+                       ret = ao_scheme_float_get(r);
+                       cons = ao_scheme_cons_fetch(0);
+               }
+               else if (rt == AO_SCHEME_STRING && ct == AO_SCHEME_STRING && op == builtin_plus) {
+                       ao_scheme_cons_stash(0, cons);
+                       ret = ao_scheme_string_poly(ao_scheme_string_cat(ao_scheme_poly_string(ret),
+                                                                        ao_scheme_poly_string(car)));
+                       cons = ao_scheme_cons_fetch(0);
+                       if (!ret)
+                               return ret;
+               }
+               else
+                       return ao_scheme_error(AO_SCHEME_INVALID, "invalid args");
+       }
+       return ret;
+}
+
+ao_poly
+ao_scheme_do_plus(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_math(cons, builtin_plus);
+}
+
+ao_poly
+ao_scheme_do_minus(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_math(cons, builtin_minus);
+}
+
+ao_poly
+ao_scheme_do_times(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_math(cons, builtin_times);
+}
+
+ao_poly
+ao_scheme_do_divide(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_math(cons, builtin_divide);
+}
+
+ao_poly
+ao_scheme_do_quotient(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_math(cons, builtin_quotient);
+}
+
+ao_poly
+ao_scheme_do_modulo(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_math(cons, builtin_modulo);
+}
+
+ao_poly
+ao_scheme_do_remainder(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_math(cons, builtin_remainder);
+}
+
+ao_poly
+ao_scheme_compare(struct ao_scheme_cons *cons, enum ao_scheme_builtin_id op)
+{
+       ao_poly left;
+
+       if (!cons)
+               return _ao_scheme_bool_true;
+
+       left = cons->car;
+       for (cons = ao_scheme_cons_cdr(cons); cons; cons = ao_scheme_cons_cdr(cons)) {
+               ao_poly right = cons->car;
+
+               if (op == builtin_equal && left == right) {
+                       ;
+               } else {
+                       uint8_t lt = ao_scheme_poly_type(left);
+                       uint8_t rt = ao_scheme_poly_type(right);
+                       if (ao_scheme_integer_typep(lt) && ao_scheme_integer_typep(rt)) {
+                               int32_t l = ao_scheme_poly_integer(left);
+                               int32_t r = ao_scheme_poly_integer(right);
+
+                               switch (op) {
+                               case builtin_less:
+                                       if (!(l < r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_greater:
+                                       if (!(l > r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_less_equal:
+                                       if (!(l <= r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_greater_equal:
+                                       if (!(l >= r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_equal:
+                                       if (!(l == r))
+                                               return _ao_scheme_bool_false;
+                               default:
+                                       break;
+                               }
+                       } else if (ao_scheme_number_typep(lt) && ao_scheme_number_typep(rt)) {
+                               float l, r;
+
+                               l = ao_scheme_poly_number(left);
+                               r = ao_scheme_poly_number(right);
+
+                               switch (op) {
+                               case builtin_less:
+                                       if (!(l < r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_greater:
+                                       if (!(l > r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_less_equal:
+                                       if (!(l <= r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_greater_equal:
+                                       if (!(l >= r))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_equal:
+                                       if (!(l == r))
+                                               return _ao_scheme_bool_false;
+                               default:
+                                       break;
+                               }
+                       } else if (lt == AO_SCHEME_STRING && rt == AO_SCHEME_STRING) {
+                               int c = strcmp(ao_scheme_poly_string(left),
+                                              ao_scheme_poly_string(right));
+                               switch (op) {
+                               case builtin_less:
+                                       if (!(c < 0))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_greater:
+                                       if (!(c > 0))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_less_equal:
+                                       if (!(c <= 0))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_greater_equal:
+                                       if (!(c >= 0))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               case builtin_equal:
+                                       if (!(c == 0))
+                                               return _ao_scheme_bool_false;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       } else
+                               return _ao_scheme_bool_false;
+               }
+               left = right;
+       }
+       return _ao_scheme_bool_true;
+}
+
+ao_poly
+ao_scheme_do_equal(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_compare(cons, builtin_equal);
+}
+
+ao_poly
+ao_scheme_do_less(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_compare(cons, builtin_less);
+}
+
+ao_poly
+ao_scheme_do_greater(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_compare(cons, builtin_greater);
+}
+
+ao_poly
+ao_scheme_do_less_equal(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_compare(cons, builtin_less_equal);
+}
+
+ao_poly
+ao_scheme_do_greater_equal(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_compare(cons, builtin_greater_equal);
+}
+
+ao_poly
+ao_scheme_do_list_to_string(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3estring, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3estring, cons, 0, AO_SCHEME_CONS, 1))
+               return AO_SCHEME_NIL;
+       return ao_scheme_string_pack(ao_scheme_poly_cons(ao_scheme_arg(cons, 0)));
+}
+
+ao_poly
+ao_scheme_do_string_to_list(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_string2d3elist, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_string2d3elist, cons, 0, AO_SCHEME_STRING, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_string_unpack(ao_scheme_poly_string(ao_scheme_arg(cons, 0)));
+}
+
+ao_poly
+ao_scheme_do_string_ref(struct ao_scheme_cons *cons)
+{
+       char *string;
+       int32_t ref;
+       if (!ao_scheme_check_argc(_ao_scheme_atom_string2dref, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_string2dref, cons, 0, AO_SCHEME_STRING, 0))
+               return AO_SCHEME_NIL;
+       ref = ao_scheme_arg_int(_ao_scheme_atom_string2dref, cons, 1);
+       if (ref == AO_SCHEME_NOT_INTEGER)
+               return AO_SCHEME_NIL;
+       string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
+       while (*string && ref) {
+               ++string;
+               --ref;
+       }
+       if (!*string)
+               return ao_scheme_error(AO_SCHEME_INVALID, "%v: string %v ref %v invalid",
+                                      _ao_scheme_atom_string2dref,
+                                      ao_scheme_arg(cons, 0),
+                                      ao_scheme_arg(cons, 1));
+       return ao_scheme_int_poly(*string);
+}
+
+ao_poly
+ao_scheme_do_string_length(struct ao_scheme_cons *cons)
+{
+       char *string;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_string2dlength, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_string2dlength, cons, 0, AO_SCHEME_STRING, 0))
+               return AO_SCHEME_NIL;
+       string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
+       return ao_scheme_integer_poly(strlen(string));
+}
+
+ao_poly
+ao_scheme_do_string_copy(struct ao_scheme_cons *cons)
+{
+       char *string;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_string2dcopy, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_string2dcopy, cons, 0, AO_SCHEME_STRING, 0))
+               return AO_SCHEME_NIL;
+       string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
+       return ao_scheme_string_poly(ao_scheme_string_copy(string));
+}
+
+ao_poly
+ao_scheme_do_string_set(struct ao_scheme_cons *cons)
+{
+       char *string;
+       int32_t ref;
+       int32_t val;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_string2dset21, cons, 3, 3))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_string2dset21, cons, 0, AO_SCHEME_STRING, 0))
+               return AO_SCHEME_NIL;
+       string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
+       ref = ao_scheme_arg_int(_ao_scheme_atom_string2dset21, cons, 1);
+       if (ref == AO_SCHEME_NOT_INTEGER)
+               return AO_SCHEME_NIL;
+       val = ao_scheme_arg_int(_ao_scheme_atom_string2dset21, cons, 2);
+       if (val == AO_SCHEME_NOT_INTEGER)
+               return AO_SCHEME_NIL;
+       while (*string && ref) {
+               ++string;
+               --ref;
+       }
+       if (!*string)
+               return ao_scheme_error(AO_SCHEME_INVALID, "%v: string %v ref %v invalid",
+                                      _ao_scheme_atom_string2dset21,
+                                      ao_scheme_arg(cons, 0),
+                                      ao_scheme_arg(cons, 1));
+       *string = val;
+       return ao_scheme_int_poly(*string);
+}
+
+ao_poly
+ao_scheme_do_flush_output(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_flush2doutput, cons, 0, 0))
+               return AO_SCHEME_NIL;
+       ao_scheme_os_flush();
+       return _ao_scheme_bool_true;
+}
+
+ao_poly
+ao_scheme_do_led(struct ao_scheme_cons *cons)
+{
+       int32_t led;
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       led = ao_scheme_arg_int(_ao_scheme_atom_led, cons, 0);
+       if (led == AO_SCHEME_NOT_INTEGER)
+               return AO_SCHEME_NIL;
+       led = ao_scheme_arg(cons, 0);
+       ao_scheme_os_led(ao_scheme_poly_int(led));
+       return led;
+}
+
+ao_poly
+ao_scheme_do_delay(struct ao_scheme_cons *cons)
+{
+       int32_t delay;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_delay, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       delay = ao_scheme_arg_int(_ao_scheme_atom_delay, cons, 0);
+       if (delay == AO_SCHEME_NOT_INTEGER)
+               return AO_SCHEME_NIL;
+       ao_scheme_os_delay(delay);
+       return delay;
+}
+
+ao_poly
+ao_scheme_do_eval(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_eval, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       ao_scheme_stack->state = eval_sexpr;
+       return cons->car;
+}
+
+ao_poly
+ao_scheme_do_apply(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_apply, cons, 2, INT_MAX))
+               return AO_SCHEME_NIL;
+       ao_scheme_stack->state = eval_apply;
+       return ao_scheme_cons_poly(cons);
+}
+
+ao_poly
+ao_scheme_do_read(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_read, cons, 0, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_read();
+}
+
+ao_poly
+ao_scheme_do_collect(struct ao_scheme_cons *cons)
+{
+       int     free;
+       (void) cons;
+       free = ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
+       return ao_scheme_integer_poly(free);
+}
+
+ao_poly
+ao_scheme_do_nullp(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (ao_scheme_arg(cons, 0) == AO_SCHEME_NIL)
+               return _ao_scheme_bool_true;
+       else
+               return _ao_scheme_bool_false;
+}
+
+ao_poly
+ao_scheme_do_not(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (ao_scheme_arg(cons, 0) == _ao_scheme_bool_false)
+               return _ao_scheme_bool_true;
+       else
+               return _ao_scheme_bool_false;
+}
+
+static ao_poly
+ao_scheme_do_typep(int type, struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == type)
+               return _ao_scheme_bool_true;
+       return _ao_scheme_bool_false;
+}
+
+ao_poly
+ao_scheme_do_pairp(struct ao_scheme_cons *cons)
+{
+       ao_poly v;
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       v = ao_scheme_arg(cons, 0);
+       if (v != AO_SCHEME_NIL && ao_scheme_poly_type(v) == AO_SCHEME_CONS)
+               return _ao_scheme_bool_true;
+       return _ao_scheme_bool_false;
+}
+
+ao_poly
+ao_scheme_do_integerp(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
+       case AO_SCHEME_INT:
+       case AO_SCHEME_BIGINT:
+               return _ao_scheme_bool_true;
+       default:
+               return _ao_scheme_bool_false;
+       }
+}
+
+ao_poly
+ao_scheme_do_numberp(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
+       case AO_SCHEME_INT:
+       case AO_SCHEME_BIGINT:
+       case AO_SCHEME_FLOAT:
+               return _ao_scheme_bool_true;
+       default:
+               return _ao_scheme_bool_false;
+       }
+}
+
+ao_poly
+ao_scheme_do_stringp(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_do_typep(AO_SCHEME_STRING, cons);
+}
+
+ao_poly
+ao_scheme_do_symbolp(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_do_typep(AO_SCHEME_ATOM, cons);
+}
+
+ao_poly
+ao_scheme_do_booleanp(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_do_typep(AO_SCHEME_BOOL, cons);
+}
+
+ao_poly
+ao_scheme_do_procedurep(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
+       case AO_SCHEME_BUILTIN:
+       case AO_SCHEME_LAMBDA:
+               return _ao_scheme_bool_true;
+       default:
+       return _ao_scheme_bool_false;
+       }
+}
+
+/* This one is special -- a list is either nil or
+ * a 'proper' list with only cons cells
+ */
+ao_poly
+ao_scheme_do_listp(struct ao_scheme_cons *cons)
+{
+       ao_poly v;
+       if (!ao_scheme_check_argc(_ao_scheme_atom_list3f, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       v = ao_scheme_arg(cons, 0);
+       for (;;) {
+               if (v == AO_SCHEME_NIL)
+                       return _ao_scheme_bool_true;
+               if (ao_scheme_poly_type(v) != AO_SCHEME_CONS)
+                       return _ao_scheme_bool_false;
+               v = ao_scheme_poly_cons(v)->cdr;
+       }
+}
+
+ao_poly
+ao_scheme_do_set_car(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->car = ao_scheme_arg(cons, 1);
+}
+
+ao_poly
+ao_scheme_do_set_cdr(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->cdr = ao_scheme_arg(cons, 1);
+}
+
+ao_poly
+ao_scheme_do_symbol_to_string(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_ATOM, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_string_poly(ao_scheme_string_copy(ao_scheme_poly_atom(ao_scheme_arg(cons, 0))->name));
+}
+
+ao_poly
+ao_scheme_do_string_to_symbol(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_STRING, 0))
+               return AO_SCHEME_NIL;
+
+       return ao_scheme_atom_poly(ao_scheme_atom_intern(ao_scheme_poly_string(ao_scheme_arg(cons, 0))));
+}
+
+ao_poly
+ao_scheme_do_read_char(struct ao_scheme_cons *cons)
+{
+       int     c;
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
+               return AO_SCHEME_NIL;
+       c = getchar();
+       return ao_scheme_int_poly(c);
+}
+
+ao_poly
+ao_scheme_do_write_char(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_INT, 0))
+               return AO_SCHEME_NIL;
+       putchar(ao_scheme_poly_integer(ao_scheme_arg(cons, 0)));
+       return _ao_scheme_bool_true;
+}
+
+ao_poly
+ao_scheme_do_exit(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
+               return AO_SCHEME_NIL;
+       ao_scheme_exception |= AO_SCHEME_EXIT;
+       return _ao_scheme_bool_true;
+}
+
+ao_poly
+ao_scheme_do_current_jiffy(struct ao_scheme_cons *cons)
+{
+       int     jiffy;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
+               return AO_SCHEME_NIL;
+       jiffy = ao_scheme_os_jiffy();
+       return (ao_scheme_int_poly(jiffy));
+}
+
+ao_poly
+ao_scheme_do_current_second(struct ao_scheme_cons *cons)
+{
+       int     second;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
+               return AO_SCHEME_NIL;
+       second = ao_scheme_os_jiffy() / AO_SCHEME_JIFFIES_PER_SECOND;
+       return (ao_scheme_int_poly(second));
+}
+
+ao_poly
+ao_scheme_do_jiffies_per_second(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
+               return AO_SCHEME_NIL;
+       return (ao_scheme_int_poly(AO_SCHEME_JIFFIES_PER_SECOND));
+}
+
+ao_poly
+ao_scheme_do_vector(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_vector_poly(ao_scheme_list_to_vector(cons));
+}
+
+ao_poly
+ao_scheme_do_make_vector(struct ao_scheme_cons *cons)
+{
+       int32_t k;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_make2dvector, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       k = ao_scheme_arg_int(_ao_scheme_atom_make2dvector, cons, 0);
+       if (k == AO_SCHEME_NOT_INTEGER)
+               return AO_SCHEME_NIL;
+       return ao_scheme_vector_poly(ao_scheme_vector_alloc(k, ao_scheme_arg(cons, 1)));
+}
+
+ao_poly
+ao_scheme_do_vector_ref(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dref, cons, 2, 2))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dref, cons, 0, AO_SCHEME_VECTOR, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_vector_get(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
+}
+
+ao_poly
+ao_scheme_do_vector_set(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dset21, cons, 3, 3))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dset21, cons, 0, AO_SCHEME_VECTOR, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_vector_set(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1), ao_scheme_arg(cons, 2));
+}
+
+ao_poly
+ao_scheme_do_list_to_vector(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3evector, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3evector, cons, 0, AO_SCHEME_CONS, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_vector_poly(ao_scheme_list_to_vector(ao_scheme_poly_cons(ao_scheme_arg(cons, 0))));
+}
+
+ao_poly
+ao_scheme_do_vector_to_list(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_cons_poly(ao_scheme_vector_to_list(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))));
+}
+
+ao_poly
+ao_scheme_do_vector_length(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
+               return AO_SCHEME_NIL;
+       return ao_scheme_integer_poly(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))->length);
+}
+
+ao_poly
+ao_scheme_do_vectorp(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_do_typep(AO_SCHEME_VECTOR, cons);
+}
+
+#define AO_SCHEME_BUILTIN_FUNCS
+#include "ao_scheme_builtin.h"
diff --git a/src/scheme/ao_scheme_builtin.txt b/src/scheme/ao_scheme_builtin.txt
new file mode 100644 (file)
index 0000000..17f5ea0
--- /dev/null
@@ -0,0 +1,81 @@
+f_lambda       eval
+f_lambda       read
+nlambda                lambda
+nlambda                nlambda
+nlambda                macro
+f_lambda       car
+f_lambda       cdr
+f_lambda       cons
+f_lambda       last
+f_lambda       length
+f_lambda       list_copy       list-copy
+nlambda                quote
+atom           quasiquote
+atom           unquote
+atom           unquote_splicing        unquote-splicing
+f_lambda       set
+macro          setq            set!
+f_lambda       def
+nlambda                cond
+nlambda                begin
+nlambda                while
+f_lambda       write
+f_lambda       display
+f_lambda       plus            +       string-append
+f_lambda       minus           -
+f_lambda       times           *
+f_lambda       divide          /
+f_lambda       modulo          modulo  %
+f_lambda       remainder
+f_lambda       quotient
+f_lambda       equal           =       eq?     eqv?
+f_lambda       less            <       string<?
+f_lambda       greater         >       string>?
+f_lambda       less_equal      <=      string<=?
+f_lambda       greater_equal   >=      string>=?
+f_lambda       flush_output            flush-output
+f_lambda       delay
+f_lambda       led
+f_lambda       save
+f_lambda       restore
+f_lambda       call_cc         call-with-current-continuation  call/cc
+f_lambda       collect
+f_lambda       nullp           null?
+f_lambda       not
+f_lambda       listp           list?
+f_lambda       pairp           pair?
+f_lambda       integerp        integer? exact? exact-integer?
+f_lambda       numberp         number? real?
+f_lambda       booleanp        boolean?
+f_lambda       set_car         set-car!
+f_lambda       set_cdr         set-cdr!
+f_lambda       symbolp         symbol?
+f_lambda       list_to_string          list->string
+f_lambda       string_to_list          string->list
+f_lambda       symbol_to_string        symbol->string
+f_lambda       string_to_symbol        string->symbol
+f_lambda       stringp         string?
+f_lambda       string_ref      string-ref
+f_lambda       string_set      string-set!
+f_lambda       string_copy     string-copy
+f_lambda       string_length   string-length
+f_lambda       procedurep      procedure?
+lambda         apply
+f_lambda       read_char       read-char
+f_lambda       write_char      write-char
+f_lambda       exit
+f_lambda       current_jiffy   current-jiffy
+f_lambda       current_second  current-second
+f_lambda       jiffies_per_second      jiffies-per-second
+f_lambda       finitep         finite?
+f_lambda       infinitep       infinite?
+f_lambda       inexactp        inexact?
+f_lambda       sqrt
+f_lambda       vector_ref      vector-ref
+f_lambda       vector_set      vector-set!
+f_lambda       vector
+f_lambda       make_vector     make-vector
+f_lambda       list_to_vector  list->vector
+f_lambda       vector_to_list  vector->list
+f_lambda       vector_length   vector-length
+f_lambda       vectorp         vector?
diff --git a/src/scheme/ao_scheme_cons.c b/src/scheme/ao_scheme_cons.c
new file mode 100644 (file)
index 0000000..02512e1
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
+static void cons_mark(void *addr)
+{
+       struct ao_scheme_cons   *cons = addr;
+
+       for (;;) {
+               ao_poly cdr = cons->cdr;
+
+               ao_scheme_poly_mark(cons->car, 1);
+               if (!cdr)
+                       break;
+               if (ao_scheme_poly_type(cdr) != AO_SCHEME_CONS) {
+                       ao_scheme_poly_mark(cdr, 1);
+                       break;
+               }
+               cons = ao_scheme_poly_cons(cdr);
+               if (ao_scheme_mark_memory(&ao_scheme_cons_type, cons))
+                       break;
+       }
+}
+
+static int cons_size(void *addr)
+{
+       (void) addr;
+       return sizeof (struct ao_scheme_cons);
+}
+
+static void cons_move(void *addr)
+{
+       struct ao_scheme_cons   *cons = addr;
+
+       if (!cons)
+               return;
+
+       for (;;) {
+               ao_poly                 cdr;
+               struct ao_scheme_cons   *c;
+               int     ret;
+
+               MDBG_MOVE("cons_move start %d (%d, %d)\n",
+                         MDBG_OFFSET(cons), MDBG_OFFSET(ao_scheme_ref(cons->car)), MDBG_OFFSET(ao_scheme_ref(cons->cdr)));
+               (void) ao_scheme_poly_move(&cons->car, 1);
+               cdr = cons->cdr;
+               if (!cdr)
+                       break;
+               if (ao_scheme_poly_base_type(cdr) != AO_SCHEME_CONS) {
+                       (void) ao_scheme_poly_move(&cons->cdr, 0);
+                       break;
+               }
+               c = ao_scheme_poly_cons(cdr);
+               ret = ao_scheme_move_memory(&ao_scheme_cons_type, (void **) &c);
+               if (c != ao_scheme_poly_cons(cons->cdr))
+                       cons->cdr = ao_scheme_cons_poly(c);
+               MDBG_MOVE("cons_move end %d (%d, %d)\n",
+                         MDBG_OFFSET(cons), MDBG_OFFSET(ao_scheme_ref(cons->car)), MDBG_OFFSET(ao_scheme_ref(cons->cdr)));
+               if (ret)
+                       break;
+               cons = c;
+       }
+}
+
+const struct ao_scheme_type ao_scheme_cons_type = {
+       .mark = cons_mark,
+       .size = cons_size,
+       .move = cons_move,
+       .name = "cons",
+};
+
+struct ao_scheme_cons *ao_scheme_cons_free_list;
+
+struct ao_scheme_cons *
+ao_scheme_cons_cons(ao_poly car, ao_poly cdr)
+{
+       struct ao_scheme_cons   *cons;
+
+       if (ao_scheme_cons_free_list) {
+               cons = ao_scheme_cons_free_list;
+               ao_scheme_cons_free_list = ao_scheme_poly_cons(cons->cdr);
+       } else {
+               ao_scheme_poly_stash(0, car);
+               ao_scheme_poly_stash(1, cdr);
+               cons = ao_scheme_alloc(sizeof (struct ao_scheme_cons));
+               cdr = ao_scheme_poly_fetch(1);
+               car = ao_scheme_poly_fetch(0);
+               if (!cons)
+                       return NULL;
+       }
+       cons->car = car;
+       cons->cdr = cdr;
+       return cons;
+}
+
+struct ao_scheme_cons *
+ao_scheme_cons_cdr(struct ao_scheme_cons *cons)
+{
+       ao_poly cdr = cons->cdr;
+       if (cdr == AO_SCHEME_NIL)
+               return NULL;
+       if (ao_scheme_poly_type(cdr) != AO_SCHEME_CONS) {
+               (void) ao_scheme_error(AO_SCHEME_INVALID, "improper cdr %v", cdr);
+               return NULL;
+       }
+       return ao_scheme_poly_cons(cdr);
+}
+
+ao_poly
+ao_scheme__cons(ao_poly car, ao_poly cdr)
+{
+       return ao_scheme_cons_poly(ao_scheme_cons_cons(car, cdr));
+}
+
+struct ao_scheme_cons *
+ao_scheme_cons_copy(struct ao_scheme_cons *cons)
+{
+       struct ao_scheme_cons   *head = NULL;
+       struct ao_scheme_cons   *tail = NULL;
+
+       while (cons) {
+               struct ao_scheme_cons   *new;
+               ao_poly cdr;
+
+               ao_scheme_cons_stash(0, cons);
+               ao_scheme_cons_stash(1, head);
+               ao_scheme_poly_stash(0, ao_scheme_cons_poly(tail));
+               new = ao_scheme_alloc(sizeof (struct ao_scheme_cons));
+               cons = ao_scheme_cons_fetch(0);
+               head = ao_scheme_cons_fetch(1);
+               tail = ao_scheme_poly_cons(ao_scheme_poly_fetch(0));
+               if (!new)
+                       return AO_SCHEME_NIL;
+               new->car = cons->car;
+               new->cdr = AO_SCHEME_NIL;
+               if (!head)
+                       head = new;
+               else
+                       tail->cdr = ao_scheme_cons_poly(new);
+               tail = new;
+               cdr = cons->cdr;
+               if (ao_scheme_poly_type(cdr) != AO_SCHEME_CONS) {
+                       tail->cdr = cdr;
+                       break;
+               }
+               cons = ao_scheme_poly_cons(cdr);
+       }
+       return head;
+}
+
+void
+ao_scheme_cons_free(struct ao_scheme_cons *cons)
+{
+#if DBG_FREE_CONS
+       ao_scheme_cons_check(cons);
+#endif
+       while (cons) {
+               ao_poly cdr = cons->cdr;
+               cons->cdr = ao_scheme_cons_poly(ao_scheme_cons_free_list);
+               ao_scheme_cons_free_list = cons;
+               cons = ao_scheme_poly_cons(cdr);
+       }
+}
+
+void
+ao_scheme_cons_write(ao_poly c)
+{
+       struct ao_scheme_cons   *cons = ao_scheme_poly_cons(c);
+       ao_poly                 cdr;
+       int                     first = 1;
+
+       printf("(");
+       while (cons) {
+               if (!first)
+                       printf(" ");
+               ao_scheme_poly_write(cons->car);
+               cdr = cons->cdr;
+               if (cdr == c) {
+                       printf(" ...");
+                       break;
+               }
+               if (ao_scheme_poly_type(cdr) == AO_SCHEME_CONS) {
+                       cons = ao_scheme_poly_cons(cdr);
+                       first = 0;
+               } else {
+                       printf(" . ");
+                       ao_scheme_poly_write(cdr);
+                       cons = NULL;
+               }
+       }
+       printf(")");
+}
+
+void
+ao_scheme_cons_display(ao_poly c)
+{
+       struct ao_scheme_cons   *cons = ao_scheme_poly_cons(c);
+       ao_poly                 cdr;
+
+       while (cons) {
+               ao_scheme_poly_display(cons->car);
+               cdr = cons->cdr;
+               if (cdr == c) {
+                       printf("...");
+                       break;
+               }
+               if (ao_scheme_poly_type(cdr) == AO_SCHEME_CONS)
+                       cons = ao_scheme_poly_cons(cdr);
+               else {
+                       ao_scheme_poly_display(cdr);
+                       cons = NULL;
+               }
+       }
+}
+
+int
+ao_scheme_cons_length(struct ao_scheme_cons *cons)
+{
+       int     len = 0;
+       while (cons) {
+               len++;
+               cons = ao_scheme_cons_cdr(cons);
+       }
+       return len;
+}
diff --git a/src/scheme/ao_scheme_const.scheme b/src/scheme/ao_scheme_const.scheme
new file mode 100644 (file)
index 0000000..ab6a309
--- /dev/null
@@ -0,0 +1,813 @@
+;
+; 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.
+;
+; Lisp code placed in ROM
+
+                                       ; return a list containing all of the arguments
+(def (quote list) (lambda l l))
+
+(def (quote def!)
+     (macro (name value)
+           (list
+            def
+            (list quote name)
+            value)
+           )
+     )
+
+(begin
+ (def! append
+   (lambda args
+         (def! append-list
+           (lambda (a b)
+             (cond ((null? a) b)
+                   (else (cons (car a) (append-list (cdr a) b)))
+                   )
+             )
+           )
+           
+         (def! append-lists
+           (lambda (lists)
+             (cond ((null? lists) lists)
+                   ((null? (cdr lists)) (car lists))
+                   (else (append-list (car lists) (append-lists (cdr lists))))
+                   )
+             )
+           )
+         (append-lists args)
+         )
+   )
+ 'append)
+
+(append '(a b c) '(d e f) '(g h i))
+
+                                       ; boolean operators
+
+(begin
+ (def! or
+   (macro l
+         (def! _or
+           (lambda (l)
+             (cond ((null? l) #f)
+                   ((null? (cdr l))
+                    (car l))
+                   (else
+                    (list
+                     cond
+                     (list
+                      (car l))
+                     (list
+                      'else
+                      (_or (cdr l))
+                      )
+                     )
+                    )
+                   )
+             )
+           )
+         (_or l)))
+ 'or)
+
+                                       ; execute to resolve macros
+
+(or #f #t)
+
+(begin
+ (def! and
+   (macro l
+         (def! _and
+           (lambda (l)
+             (cond ((null? l) #t)
+                   ((null? (cdr l))
+                    (car l))
+                   (else
+                    (list
+                     cond
+                     (list
+                      (car l)
+                      (_and (cdr l))
+                      )
+                     )
+                    )
+                   )
+             )
+           )
+         (_and l)
+         )
+   )
+ 'and)
+
+                                       ; execute to resolve macros
+
+(and #t #f)
+
+(begin
+ (def! quasiquote
+   (macro (x)
+         (def! constant?
+                                       ; A constant value is either a pair starting with quote,
+                                       ; or anything which is neither a pair nor a symbol
+
+           (lambda (exp)
+             (cond ((pair? exp)
+                    (eq? (car exp) 'quote)
+                    )
+                   (else
+                    (not (symbol? exp))
+                    )
+                   )
+             )
+           )
+         (def! combine-skeletons
+           (lambda (left right exp)
+             (cond
+              ((and (constant? left) (constant? right)) 
+               (cond ((and (eqv? (eval left) (car exp))
+                           (eqv? (eval right) (cdr exp)))
+                      (list 'quote exp)
+                      )
+                     (else
+                      (list 'quote (cons (eval left) (eval right)))
+                      )
+                     )
+               )
+              ((null? right)
+               (list 'list left)
+               )
+              ((and (pair? right) (eq? (car right) 'list))
+               (cons 'list (cons left (cdr right)))
+               )
+              (else
+               (list 'cons left right)
+               )
+              )
+             )
+           )
+
+         (def! expand-quasiquote
+           (lambda (exp nesting)
+             (cond
+
+                                       ; non cons -- constants
+                                       ; themselves, others are
+                                       ; quoted
+
+              ((not (pair? exp)) 
+               (cond ((constant? exp)
+                      exp
+                      )
+                     (else
+                      (list 'quote exp)
+                      )
+                     )
+               )
+
+                                       ; check for an unquote exp and
+                                       ; add the param unquoted
+
+              ((and (eq? (car exp) 'unquote) (= (length exp) 2))
+               (cond ((= nesting 0)
+                      (car (cdr exp))
+                      )
+                     (else
+                      (combine-skeletons ''unquote 
+                                         (expand-quasiquote (cdr exp) (- nesting 1))
+                                         exp))
+                     )
+               )
+
+                                       ; nested quasi-quote --
+                                       ; construct the right
+                                       ; expression
+
+              ((and (eq? (car exp) 'quasiquote) (= (length exp) 2))
+               (combine-skeletons ''quasiquote 
+                                  (expand-quasiquote (cdr exp) (+ nesting 1))
+                                  exp))
+
+                                       ; check for an
+                                       ; unquote-splicing member,
+                                       ; compute the expansion of the
+                                       ; value and append the rest of
+                                       ; the quasiquote result to it
+
+              ((and (pair? (car exp))
+                    (eq? (car (car exp)) 'unquote-splicing)
+                    (= (length (car exp)) 2))
+               (cond ((= nesting 0)
+                      (list 'append (car (cdr (car exp)))
+                            (expand-quasiquote (cdr exp) nesting))
+                      )
+                     (else
+                      (combine-skeletons (expand-quasiquote (car exp) (- nesting 1))
+                                         (expand-quasiquote (cdr exp) nesting)
+                                         exp))
+                     )
+               )
+
+                                       ; for other lists, just glue
+                                       ; the expansion of the first
+                                       ; element to the expansion of
+                                       ; the rest of the list
+
+              (else (combine-skeletons (expand-quasiquote (car exp) nesting)
+                                       (expand-quasiquote (cdr exp) nesting)
+                                       exp)
+                    )
+              )
+             )
+           )
+         (def! result (expand-quasiquote x 0))
+         result
+         )
+   )
+ 'quasiquote)
+
+                                       ;
+                                       ; Define a variable without returning the value
+                                       ; Useful when defining functions to avoid
+                                       ; having lots of output generated.
+                                       ;
+                                       ; Also accepts the alternate
+                                       ; form for defining lambdas of
+                                       ; (define (name x y z) sexprs ...) 
+                                       ;
+
+(begin
+ (def! define
+   (macro (first . rest)
+                                       ; check for alternate lambda definition form
+
+         (cond ((list? first)
+                (set! rest
+                      (append
+                       (list
+                        'lambda
+                        (cdr first))
+                       rest))
+                (set! first (car first))
+                )
+               (else
+                (set! rest (car rest))
+                )
+               )
+         (def! result `(,begin
+                        (,def (,quote ,first) ,rest)
+                        (,quote ,first))
+           )
+         result
+         )
+   )
+ 'define
+ )
+
+                                       ; basic list accessors
+
+(define (caar l) (car (car l)))
+
+(define (cadr l) (car (cdr l)))
+
+(define (cdar l) (cdr (car l)))
+
+(define (caddr l) (car (cdr (cdr l))))
+
+                                       ; (if <condition> <if-true>)
+                                       ; (if <condition> <if-true> <if-false)
+
+(define if
+  (macro (test . args)
+        (cond ((null? (cdr args))
+               `(cond (,test ,(car args)))
+               )
+              (else
+               `(cond (,test ,(car args))
+                      (else ,(cadr args)))
+               )
+              )
+        )
+  )
+
+(if (> 3 2) 'yes)
+(if (> 3 2) 'yes 'no)
+(if (> 2 3) 'no 'yes)
+(if (> 2 3) 'no)
+
+                                       ; simple math operators
+
+(define zero? (macro (value) `(eq? ,value 0)))
+
+(zero? 1)
+(zero? 0)
+(zero? "hello")
+
+(define positive? (macro (value) `(> ,value 0)))
+
+(positive? 12)
+(positive? -12)
+
+(define negative? (macro (value) `(< ,value 0)))
+
+(negative? 12)
+(negative? -12)
+
+(define (abs x) (if (>= x 0) x (- x)))
+
+(abs 12)
+(abs -12)
+
+(define max (lambda (first . rest)
+                  (while (not (null? rest))
+                    (cond ((< first (car rest))
+                           (set! first (car rest)))
+                          )
+                    (set! rest (cdr rest))
+                    )
+                  first)
+  )
+
+(max 1 2 3)
+(max 3 2 1)
+
+(define min (lambda (first . rest)
+                  (while (not (null? rest))
+                    (cond ((> first (car rest))
+                           (set! first (car rest)))
+                          )
+                    (set! rest (cdr rest))
+                    )
+                  first)
+  )
+
+(min 1 2 3)
+(min 3 2 1)
+
+(define (even? x) (zero? (% x 2)))
+
+(even? 2)
+(even? -2)
+(even? 3)
+(even? -1)
+
+(define (odd? x) (not (even? x)))
+
+(odd? 2)
+(odd? -2)
+(odd? 3)
+(odd? -1)
+
+
+(define (list-tail x k)
+  (if (zero? k)
+      x
+    (list-tail (cdr x (- k 1)))
+    )
+  )
+
+(define (list-ref x k)
+  (car (list-tail x k))
+  )
+
+                                       ; define a set of local
+                                       ; variables all at once and
+                                       ; then evaluate a list of
+                                       ; sexprs
+                                       ;
+                                       ; (let (var-defines) sexprs)
+                                       ;
+                                       ; where var-defines are either
+                                       ;
+                                       ; (name value)
+                                       ;
+                                       ; or
+                                       ;
+                                       ; (name)
+                                       ;
+                                       ; e.g.
+                                       ;
+                                       ; (let ((x 1) (y)) (set! y (+ x 1)) y)
+
+(define let
+  (macro (vars . exprs)
+        (define (make-names vars)
+          (cond ((not (null? vars))
+                 (cons (car (car vars))
+                       (make-names (cdr vars))))
+                (else ())
+                )
+          )
+
+                                       ; the parameters to the lambda is a list
+                                       ; of nils of the right length
+
+        (define (make-vals vars)
+          (cond ((not (null? vars))
+                 (cons (cond ((null? (cdr (car vars))) ())
+                             (else
+                              (car (cdr (car vars))))
+                             )
+                       (make-vals (cdr vars))))
+                (else ())
+                )
+          )
+                                       ; prepend the set operations
+                                       ; to the expressions
+
+                                       ; build the lambda.
+
+        `((lambda ,(make-names vars) ,@exprs) ,@(make-vals vars))
+        )
+     )
+                  
+
+(let ((x 1) (y)) (set! y 2) (+ x y))
+
+                                       ; define a set of local
+                                       ; variables one at a time and
+                                       ; then evaluate a list of
+                                       ; sexprs
+                                       ;
+                                       ; (let* (var-defines) sexprs)
+                                       ;
+                                       ; where var-defines are either
+                                       ;
+                                       ; (name value)
+                                       ;
+                                       ; or
+                                       ;
+                                       ; (name)
+                                       ;
+                                       ; e.g.
+                                       ;
+                                       ; (let* ((x 1) (y)) (set! y (+ x 1)) y)
+
+(define let*
+  (macro (vars . exprs)
+
+                                       ;
+                                       ; make the list of names in the let
+                                       ;
+
+        (define (make-names vars)
+          (cond ((not (null? vars))
+                 (cons (car (car vars))
+                       (make-names (cdr vars))))
+                (else ())
+                )
+          )
+
+                                       ; the set of expressions is
+                                       ; the list of set expressions
+                                       ; pre-pended to the
+                                       ; expressions to evaluate
+
+        (define (make-exprs vars exprs)
+          (cond ((null? vars) exprs)
+                (else
+                 (cons
+                  (list set
+                        (list quote
+                              (car (car vars))
+                              )
+                        (cond ((null? (cdr (car vars))) ())
+                              (else (cadr (car vars))))
+                        )
+                  (make-exprs (cdr vars) exprs)
+                  )
+                 )
+                )
+          )
+
+                                       ; the parameters to the lambda is a list
+                                       ; of nils of the right length
+
+        (define (make-nils vars)
+          (cond ((null? vars) ())
+                (else (cons () (make-nils (cdr vars))))
+                )
+          )
+                                       ; build the lambda.
+
+        `((lambda ,(make-names vars) ,@(make-exprs vars exprs)) ,@(make-nils vars))
+        )
+     )
+
+(let* ((x 1) (y x)) (+ x y))
+
+(define when (macro (test . l) `(cond (,test ,@l))))
+
+(when #t (write 'when))
+
+(define unless (macro (test . l) `(cond ((not ,test) ,@l))))
+
+(unless #f (write 'unless))
+
+(define (reverse list)
+  (let ((result ()))
+    (while (not (null? list))
+      (set! result (cons (car list) result))
+      (set! list (cdr list))
+      )
+    result)
+  )
+
+(reverse '(1 2 3))
+
+(define (list-tail x k)
+  (if (zero? k)
+      x
+    (list-tail (cdr x) (- k 1))))
+
+(list-tail '(1 2 3) 2)
+
+(define (list-ref x k) (car (list-tail x k)))
+
+(list-ref '(1 2 3) 2)
+    
+                                       ; recursive equality
+
+(define (equal? a b)
+  (cond ((eq? a b) #t)
+       ((and (pair? a) (pair? b))
+        (and (equal? (car a) (car b))
+             (equal? (cdr a) (cdr b)))
+        )
+       (else #f)
+       )
+  )
+
+(equal? '(a b c) '(a b c))
+(equal? '(a b c) '(a b b))
+
+(define member (lambda (obj list . test?)
+                     (cond ((null? list)
+                            #f
+                            )
+                           (else
+                            (if (null? test?) (set! test? equal?) (set! test? (car test?)))
+                            (if (test? obj (car list))
+                                list
+                              (member obj (cdr list) test?))
+                            )
+                           )
+                     )
+  )
+
+(member '(2) '((1) (2) (3)))
+
+(member '(4) '((1) (2) (3)))
+
+(define (memq obj list) (member obj list eq?))
+
+(memq 2 '(1 2 3))
+
+(memq 4 '(1 2 3))
+
+(memq '(2) '((1) (2) (3)))
+
+(define (memv obj list) (member obj list eqv?))
+
+(memv 2 '(1 2 3))
+
+(memv 4 '(1 2 3))
+
+(memv '(2) '((1) (2) (3)))
+
+(define (_assoc obj list test?)
+  (if (null? list)
+      #f
+    (if (test? obj (caar list))
+       (car list)
+      (_assoc obj (cdr list) test?)
+      )
+    )
+  )
+
+(define (assq obj list) (_assoc obj list eq?))
+(define (assv obj list) (_assoc obj list eqv?))
+(define (assoc obj list) (_assoc obj list equal?))
+
+(assq 'a '((a 1) (b 2) (c 3)))
+(assv 'b '((a 1) (b 2) (c 3)))
+(assoc '(c) '((a 1) (b 2) ((c) 3)))
+
+(define char? integer?)
+
+(char? #\q)
+(char? "h")
+
+(define (char-upper-case? c) (<= #\A c #\Z))
+
+(char-upper-case? #\a)
+(char-upper-case? #\B)
+(char-upper-case? #\0)
+(char-upper-case? #\space)
+
+(define (char-lower-case? c) (<= #\a c #\a))
+
+(char-lower-case? #\a)
+(char-lower-case? #\B)
+(char-lower-case? #\0)
+(char-lower-case? #\space)
+
+(define (char-alphabetic? c) (or (char-upper-case? c) (char-lower-case? c)))
+
+(char-alphabetic? #\a)
+(char-alphabetic? #\B)
+(char-alphabetic? #\0)
+(char-alphabetic? #\space)
+
+(define (char-numeric? c) (<= #\0 c #\9))
+
+(char-numeric? #\a)
+(char-numeric? #\B)
+(char-numeric? #\0)
+(char-numeric? #\space)
+
+(define (char-whitespace? c) (or (<= #\tab c #\return) (= #\space c)))
+
+(char-whitespace? #\a)
+(char-whitespace? #\B)
+(char-whitespace? #\0)
+(char-whitespace? #\space)
+
+(define (char->integer c) c)
+(define integer->char char->integer)
+
+(define (char-upcase c) (if (char-lower-case? c) (+ c (- #\A #\a)) c))
+
+(char-upcase #\a)
+(char-upcase #\B)
+(char-upcase #\0)
+(char-upcase #\space)
+
+(define (char-downcase c) (if (char-upper-case? c) (+ c (- #\a #\A)) c))
+
+(char-downcase #\a)
+(char-downcase #\B)
+(char-downcase #\0)
+(char-downcase #\space)
+
+(define string (lambda chars (list->string chars)))
+
+(display "apply\n")
+(apply cons '(a b))
+
+(define map
+  (lambda (proc . lists)
+        (define (args lists)
+          (cond ((null? lists) ())
+                (else
+                 (cons (caar lists) (args (cdr lists)))
+                 )
+                )
+          )
+        (define (next lists)
+          (cond ((null? lists) ())
+                (else
+                 (cons (cdr (car lists)) (next (cdr lists)))
+                 )
+                )
+          )
+        (define (domap lists)
+          (cond ((null? (car lists)) ())
+                (else
+                 (cons (apply proc (args lists)) (domap (next lists)))
+                 )
+                )
+          )
+        (domap lists)
+        )
+  )
+
+(map cadr '((a b) (d e) (g h)))
+
+(define for-each (lambda (proc . lists)
+                       (apply map proc lists)
+                       #t))
+
+(for-each display '("hello" " " "world" "\n"))
+
+(define (_string-ml strings)
+  (if (null? strings) ()
+    (cons (string->list (car strings)) (_string-ml (cdr strings)))
+    )
+  )
+
+(define string-map (lambda (proc . strings)
+                         (list->string (apply map proc (_string-ml strings))))))
+
+(string-map (lambda (x) (+ 1 x)) "HAL")
+
+(define string-for-each (lambda (proc . strings)
+                              (apply for-each proc (_string-ml strings))))
+
+(string-for-each write-char "IBM\n")
+
+(define (newline) (write-char #\newline))
+
+(newline)
+
+(call-with-current-continuation
+ (lambda (exit)
+   (for-each (lambda (x)
+              (write "test" x)
+              (if (negative? x)
+                  (exit x)))
+            '(54 0 37 -3 245 19))
+   #t))
+
+
+                                       ; `q -> (quote q)
+                                       ; `(q) -> (append (quote (q)))
+                                       ; `(a ,(+ 1 2)) -> (append (quote (a)) (list (+ 1 2)))
+                                       ; `(a ,@(list 1 2 3) -> (append (quote (a)) (list 1 2 3))
+
+
+
+`(hello ,(+ 1 2) ,@(list 1 2 3) `foo)
+
+
+(define repeat
+  (macro (count . rest)
+        (define counter '__count__)
+        (cond ((pair? count)
+               (set! counter (car count))
+               (set! count (cadr count))
+               )
+              )
+        `(let ((,counter 0)
+               (__max__ ,count)
+               )
+           (while (< ,counter __max__)
+             ,@rest
+             (set! ,counter (+ ,counter 1))
+             )
+           )
+        )
+  )
+
+(repeat 2 (write 'hello))
+(repeat (x 3) (write 'goodbye x))
+
+(define case
+  (macro (test . l)
+                                       ; construct the body of the
+                                       ; case, dealing with the
+                                       ; lambda version ( => lambda)
+
+        (define (_unarrow l)
+          (cond ((null? l) l)
+                ((eq? (car l) '=>) `(( ,(cadr l) __key__)))
+                (else l))
+          )
+
+                                       ; Build the case elements, which is
+                                       ; simply a list of cond clauses
+
+        (define (_case l)
+
+          (cond ((null? l) ())
+
+                                       ; else case
+
+                ((eq? (caar l) 'else)
+                 `((else ,@(_unarrow (cdr (car l))))))
+
+                                       ; regular case
+                
+                (else
+                 (cons
+                  `((eqv? ,(caar l) __key__)
+                    ,@(_unarrow (cdr (car l))))
+                  (_case (cdr l)))
+                 )
+                )
+          )
+
+                                       ; now construct the overall
+                                       ; expression, using a lambda
+                                       ; to hold the computed value
+                                       ; of the test expression
+
+        `((lambda (__key__)
+            (cond ,@(_case l))) ,test)
+        )
+  )
+
+(case 12 (1 "one") (2 "two") (3 => (lambda (x) (write "the value is" x))) (12 "twelve") (else "else"))
+
+;(define number->string (lambda (arg . opt)
+;                            (let ((base (if (null? opt) 10 (car opt)))
+                                       ;
+;
+                               
diff --git a/src/scheme/ao_scheme_error.c b/src/scheme/ao_scheme_error.c
new file mode 100644 (file)
index 0000000..d580a2c
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+#include <stdarg.h>
+
+void
+ao_scheme_error_poly(char *name, ao_poly poly, ao_poly last)
+{
+       int first = 1;
+       printf("\t\t%s(", name);
+       if (ao_scheme_poly_type(poly) == AO_SCHEME_CONS) {
+               if (poly) {
+                       while (poly) {
+                               struct ao_scheme_cons *cons = ao_scheme_poly_cons(poly);
+                               if (!first)
+                                       printf("\t\t         ");
+                               else
+                                       first = 0;
+                               ao_scheme_poly_write(cons->car);
+                               printf("\n");
+                               if (poly == last)
+                                       break;
+                               poly = cons->cdr;
+                       }
+                       printf("\t\t         )\n");
+               } else
+                       printf(")\n");
+       } else {
+               ao_scheme_poly_write(poly);
+               printf("\n");
+       }
+}
+
+static void tabs(int indent)
+{
+       while (indent--)
+               printf("\t");
+}
+
+void
+ao_scheme_error_frame(int indent, char *name, struct ao_scheme_frame *frame)
+{
+       int                     f;
+
+       tabs(indent);
+       printf ("%s{", name);
+       if (frame) {
+               struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
+               if (frame->type & AO_SCHEME_FRAME_PRINT)
+                       printf("recurse...");
+               else {
+                       frame->type |= AO_SCHEME_FRAME_PRINT;
+                       for (f = 0; f < frame->num; f++) {
+                               if (f != 0) {
+                                       tabs(indent);
+                                       printf("         ");
+                               }
+                               ao_scheme_poly_write(vals->vals[f].atom);
+                               printf(" = ");
+                               ao_scheme_poly_write(vals->vals[f].val);
+                               printf("\n");
+                       }
+                       if (frame->prev)
+                               ao_scheme_error_frame(indent + 1, "prev:   ", ao_scheme_poly_frame(frame->prev));
+                       frame->type &= ~AO_SCHEME_FRAME_PRINT;
+               }
+               tabs(indent);
+               printf("        }\n");
+       } else
+               printf ("}\n");
+}
+
+void
+ao_scheme_vprintf(char *format, va_list args)
+{
+       char c;
+
+       while ((c = *format++) != '\0') {
+               if (c == '%') {
+                       switch (c = *format++) {
+                       case 'v':
+                               ao_scheme_poly_write((ao_poly) va_arg(args, unsigned int));
+                               break;
+                       case 'p':
+                               printf("%p", va_arg(args, void *));
+                               break;
+                       case 'd':
+                               printf("%d", va_arg(args, int));
+                               break;
+                       case 's':
+                               printf("%s", va_arg(args, char *));
+                               break;
+                       default:
+                               putchar(c);
+                               break;
+                       }
+               } else
+                       putchar(c);
+       }
+}
+
+void
+ao_scheme_printf(char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       ao_scheme_vprintf(format, args);
+       va_end(args);
+}
+
+ao_poly
+ao_scheme_error(int error, char *format, ...)
+{
+       va_list args;
+
+       ao_scheme_exception |= error;
+       va_start(args, format);
+       ao_scheme_vprintf(format, args);
+       putchar('\n');
+       va_end(args);
+       ao_scheme_printf("Value:  %v\n", ao_scheme_v);
+       ao_scheme_printf("Frame:  %v\n", ao_scheme_frame_poly(ao_scheme_frame_current));
+       printf("Stack:\n");
+       ao_scheme_stack_write(ao_scheme_stack_poly(ao_scheme_stack));
+       ao_scheme_printf("Globals: %v\n", ao_scheme_frame_poly(ao_scheme_frame_global));
+       return AO_SCHEME_NIL;
+}
diff --git a/src/scheme/ao_scheme_eval.c b/src/scheme/ao_scheme_eval.c
new file mode 100644 (file)
index 0000000..907ecf0
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+#include <assert.h>
+
+struct ao_scheme_stack         *ao_scheme_stack;
+ao_poly                                ao_scheme_v;
+uint8_t                                ao_scheme_skip_cons_free;
+
+ao_poly
+ao_scheme_set_cond(struct ao_scheme_cons *c)
+{
+       ao_scheme_stack->state = eval_cond;
+       ao_scheme_stack->sexprs = ao_scheme_cons_poly(c);
+       return AO_SCHEME_NIL;
+}
+
+static int
+func_type(ao_poly func)
+{
+       if (func == AO_SCHEME_NIL)
+               return ao_scheme_error(AO_SCHEME_INVALID, "func is nil");
+       switch (ao_scheme_poly_type(func)) {
+       case AO_SCHEME_BUILTIN:
+               return ao_scheme_poly_builtin(func)->args & AO_SCHEME_FUNC_MASK;
+       case AO_SCHEME_LAMBDA:
+               return ao_scheme_poly_lambda(func)->args;
+       case AO_SCHEME_STACK:
+               return AO_SCHEME_FUNC_LAMBDA;
+       default:
+               ao_scheme_error(AO_SCHEME_INVALID, "not a func");
+               return -1;
+       }
+}
+
+/*
+ * Flattened eval to avoid stack issues
+ */
+
+/*
+ * Evaluate an s-expression
+ *
+ * For a list, evaluate all of the elements and
+ * then execute the resulting function call.
+ *
+ * Each element of the list is evaluated in
+ * a clean stack context.
+ *
+ * The current stack state is set to 'formal' so that
+ * when the evaluation is complete, the value
+ * will get appended to the values list.
+ *
+ * For other types, compute the value directly.
+ */
+
+static int
+ao_scheme_eval_sexpr(void)
+{
+       DBGI("sexpr: %v\n", ao_scheme_v);
+       switch (ao_scheme_poly_type(ao_scheme_v)) {
+       case AO_SCHEME_CONS:
+               if (ao_scheme_v == AO_SCHEME_NIL) {
+                       if (!ao_scheme_stack->values) {
+                               /*
+                                * empty list evaluates to empty list
+                                */
+                               ao_scheme_v = AO_SCHEME_NIL;
+                               ao_scheme_stack->state = eval_val;
+                       } else {
+                               /*
+                                * done with arguments, go execute it
+                                */
+                               ao_scheme_v = ao_scheme_poly_cons(ao_scheme_stack->values)->car;
+                               ao_scheme_stack->state = eval_exec;
+                       }
+               } else {
+                       if (!ao_scheme_stack->values)
+                               ao_scheme_stack->list = ao_scheme_v;
+                       /*
+                        * Evaluate another argument and then switch
+                        * to 'formal' to add the value to the values
+                        * list
+                        */
+                       ao_scheme_stack->sexprs = ao_scheme_v;
+                       ao_scheme_stack->state = eval_formal;
+                       if (!ao_scheme_stack_push())
+                               return 0;
+                       /*
+                        * push will reset the state to 'sexpr', which
+                        * will evaluate the expression
+                        */
+                       ao_scheme_v = ao_scheme_poly_cons(ao_scheme_v)->car;
+               }
+               break;
+       case AO_SCHEME_ATOM:
+               DBGI("..frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+               ao_scheme_v = ao_scheme_atom_get(ao_scheme_v);
+               /* fall through */
+       default:
+               ao_scheme_stack->state = eval_val;
+               break;
+       }
+       DBGI(".. result "); DBG_POLY(ao_scheme_v); DBG("\n");
+       return 1;
+}
+
+/*
+ * A value has been computed.
+ *
+ * If the value was computed from a macro,
+ * then we want to reset the current context
+ * to evaluate the macro result again.
+ *
+ * If not a macro, then pop the stack.
+ * If the stack is empty, we're done.
+ * Otherwise, the stack will contain
+ * the next state.
+ */
+
+static int
+ao_scheme_eval_val(void)
+{
+       DBGI("val: "); DBG_POLY(ao_scheme_v); DBG("\n");
+       /*
+        * Value computed, pop the stack
+        * to figure out what to do with the value
+        */
+       ao_scheme_stack_pop();
+       DBGI("..state %d\n", ao_scheme_stack ? ao_scheme_stack->state : -1);
+       return 1;
+}
+
+/*
+ * A formal has been computed.
+ *
+ * If this is the first formal, then check to see if we've got a
+ * lamda, macro or nlambda.
+ *
+ * For lambda, go compute another formal.  This will terminate
+ * when the sexpr state sees nil.
+ *
+ * For macro/nlambda, we're done, so move the sexprs into the values
+ * and go execute it.
+ *
+ * Macros have an additional step of saving a stack frame holding the
+ * macro value execution context, which then gets the result of the
+ * macro to run
+ */
+
+static int
+ao_scheme_eval_formal(void)
+{
+       ao_poly                 formal;
+       struct ao_scheme_stack  *prev;
+
+       DBGI("formal: "); DBG_POLY(ao_scheme_v); DBG("\n");
+
+       /* Check what kind of function we've got */
+       if (!ao_scheme_stack->values) {
+               switch (func_type(ao_scheme_v)) {
+               case AO_SCHEME_FUNC_LAMBDA:
+                       DBGI(".. lambda\n");
+                       break;
+               case AO_SCHEME_FUNC_MACRO:
+                       /* Evaluate the result once more */
+                       ao_scheme_stack->state = eval_macro;
+                       if (!ao_scheme_stack_push())
+                               return 0;
+
+                       /* After the function returns, take that
+                        * value and re-evaluate it
+                        */
+                       prev = ao_scheme_poly_stack(ao_scheme_stack->prev);
+                       ao_scheme_stack->sexprs = prev->sexprs;
+
+                       DBGI(".. start macro\n");
+                       DBGI("\t.. sexprs       "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+                       DBGI("\t.. values       "); DBG_POLY(ao_scheme_stack->values); DBG("\n");
+                       DBG_FRAMES();
+
+                       /* fall through ... */
+               case AO_SCHEME_FUNC_NLAMBDA:
+                       DBGI(".. nlambda or macro\n");
+
+                       /* use the raw sexprs as values */
+                       ao_scheme_stack->values = ao_scheme_stack->sexprs;
+                       ao_scheme_stack->values_tail = AO_SCHEME_NIL;
+                       ao_scheme_stack->state = eval_exec;
+
+                       /* ready to execute now */
+                       return 1;
+               case -1:
+                       return 0;
+               }
+       }
+
+       /* Append formal to list of values */
+       formal = ao_scheme__cons(ao_scheme_v, AO_SCHEME_NIL);
+       if (!formal)
+               return 0;
+
+       if (ao_scheme_stack->values_tail)
+               ao_scheme_poly_cons(ao_scheme_stack->values_tail)->cdr = formal;
+       else
+               ao_scheme_stack->values = formal;
+       ao_scheme_stack->values_tail = formal;
+
+       DBGI(".. values "); DBG_POLY(ao_scheme_stack->values); DBG("\n");
+
+       /*
+        * Step to the next argument, if this is last, then
+        * 'sexpr' will end up switching to 'exec'
+        */
+       ao_scheme_v = ao_scheme_poly_cons(ao_scheme_stack->sexprs)->cdr;
+
+       ao_scheme_stack->state = eval_sexpr;
+
+       DBGI(".. "); DBG_POLY(ao_scheme_v); DBG("\n");
+       return 1;
+}
+
+/*
+ * Start executing a function call
+ *
+ * Most builtins are easy, just call the function.
+ * 'cond' is magic; it sticks the list of clauses
+ * in 'sexprs' and switches to 'cond' state. That
+ * bit of magic is done in ao_scheme_set_cond.
+ *
+ * Lambdas build a new frame to hold the locals and
+ * then re-use the current stack context to evaluate
+ * the s-expression from the lambda.
+ */
+
+static int
+ao_scheme_eval_exec(void)
+{
+       ao_poly v;
+       struct ao_scheme_builtin        *builtin;
+
+       DBGI("exec: "); DBG_POLY(ao_scheme_v); DBG(" values "); DBG_POLY(ao_scheme_stack->values); DBG ("\n");
+       ao_scheme_stack->sexprs = AO_SCHEME_NIL;
+       switch (ao_scheme_poly_type(ao_scheme_v)) {
+       case AO_SCHEME_BUILTIN:
+               ao_scheme_stack->state = eval_val;
+               builtin = ao_scheme_poly_builtin(ao_scheme_v);
+               v = ao_scheme_func(builtin) (
+                       ao_scheme_poly_cons(ao_scheme_poly_cons(ao_scheme_stack->values)->cdr));
+               DBG_DO(if (!ao_scheme_exception && ao_scheme_poly_builtin(ao_scheme_v)->func == builtin_set) {
+                               struct ao_scheme_cons *cons = ao_scheme_poly_cons(ao_scheme_stack->values);
+                               ao_poly atom = ao_scheme_arg(cons, 1);
+                               ao_poly val = ao_scheme_arg(cons, 2);
+                               DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n");
+                       });
+               builtin = ao_scheme_poly_builtin(ao_scheme_v);
+               if (builtin && (builtin->args & AO_SCHEME_FUNC_FREE_ARGS) && !ao_scheme_stack_marked(ao_scheme_stack) && !ao_scheme_skip_cons_free) {
+                       struct ao_scheme_cons *cons = ao_scheme_poly_cons(ao_scheme_stack->values);
+                       ao_scheme_stack->values = AO_SCHEME_NIL;
+                       ao_scheme_cons_free(cons);
+               }
+
+               ao_scheme_v = v;
+               ao_scheme_stack->values = AO_SCHEME_NIL;
+               ao_scheme_stack->values_tail = AO_SCHEME_NIL;
+               DBGI(".. result "); DBG_POLY(ao_scheme_v); DBG ("\n");
+               DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+               break;
+       case AO_SCHEME_LAMBDA:
+               DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+               ao_scheme_stack->state = eval_begin;
+               v = ao_scheme_lambda_eval();
+               ao_scheme_stack->sexprs = v;
+               ao_scheme_stack->values = AO_SCHEME_NIL;
+               ao_scheme_stack->values_tail = AO_SCHEME_NIL;
+               DBGI(".. sexprs "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+               DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+               break;
+       case AO_SCHEME_STACK:
+               DBGI(".. stack "); DBG_POLY(ao_scheme_v); DBG("\n");
+               ao_scheme_v = ao_scheme_stack_eval();
+               DBGI(".. value "); DBG_POLY(ao_scheme_v); DBG("\n");
+               DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+               break;
+       }
+       ao_scheme_skip_cons_free = 0;
+       return 1;
+}
+
+/*
+ * Finish setting up the apply evaluation
+ *
+ * The value is the list to execute
+ */
+static int
+ao_scheme_eval_apply(void)
+{
+       struct ao_scheme_cons   *cons = ao_scheme_poly_cons(ao_scheme_v);
+       struct ao_scheme_cons   *cdr, *prev;
+
+       /* Glue the arguments into the right shape. That's all but the last
+        * concatenated onto the last
+        */
+       cdr = cons;
+       for (;;) {
+               prev = cdr;
+               cdr = ao_scheme_poly_cons(prev->cdr);
+               if (cdr->cdr == AO_SCHEME_NIL)
+                       break;
+       }
+       DBGI("before mangling: "); DBG_POLY(ao_scheme_v); DBG("\n");
+       prev->cdr = cdr->car;
+       ao_scheme_stack->values = ao_scheme_v;
+       ao_scheme_v = ao_scheme_poly_cons(ao_scheme_stack->values)->car;
+       DBGI("apply: "); DBG_POLY(ao_scheme_stack->values); DBG ("\n");
+       ao_scheme_stack->state = eval_exec;
+       ao_scheme_skip_cons_free = 1;
+       return 1;
+}
+
+/*
+ * Start evaluating the next cond clause
+ *
+ * If the list of clauses is empty, then
+ * the result of the cond is nil.
+ *
+ * Otherwise, set the current stack state to 'cond_test' and create a
+ * new stack context to evaluate the test s-expression. Once that's
+ * complete, we'll land in 'cond_test' to finish the clause.
+ */
+static int
+ao_scheme_eval_cond(void)
+{
+       DBGI("cond: "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+       DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+       DBGI(".. saved frame "); DBG_POLY(ao_scheme_stack->frame); DBG("\n");
+       if (!ao_scheme_stack->sexprs) {
+               ao_scheme_v = _ao_scheme_bool_false;
+               ao_scheme_stack->state = eval_val;
+       } else {
+               ao_scheme_v = ao_scheme_poly_cons(ao_scheme_stack->sexprs)->car;
+               if (!ao_scheme_v || ao_scheme_poly_type(ao_scheme_v) != AO_SCHEME_CONS) {
+                       ao_scheme_error(AO_SCHEME_INVALID, "invalid cond clause");
+                       return 0;
+               }
+               ao_scheme_v = ao_scheme_poly_cons(ao_scheme_v)->car;
+               if (ao_scheme_v == _ao_scheme_atom_else)
+                       ao_scheme_v = _ao_scheme_bool_true;
+               ao_scheme_stack->state = eval_cond_test;
+               if (!ao_scheme_stack_push())
+                       return 0;
+       }
+       return 1;
+}
+
+/*
+ * Finish a cond clause.
+ *
+ * Check the value from the test expression, if
+ * non-nil, then set up to evaluate the value expression.
+ *
+ * Otherwise, step to the next clause and go back to the 'cond'
+ * state
+ */
+static int
+ao_scheme_eval_cond_test(void)
+{
+       DBGI("cond_test: "); DBG_POLY(ao_scheme_v); DBG(" sexprs "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+       DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+       DBGI(".. saved frame "); DBG_POLY(ao_scheme_stack->frame); DBG("\n");
+       if (ao_scheme_v != _ao_scheme_bool_false) {
+               struct ao_scheme_cons *car = ao_scheme_poly_cons(ao_scheme_poly_cons(ao_scheme_stack->sexprs)->car);
+               ao_poly c = car->cdr;
+
+               if (c) {
+                       ao_scheme_stack->state = eval_begin;
+                       ao_scheme_stack->sexprs = c;
+               } else
+                       ao_scheme_stack->state = eval_val;
+       } else {
+               ao_scheme_stack->sexprs = ao_scheme_poly_cons(ao_scheme_stack->sexprs)->cdr;
+               DBGI("next cond: "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+               ao_scheme_stack->state = eval_cond;
+       }
+       return 1;
+}
+
+/*
+ * Evaluate a list of sexprs, returning the value from the last one.
+ *
+ * ao_scheme_begin records the list in stack->sexprs, so we just need to
+ * walk that list. Set ao_scheme_v to the car of the list and jump to
+ * eval_sexpr. When that's done, it will land in eval_val. For all but
+ * the last, leave a stack frame with eval_begin set so that we come
+ * back here. For the last, don't add a stack frame so that we can
+ * just continue on.
+ */
+static int
+ao_scheme_eval_begin(void)
+{
+       DBGI("begin: "); DBG_POLY(ao_scheme_v); DBG(" sexprs "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+       DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+       DBGI(".. saved frame "); DBG_POLY(ao_scheme_stack->frame); DBG("\n");
+
+       if (!ao_scheme_stack->sexprs) {
+               ao_scheme_v = AO_SCHEME_NIL;
+               ao_scheme_stack->state = eval_val;
+       } else {
+               ao_scheme_v = ao_scheme_poly_cons(ao_scheme_stack->sexprs)->car;
+               ao_scheme_stack->sexprs = ao_scheme_poly_cons(ao_scheme_stack->sexprs)->cdr;
+
+               /* If there are more sexprs to do, then come back here, otherwise
+                * return the value of the last one by just landing in eval_sexpr
+                */
+               if (ao_scheme_stack->sexprs) {
+                       ao_scheme_stack->state = eval_begin;
+                       if (!ao_scheme_stack_push())
+                               return 0;
+               }
+               ao_scheme_stack->state = eval_sexpr;
+       }
+       return 1;
+}
+
+/*
+ * Conditionally execute a list of sexprs while the first is true
+ */
+static int
+ao_scheme_eval_while(void)
+{
+       DBGI("while: "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+       DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+       DBGI(".. saved frame "); DBG_POLY(ao_scheme_stack->frame); DBG("\n");
+
+       ao_scheme_stack->values = ao_scheme_v;
+       if (!ao_scheme_stack->sexprs) {
+               ao_scheme_v = AO_SCHEME_NIL;
+               ao_scheme_stack->state = eval_val;
+       } else {
+               ao_scheme_v = ao_scheme_poly_cons(ao_scheme_stack->sexprs)->car;
+               ao_scheme_stack->state = eval_while_test;
+               if (!ao_scheme_stack_push())
+                       return 0;
+       }
+       return 1;
+}
+
+/*
+ * Check the while condition, terminate the loop if nil. Otherwise keep going
+ */
+static int
+ao_scheme_eval_while_test(void)
+{
+       DBGI("while_test: "); DBG_POLY(ao_scheme_v); DBG(" sexprs "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+       DBGI(".. frame "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");
+       DBGI(".. saved frame "); DBG_POLY(ao_scheme_stack->frame); DBG("\n");
+
+       if (ao_scheme_v != _ao_scheme_bool_false) {
+               ao_scheme_stack->values = ao_scheme_v;
+               ao_scheme_v = ao_scheme_poly_cons(ao_scheme_stack->sexprs)->cdr;
+               ao_scheme_stack->state = eval_while;
+               if (!ao_scheme_stack_push())
+                       return 0;
+               ao_scheme_stack->state = eval_begin;
+               ao_scheme_stack->sexprs = ao_scheme_v;
+       }
+       else
+       {
+               ao_scheme_stack->state = eval_val;
+               ao_scheme_v = ao_scheme_stack->values;
+       }
+       return 1;
+}
+
+/*
+ * Replace the original sexpr with the macro expansion, then
+ * execute that
+ */
+static int
+ao_scheme_eval_macro(void)
+{
+       DBGI("macro: "); DBG_POLY(ao_scheme_v); DBG(" sexprs "); DBG_POLY(ao_scheme_stack->sexprs); DBG("\n");
+
+       if (ao_scheme_v == AO_SCHEME_NIL)
+               ao_scheme_abort();
+       if (ao_scheme_poly_type(ao_scheme_v) == AO_SCHEME_CONS) {
+               *ao_scheme_poly_cons(ao_scheme_stack->sexprs) = *ao_scheme_poly_cons(ao_scheme_v);
+               ao_scheme_v = ao_scheme_stack->sexprs;
+               DBGI("sexprs rewritten to: "); DBG_POLY(ao_scheme_v); DBG("\n");
+       }
+       ao_scheme_stack->sexprs = AO_SCHEME_NIL;
+       ao_scheme_stack->state = eval_sexpr;
+       return 1;
+}
+
+static int (*const evals[])(void) = {
+       [eval_sexpr] = ao_scheme_eval_sexpr,
+       [eval_val] = ao_scheme_eval_val,
+       [eval_formal] = ao_scheme_eval_formal,
+       [eval_exec] = ao_scheme_eval_exec,
+       [eval_apply] = ao_scheme_eval_apply,
+       [eval_cond] = ao_scheme_eval_cond,
+       [eval_cond_test] = ao_scheme_eval_cond_test,
+       [eval_begin] = ao_scheme_eval_begin,
+       [eval_while] = ao_scheme_eval_while,
+       [eval_while_test] = ao_scheme_eval_while_test,
+       [eval_macro] = ao_scheme_eval_macro,
+};
+
+const char * const ao_scheme_state_names[] = {
+       [eval_sexpr] = "sexpr",
+       [eval_val] = "val",
+       [eval_formal] = "formal",
+       [eval_exec] = "exec",
+       [eval_apply] = "apply",
+       [eval_cond] = "cond",
+       [eval_cond_test] = "cond_test",
+       [eval_begin] = "begin",
+       [eval_while] = "while",
+       [eval_while_test] = "while_test",
+       [eval_macro] = "macro",
+};
+
+/*
+ * Called at restore time to reset all execution state
+ */
+
+void
+ao_scheme_eval_clear_globals(void)
+{
+       ao_scheme_stack = NULL;
+       ao_scheme_frame_current = NULL;
+       ao_scheme_v = AO_SCHEME_NIL;
+}
+
+int
+ao_scheme_eval_restart(void)
+{
+       return ao_scheme_stack_push();
+}
+
+ao_poly
+ao_scheme_eval(ao_poly _v)
+{
+       ao_scheme_v = _v;
+
+       ao_scheme_frame_init();
+
+       if (!ao_scheme_stack_push())
+               return AO_SCHEME_NIL;
+
+       while (ao_scheme_stack) {
+               if (!(*evals[ao_scheme_stack->state])() || ao_scheme_exception) {
+                       ao_scheme_stack_clear();
+                       return AO_SCHEME_NIL;
+               }
+       }
+       DBG_DO(if (ao_scheme_frame_current) {DBGI("frame left as "); DBG_POLY(ao_scheme_frame_poly(ao_scheme_frame_current)); DBG("\n");});
+       ao_scheme_frame_current = NULL;
+       return ao_scheme_v;
+}
diff --git a/src/scheme/ao_scheme_float.c b/src/scheme/ao_scheme_float.c
new file mode 100644 (file)
index 0000000..9924903
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include "ao_scheme.h"
+#include <math.h>
+
+static void float_mark(void *addr)
+{
+       (void) addr;
+}
+
+static int float_size(void *addr)
+{
+       if (!addr)
+               return 0;
+       return sizeof (struct ao_scheme_float);
+}
+
+static void float_move(void *addr)
+{
+       (void) addr;
+}
+
+const struct ao_scheme_type ao_scheme_float_type = {
+       .mark = float_mark,
+       .size = float_size,
+       .move = float_move,
+       .name = "float",
+};
+
+#ifndef FLOAT_FORMAT
+#define FLOAT_FORMAT "%g"
+#endif
+
+void
+ao_scheme_float_write(ao_poly p)
+{
+       struct ao_scheme_float *f = ao_scheme_poly_float(p);
+       float   v = f->value;
+
+       if (isnanf(v))
+               printf("+nan.0");
+       else if (isinff(v)) {
+               if (v < 0)
+                       printf("-");
+               else
+                       printf("+");
+               printf("inf.0");
+       } else
+               printf (FLOAT_FORMAT, v);
+}
+
+float
+ao_scheme_poly_number(ao_poly p)
+{
+       switch (ao_scheme_poly_base_type(p)) {
+       case AO_SCHEME_INT:
+               return ao_scheme_poly_int(p);
+       case AO_SCHEME_OTHER:
+               switch (ao_scheme_other_type(ao_scheme_poly_other(p))) {
+               case AO_SCHEME_BIGINT:
+                       return ao_scheme_bigint_int(ao_scheme_poly_bigint(p)->value);
+               case AO_SCHEME_FLOAT:
+                       return ao_scheme_poly_float(p)->value;
+               }
+       }
+       return NAN;
+}
+
+ao_poly
+ao_scheme_float_get(float value)
+{
+       struct ao_scheme_float  *f;
+
+       f = ao_scheme_alloc(sizeof (struct ao_scheme_float));
+       f->type = AO_SCHEME_FLOAT;
+       f->value = value;
+       return ao_scheme_float_poly(f);
+}
+
+ao_poly
+ao_scheme_do_inexactp(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == AO_SCHEME_FLOAT)
+               return _ao_scheme_bool_true;
+       return _ao_scheme_bool_false;
+}
+
+ao_poly
+ao_scheme_do_finitep(struct ao_scheme_cons *cons)
+{
+       ao_poly value;
+       float   f;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       value = ao_scheme_arg(cons, 0);
+       switch (ao_scheme_poly_type(value)) {
+       case AO_SCHEME_INT:
+       case AO_SCHEME_BIGINT:
+               return _ao_scheme_bool_true;
+       case AO_SCHEME_FLOAT:
+               f = ao_scheme_poly_float(value)->value;
+               if (!isnan(f) && !isinf(f))
+                       return _ao_scheme_bool_true;
+       }
+       return _ao_scheme_bool_false;
+}
+
+ao_poly
+ao_scheme_do_infinitep(struct ao_scheme_cons *cons)
+{
+       ao_poly value;
+       float   f;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       value = ao_scheme_arg(cons, 0);
+       switch (ao_scheme_poly_type(value)) {
+       case AO_SCHEME_FLOAT:
+               f = ao_scheme_poly_float(value)->value;
+               if (isinf(f))
+                       return _ao_scheme_bool_true;
+       }
+       return _ao_scheme_bool_false;
+}
+
+ao_poly
+ao_scheme_do_sqrt(struct ao_scheme_cons *cons)
+{
+       ao_poly value;
+
+       if (!ao_scheme_check_argc(_ao_scheme_atom_sqrt, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       value = ao_scheme_arg(cons, 0);
+       if (!ao_scheme_number_typep(ao_scheme_poly_type(value)))
+               return ao_scheme_error(AO_SCHEME_INVALID, "%s: non-numeric", ao_scheme_poly_atom(_ao_scheme_atom_sqrt)->name);
+       return ao_scheme_float_get(sqrtf(ao_scheme_poly_number(value)));
+}
diff --git a/src/scheme/ao_scheme_frame.c b/src/scheme/ao_scheme_frame.c
new file mode 100644 (file)
index 0000000..e5d481e
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
+static inline int
+frame_vals_num_size(int num)
+{
+       return sizeof (struct ao_scheme_frame_vals) + num * sizeof (struct ao_scheme_val);
+}
+
+static int
+frame_vals_size(void *addr)
+{
+       struct ao_scheme_frame_vals     *vals = addr;
+       return frame_vals_num_size(vals->size);
+}
+
+static void
+frame_vals_mark(void *addr)
+{
+       struct ao_scheme_frame_vals     *vals = addr;
+       int                             f;
+
+       for (f = 0; f < vals->size; f++) {
+               struct ao_scheme_val    *v = &vals->vals[f];
+
+               ao_scheme_poly_mark(v->val, 0);
+               MDBG_MOVE("frame mark atom %s %d val %d at %d    ",
+                         ao_scheme_poly_atom(v->atom)->name,
+                         MDBG_OFFSET(ao_scheme_ref(v->atom)),
+                         MDBG_OFFSET(ao_scheme_ref(v->val)), f);
+               MDBG_DO(ao_scheme_poly_write(v->val));
+               MDBG_DO(printf("\n"));
+       }
+}
+
+static void
+frame_vals_move(void *addr)
+{
+       struct ao_scheme_frame_vals     *vals = addr;
+       int                             f;
+
+       for (f = 0; f < vals->size; f++) {
+               struct ao_scheme_val    *v = &vals->vals[f];
+
+               ao_scheme_poly_move(&v->atom, 0);
+               ao_scheme_poly_move(&v->val, 0);
+               MDBG_MOVE("frame move atom %s %d val %d at %d\n",
+                         ao_scheme_poly_atom(v->atom)->name,
+                         MDBG_OFFSET(ao_scheme_ref(v->atom)),
+                         MDBG_OFFSET(ao_scheme_ref(v->val)), f);
+       }
+}
+
+const struct ao_scheme_type ao_scheme_frame_vals_type = {
+       .mark = frame_vals_mark,
+       .size = frame_vals_size,
+       .move = frame_vals_move,
+       .name = "frame_vals"
+};
+
+static int
+frame_size(void *addr)
+{
+       (void) addr;
+       return sizeof (struct ao_scheme_frame);
+}
+
+static void
+frame_mark(void *addr)
+{
+       struct ao_scheme_frame  *frame = addr;
+
+       for (;;) {
+               MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame));
+               if (!AO_SCHEME_IS_POOL(frame))
+                       break;
+               ao_scheme_poly_mark(frame->vals, 0);
+               frame = ao_scheme_poly_frame(frame->prev);
+               MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame));
+               if (!frame)
+                       break;
+               if (ao_scheme_mark_memory(&ao_scheme_frame_type, frame))
+                       break;
+       }
+}
+
+static void
+frame_move(void *addr)
+{
+       struct ao_scheme_frame  *frame = addr;
+
+       for (;;) {
+               struct ao_scheme_frame  *prev;
+               int                     ret;
+
+               MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame));
+               if (!AO_SCHEME_IS_POOL(frame))
+                       break;
+               ao_scheme_poly_move(&frame->vals, 0);
+               prev = ao_scheme_poly_frame(frame->prev);
+               if (!prev)
+                       break;
+               ret = ao_scheme_move_memory(&ao_scheme_frame_type, (void **) &prev);
+               if (prev != ao_scheme_poly_frame(frame->prev)) {
+                       MDBG_MOVE("frame prev moved from %d to %d\n",
+                                 MDBG_OFFSET(ao_scheme_poly_frame(frame->prev)),
+                                 MDBG_OFFSET(prev));
+                       frame->prev = ao_scheme_frame_poly(prev);
+               }
+               if (ret)
+                       break;
+               frame = prev;
+       }
+}
+
+const struct ao_scheme_type ao_scheme_frame_type = {
+       .mark = frame_mark,
+       .size = frame_size,
+       .move = frame_move,
+       .name = "frame",
+};
+
+void
+ao_scheme_frame_write(ao_poly p)
+{
+       struct ao_scheme_frame          *frame = ao_scheme_poly_frame(p);
+       struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
+       int                             f;
+
+       printf ("{");
+       if (frame) {
+               if (frame->type & AO_SCHEME_FRAME_PRINT)
+                       printf("recurse...");
+               else {
+                       frame->type |= AO_SCHEME_FRAME_PRINT;
+                       for (f = 0; f < frame->num; f++) {
+                               if (f != 0)
+                                       printf(", ");
+                               ao_scheme_poly_write(vals->vals[f].atom);
+                               printf(" = ");
+                               ao_scheme_poly_write(vals->vals[f].val);
+                       }
+                       if (frame->prev)
+                               ao_scheme_poly_write(frame->prev);
+                       frame->type &= ~AO_SCHEME_FRAME_PRINT;
+               }
+       }
+       printf("}");
+}
+
+static int
+ao_scheme_frame_find(struct ao_scheme_frame *frame, int top, ao_poly atom)
+{
+       struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
+       int                             l = 0;
+       int                             r = top - 1;
+
+       while (l <= r) {
+               int m = (l + r) >> 1;
+               if (vals->vals[m].atom < atom)
+                       l = m + 1;
+               else
+                       r = m - 1;
+       }
+       return l;
+}
+
+ao_poly *
+ao_scheme_frame_ref(struct ao_scheme_frame *frame, ao_poly atom)
+{
+       struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
+       int                             l = ao_scheme_frame_find(frame, frame->num, atom);
+
+       if (l >= frame->num)
+               return NULL;
+
+       if (vals->vals[l].atom != atom)
+               return NULL;
+       return &vals->vals[l].val;
+}
+
+struct ao_scheme_frame *ao_scheme_frame_free_list[AO_SCHEME_FRAME_FREE];
+
+static struct ao_scheme_frame_vals *
+ao_scheme_frame_vals_new(int num)
+{
+       struct ao_scheme_frame_vals     *vals;
+
+       vals = ao_scheme_alloc(frame_vals_num_size(num));
+       if (!vals)
+               return NULL;
+       vals->type = AO_SCHEME_FRAME_VALS;
+       vals->size = num;
+       memset(vals->vals, '\0', num * sizeof (struct ao_scheme_val));
+       return vals;
+}
+
+struct ao_scheme_frame *
+ao_scheme_frame_new(int num)
+{
+       struct ao_scheme_frame          *frame;
+       struct ao_scheme_frame_vals     *vals;
+
+       if (num < AO_SCHEME_FRAME_FREE && (frame = ao_scheme_frame_free_list[num])) {
+               ao_scheme_frame_free_list[num] = ao_scheme_poly_frame(frame->prev);
+               vals = ao_scheme_poly_frame_vals(frame->vals);
+       } else {
+               frame = ao_scheme_alloc(sizeof (struct ao_scheme_frame));
+               if (!frame)
+                       return NULL;
+               frame->type = AO_SCHEME_FRAME;
+               frame->num = 0;
+               frame->prev = AO_SCHEME_NIL;
+               frame->vals = AO_SCHEME_NIL;
+               ao_scheme_frame_stash(0, frame);
+               vals = ao_scheme_frame_vals_new(num);
+               frame = ao_scheme_frame_fetch(0);
+               if (!vals)
+                       return NULL;
+               frame->vals = ao_scheme_frame_vals_poly(vals);
+               frame->num = num;
+       }
+       frame->prev = AO_SCHEME_NIL;
+       return frame;
+}
+
+ao_poly
+ao_scheme_frame_mark(struct ao_scheme_frame *frame)
+{
+       if (!frame)
+               return AO_SCHEME_NIL;
+       frame->type |= AO_SCHEME_FRAME_MARK;
+       return ao_scheme_frame_poly(frame);
+}
+
+void
+ao_scheme_frame_free(struct ao_scheme_frame *frame)
+{
+       if (frame && !ao_scheme_frame_marked(frame)) {
+               int     num = frame->num;
+               if (num < AO_SCHEME_FRAME_FREE) {
+                       struct ao_scheme_frame_vals     *vals;
+
+                       vals = ao_scheme_poly_frame_vals(frame->vals);
+                       memset(vals->vals, '\0', vals->size * sizeof (struct ao_scheme_val));
+                       frame->prev = ao_scheme_frame_poly(ao_scheme_frame_free_list[num]);
+                       ao_scheme_frame_free_list[num] = frame;
+               }
+       }
+}
+
+static struct ao_scheme_frame *
+ao_scheme_frame_realloc(struct ao_scheme_frame *frame, int new_num)
+{
+       struct ao_scheme_frame_vals     *vals;
+       struct ao_scheme_frame_vals     *new_vals;
+       int                             copy;
+
+       if (new_num == frame->num)
+               return frame;
+       ao_scheme_frame_stash(0, frame);
+       new_vals = ao_scheme_frame_vals_new(new_num);
+       frame = ao_scheme_frame_fetch(0);
+       if (!new_vals)
+               return NULL;
+       vals = ao_scheme_poly_frame_vals(frame->vals);
+       copy = new_num;
+       if (copy > frame->num)
+               copy = frame->num;
+       memcpy(new_vals->vals, vals->vals, copy * sizeof (struct ao_scheme_val));
+       frame->vals = ao_scheme_frame_vals_poly(new_vals);
+       frame->num = new_num;
+       return frame;
+}
+
+void
+ao_scheme_frame_bind(struct ao_scheme_frame *frame, int num, ao_poly atom, ao_poly val)
+{
+       struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
+       int                             l = ao_scheme_frame_find(frame, num, atom);
+
+       memmove(&vals->vals[l+1],
+               &vals->vals[l],
+               (num - l) * sizeof (struct ao_scheme_val));
+       vals->vals[l].atom = atom;
+       vals->vals[l].val = val;
+}
+
+ao_poly
+ao_scheme_frame_add(struct ao_scheme_frame *frame, ao_poly atom, ao_poly val)
+{
+       ao_poly *ref = frame ? ao_scheme_frame_ref(frame, atom) : NULL;
+
+       if (!ref) {
+               int f = frame->num;
+               ao_scheme_poly_stash(0, atom);
+               ao_scheme_poly_stash(1, val);
+               frame = ao_scheme_frame_realloc(frame, f + 1);
+               val = ao_scheme_poly_fetch(1);
+               atom = ao_scheme_poly_fetch(0);
+               if (!frame)
+                       return AO_SCHEME_NIL;
+               ao_scheme_frame_bind(frame, frame->num - 1, atom, val);
+       } else
+               *ref = val;
+       return val;
+}
+
+struct ao_scheme_frame *ao_scheme_frame_global;
+struct ao_scheme_frame *ao_scheme_frame_current;
+
+void
+ao_scheme_frame_init(void)
+{
+       if (!ao_scheme_frame_global)
+               ao_scheme_frame_global = ao_scheme_frame_new(0);
+}
diff --git a/src/scheme/ao_scheme_int.c b/src/scheme/ao_scheme_int.c
new file mode 100644 (file)
index 0000000..350a5d3
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
+void
+ao_scheme_int_write(ao_poly p)
+{
+       int i = ao_scheme_poly_int(p);
+       printf("%d", i);
+}
+
+int32_t
+ao_scheme_poly_integer(ao_poly p)
+{
+       switch (ao_scheme_poly_base_type(p)) {
+       case AO_SCHEME_INT:
+               return ao_scheme_poly_int(p);
+       case AO_SCHEME_OTHER:
+               if (ao_scheme_other_type(ao_scheme_poly_other(p)) == AO_SCHEME_BIGINT)
+                       return ao_scheme_bigint_int(ao_scheme_poly_bigint(p)->value);
+       }
+       return AO_SCHEME_NOT_INTEGER;
+}
+
+ao_poly
+ao_scheme_integer_poly(int32_t p)
+{
+       struct ao_scheme_bigint *bi;
+
+       if (AO_SCHEME_MIN_INT <= p && p <= AO_SCHEME_MAX_INT)
+               return ao_scheme_int_poly(p);
+       bi = ao_scheme_alloc(sizeof (struct ao_scheme_bigint));
+       bi->value = ao_scheme_int_bigint(p);
+       return ao_scheme_bigint_poly(bi);
+}
+
+static void bigint_mark(void *addr)
+{
+       (void) addr;
+}
+
+static int bigint_size(void *addr)
+{
+       if (!addr)
+               return 0;
+       return sizeof (struct ao_scheme_bigint);
+}
+
+static void bigint_move(void *addr)
+{
+       (void) addr;
+}
+
+const struct ao_scheme_type ao_scheme_bigint_type = {
+       .mark = bigint_mark,
+       .size = bigint_size,
+       .move = bigint_move,
+       .name = "bigint",
+};
+
+void
+ao_scheme_bigint_write(ao_poly p)
+{
+       struct ao_scheme_bigint *bi = ao_scheme_poly_bigint(p);
+
+       printf("%d", ao_scheme_bigint_int(bi->value));
+}
diff --git a/src/scheme/ao_scheme_lambda.c b/src/scheme/ao_scheme_lambda.c
new file mode 100644 (file)
index 0000000..ec6f858
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao_scheme.h"
+
+int
+lambda_size(void *addr)
+{
+       (void) addr;
+       return sizeof (struct ao_scheme_lambda);
+}
+
+void
+lambda_mark(void *addr)
+{
+       struct ao_scheme_lambda *lambda = addr;
+
+       ao_scheme_poly_mark(lambda->code, 0);
+       ao_scheme_poly_mark(lambda->frame, 0);
+}
+
+void
+lambda_move(void *addr)
+{
+       struct ao_scheme_lambda *lambda = addr;
+
+       ao_scheme_poly_move(&lambda->code, 0);
+       ao_scheme_poly_move(&lambda->frame, 0);
+}
+
+const struct ao_scheme_type ao_scheme_lambda_type = {
+       .size = lambda_size,
+       .mark = lambda_mark,
+       .move = lambda_move,
+       .name = "lambda",
+};
+
+void
+ao_scheme_lambda_write(ao_poly poly)
+{
+       struct ao_scheme_lambda *lambda = ao_scheme_poly_lambda(poly);
+       struct ao_scheme_cons   *cons = ao_scheme_poly_cons(lambda->code);
+
+       printf("(");
+       printf("%s", ao_scheme_args_name(lambda->args));
+       while (cons) {
+               printf(" ");
+               ao_scheme_poly_write(cons->car);
+               cons = ao_scheme_poly_cons(cons->cdr);
+       }
+       printf(")");
+}
+
+ao_poly
+ao_scheme_lambda_alloc(struct ao_scheme_cons *code, int args)
+{
+       struct ao_scheme_lambda *lambda;
+       ao_poly                 formal;
+       struct ao_scheme_cons   *cons;
+
+       formal = ao_scheme_arg(code, 0);
+       while (formal != AO_SCHEME_NIL) {
+               switch (ao_scheme_poly_type(formal)) {
+               case AO_SCHEME_CONS:
+                       cons = ao_scheme_poly_cons(formal);
+                       if (ao_scheme_poly_type(cons->car) != AO_SCHEME_ATOM)
+                               return ao_scheme_error(AO_SCHEME_INVALID, "formal %p is not atom", cons->car);
+                       formal = cons->cdr;
+                       break;
+               case AO_SCHEME_ATOM:
+                       formal = AO_SCHEME_NIL;
+                       break;
+               default:
+                       return ao_scheme_error(AO_SCHEME_INVALID, "formal %p is not atom", formal);
+               }
+       }
+
+       ao_scheme_cons_stash(0, code);
+       lambda = ao_scheme_alloc(sizeof (struct ao_scheme_lambda));
+       code = ao_scheme_cons_fetch(0);
+       if (!lambda)
+               return AO_SCHEME_NIL;
+
+       lambda->type = AO_SCHEME_LAMBDA;
+       lambda->args = args;
+       lambda->code = ao_scheme_cons_poly(code);
+       lambda->frame = ao_scheme_frame_mark(ao_scheme_frame_current);
+       DBGI("build frame: "); DBG_POLY(lambda->frame); DBG("\n");
+       DBG_STACK();
+       return ao_scheme_lambda_poly(lambda);
+}
+
+ao_poly
+ao_scheme_do_lambda(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_lambda_alloc(cons, AO_SCHEME_FUNC_LAMBDA);
+}
+
+ao_poly
+ao_scheme_do_nlambda(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_lambda_alloc(cons, AO_SCHEME_FUNC_NLAMBDA);
+}
+
+ao_poly
+ao_scheme_do_macro(struct ao_scheme_cons *cons)
+{
+       return ao_scheme_lambda_alloc(cons, AO_SCHEME_FUNC_MACRO);
+}
+
+ao_poly
+ao_scheme_lambda_eval(void)
+{
+       struct ao_scheme_lambda *lambda = ao_scheme_poly_lambda(ao_scheme_v);
+       struct ao_scheme_cons   *cons = ao_scheme_poly_cons(ao_scheme_stack->values);
+       struct ao_scheme_cons   *code = ao_scheme_poly_cons(lambda->code);
+       ao_poly                 formals;
+       struct ao_scheme_frame  *next_frame;
+       int                     args_wanted;
+       ao_poly                 varargs = AO_SCHEME_NIL;
+       int                     args_provided;
+       int                     f;
+       struct ao_scheme_cons   *vals;
+
+       DBGI("lambda "); DBG_POLY(ao_scheme_lambda_poly(lambda)); DBG("\n");
+
+       args_wanted = 0;
+       for (formals = ao_scheme_arg(code, 0);
+            ao_scheme_is_pair(formals);
+            formals = ao_scheme_poly_cons(formals)->cdr)
+               ++args_wanted;
+       if (formals != AO_SCHEME_NIL) {
+               if (ao_scheme_poly_type(formals) != AO_SCHEME_ATOM)
+                       return ao_scheme_error(AO_SCHEME_INVALID, "bad lambda form");
+               varargs = formals;
+       }
+
+       /* Create a frame to hold the variables
+        */
+       args_provided = ao_scheme_cons_length(cons) - 1;
+       if (varargs == AO_SCHEME_NIL) {
+               if (args_wanted != args_provided)
+                       return ao_scheme_error(AO_SCHEME_INVALID, "need %d args, got %d", args_wanted, args_provided);
+       } else {
+               if (args_provided < args_wanted)
+                       return ao_scheme_error(AO_SCHEME_INVALID, "need at least %d args, got %d", args_wanted, args_provided);
+       }
+
+       ao_scheme_poly_stash(1, varargs);
+       next_frame = ao_scheme_frame_new(args_wanted + (varargs != AO_SCHEME_NIL));
+       varargs = ao_scheme_poly_fetch(1);
+       if (!next_frame)
+               return AO_SCHEME_NIL;
+
+       /* Re-fetch all of the values in case something moved */
+       lambda = ao_scheme_poly_lambda(ao_scheme_v);
+       cons = ao_scheme_poly_cons(ao_scheme_stack->values);
+       code = ao_scheme_poly_cons(lambda->code);
+       formals = ao_scheme_arg(code, 0);
+       vals = ao_scheme_poly_cons(cons->cdr);
+
+       next_frame->prev = lambda->frame;
+       ao_scheme_frame_current = next_frame;
+       ao_scheme_stack->frame = ao_scheme_frame_poly(ao_scheme_frame_current);
+
+       for (f = 0; f < args_wanted; f++) {
+               struct ao_scheme_cons *arg = ao_scheme_poly_cons(formals);
+               DBGI("bind "); DBG_POLY(arg->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n");
+               ao_scheme_frame_bind(next_frame, f, arg->car, vals->car);
+               formals = arg->cdr;
+               vals = ao_scheme_poly_cons(vals->cdr);
+       }
+       if (varargs) {
+               DBGI("bind "); DBG_POLY(varargs); DBG(" = "); DBG_POLY(ao_scheme_cons_poly(vals)); DBG("\n");
+               /*
+                * Bind the rest of the arguments to the final parameter
+                */
+               ao_scheme_frame_bind(next_frame, f, varargs, ao_scheme_cons_poly(vals));
+       } else {
+               /*
+                * Mark the cons cells from the actuals as freed for immediate re-use, unless
+                * the actuals point into the source function (nlambdas and macros), or if the
+                * stack containing them was copied as a part of a continuation
+                */
+               if (lambda->args == AO_SCHEME_FUNC_LAMBDA && !ao_scheme_stack_marked(ao_scheme_stack)) {
+                       ao_scheme_stack->values = AO_SCHEME_NIL;
+                       ao_scheme_cons_free(cons);
+               }
+       }
+       DBGI("eval frame: "); DBG_POLY(ao_scheme_frame_poly(next_frame)); DBG("\n");
+       DBG_STACK();
+       DBGI("eval code: "); DBG_POLY(code->cdr); DBG("\n");
+       return code->cdr;
+}
diff --git a/src/scheme/ao_scheme_lex.c b/src/scheme/ao_scheme_lex.c
new file mode 100644 (file)
index 0000000..266b1fc
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
diff --git a/src/scheme/ao_scheme_make_builtin b/src/scheme/ao_scheme_make_builtin
new file mode 100644 (file)
index 0000000..8e9c2c0
--- /dev/null
@@ -0,0 +1,190 @@
+#!/usr/bin/nickle
+
+typedef struct {
+       string  type;
+       string  c_name;
+       string[*]       lisp_names;
+} builtin_t;
+
+string[string] type_map = {
+       "lambda" => "LAMBDA",
+       "nlambda" => "NLAMBDA",
+       "macro" => "MACRO",
+       "f_lambda" => "F_LAMBDA",
+       "atom" => "atom",
+};
+
+string[*]
+make_lisp(string[*] tokens)
+{
+       string[...] lisp = {};
+
+       if (dim(tokens) < 3)
+               return (string[1]) { tokens[dim(tokens) - 1] };
+       return (string[dim(tokens)-2]) { [i] = tokens[i+2] };
+}
+
+builtin_t
+read_builtin(file f) {
+       string  line = File::fgets(f);
+       string[*]       tokens = String::wordsplit(line, " \t");
+
+       return (builtin_t) {
+               .type = dim(tokens) > 0 ? type_map[tokens[0]] : "#",
+               .c_name = dim(tokens) > 1 ? tokens[1] : "#",
+               .lisp_names = make_lisp(tokens),
+       };
+}
+
+builtin_t[*]
+read_builtins(file f) {
+       builtin_t[...] builtins = {};
+
+       while (!File::end(f)) {
+               builtin_t       b = read_builtin(f);
+
+               if (b.type[0] != '#')
+                       builtins[dim(builtins)] = b;
+       }
+       return builtins;
+}
+
+bool is_atom(builtin_t b) = b.type == "atom";
+
+void
+dump_ids(builtin_t[*] builtins) {
+       printf("#ifdef AO_SCHEME_BUILTIN_ID\n");
+       printf("#undef AO_SCHEME_BUILTIN_ID\n");
+       printf("enum ao_scheme_builtin_id {\n");
+       for (int i = 0; i < dim(builtins); i++)
+               if (!is_atom(builtins[i]))
+                       printf("\tbuiltin_%s,\n", builtins[i].c_name);
+       printf("\t_builtin_last\n");
+       printf("};\n");
+       printf("#endif /* AO_SCHEME_BUILTIN_ID */\n");
+}
+
+void
+dump_casename(builtin_t[*] builtins) {
+       printf("#ifdef AO_SCHEME_BUILTIN_CASENAME\n");
+       printf("#undef AO_SCHEME_BUILTIN_CASENAME\n");
+       printf("static char *ao_scheme_builtin_name(enum ao_scheme_builtin_id b) {\n");
+       printf("\tswitch(b) {\n");
+       for (int i = 0; i < dim(builtins); i++)
+               if (!is_atom(builtins[i]))
+                       printf("\tcase builtin_%s: return ao_scheme_poly_atom(_atom(\"%s\"))->name;\n",
+                              builtins[i].c_name, builtins[i].lisp_names[0]);
+       printf("\tdefault: return \"???\";\n");
+       printf("\t}\n");
+       printf("}\n");
+       printf("#endif /* AO_SCHEME_BUILTIN_CASENAME */\n");
+}
+
+void
+cify_lisp(string l) {
+       for (int j = 0; j < String::length(l); j++) {
+               int c= l[j];
+               if (Ctype::isalnum(c) || c == '_')
+                       printf("%c", c);
+               else
+                       printf("%02x", c);
+       }
+}
+
+void
+dump_arrayname(builtin_t[*] builtins) {
+       printf("#ifdef AO_SCHEME_BUILTIN_ARRAYNAME\n");
+       printf("#undef AO_SCHEME_BUILTIN_ARRAYNAME\n");
+       printf("static const ao_poly builtin_names[] = {\n");
+       for (int i = 0; i < dim(builtins); i++) {
+               if (!is_atom(builtins[i])) {
+                       printf("\t[builtin_%s] = _ao_scheme_atom_",
+                              builtins[i].c_name);
+                       cify_lisp(builtins[i].lisp_names[0]);
+                       printf(",\n");
+               }
+       }
+       printf("};\n");
+       printf("#endif /* AO_SCHEME_BUILTIN_ARRAYNAME */\n");
+}
+
+void
+dump_funcs(builtin_t[*] builtins) {
+       printf("#ifdef AO_SCHEME_BUILTIN_FUNCS\n");
+       printf("#undef AO_SCHEME_BUILTIN_FUNCS\n");
+       printf("const ao_scheme_func_t ao_scheme_builtins[] = {\n");
+       for (int i = 0; i < dim(builtins); i++) {
+               if (!is_atom(builtins[i]))
+                       printf("\t[builtin_%s] = ao_scheme_do_%s,\n",
+                              builtins[i].c_name,
+                              builtins[i].c_name);
+       }
+       printf("};\n");
+       printf("#endif /* AO_SCHEME_BUILTIN_FUNCS */\n");
+}
+
+void
+dump_decls(builtin_t[*] builtins) {
+       printf("#ifdef AO_SCHEME_BUILTIN_DECLS\n");
+       printf("#undef AO_SCHEME_BUILTIN_DECLS\n");
+       for (int i = 0; i < dim(builtins); i++) {
+               if (!is_atom(builtins[i])) {
+                       printf("ao_poly\n");
+                       printf("ao_scheme_do_%s(struct ao_scheme_cons *cons);\n",
+                              builtins[i].c_name);
+               }
+       }
+       printf("#endif /* AO_SCHEME_BUILTIN_DECLS */\n");
+}
+
+void
+dump_consts(builtin_t[*] builtins) {
+       printf("#ifdef AO_SCHEME_BUILTIN_CONSTS\n");
+       printf("#undef AO_SCHEME_BUILTIN_CONSTS\n");
+       printf("struct builtin_func funcs[] = {\n");
+       for (int i = 0; i < dim(builtins); i++) {
+               if (!is_atom(builtins[i])) {
+                       for (int j = 0; j < dim(builtins[i].lisp_names); j++) {
+                               printf ("\t{ .name = \"%s\", .args = AO_SCHEME_FUNC_%s, .func = builtin_%s },\n",
+                                       builtins[i].lisp_names[j],
+                                       builtins[i].type,
+                                       builtins[i].c_name);
+                       }
+               }
+       }
+       printf("};\n");
+       printf("#endif /* AO_SCHEME_BUILTIN_CONSTS */\n");
+}
+
+void
+dump_atoms(builtin_t[*] builtins) {
+       printf("#ifdef AO_SCHEME_BUILTIN_ATOMS\n");
+       printf("#undef AO_SCHEME_BUILTIN_ATOMS\n");
+       for (int i = 0; i < dim(builtins); i++) {
+               for (int j = 0; j < dim(builtins[i].lisp_names); j++) {
+                       printf("#define _ao_scheme_atom_");
+                       cify_lisp(builtins[i].lisp_names[j]);
+                       printf(" _atom(\"%s\")\n", builtins[i].lisp_names[j]);
+               }
+       }
+       printf("#endif /* AO_SCHEME_BUILTIN_ATOMS */\n");
+}
+
+void main() {
+       if (dim(argv) < 2) {
+               File::fprintf(stderr, "usage: %s <file>\n", argv[0]);
+               exit(1);
+       }
+       twixt(file f = File::open(argv[1], "r"); File::close(f)) {
+               builtin_t[*]    builtins = read_builtins(f);
+               dump_ids(builtins);
+               dump_casename(builtins);
+               dump_arrayname(builtins);
+               dump_funcs(builtins);
+               dump_decls(builtins);
+               dump_consts(builtins);
+               dump_atoms(builtins);
+       }
+}
+
+main();
diff --git a/src/scheme/ao_scheme_make_const.c b/src/scheme/ao_scheme_make_const.c
new file mode 100644 (file)
index 0000000..cf42ec5
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <getopt.h>
+
+static struct ao_scheme_builtin *
+ao_scheme_make_builtin(enum ao_scheme_builtin_id func, int args) {
+       struct ao_scheme_builtin *b = ao_scheme_alloc(sizeof (struct ao_scheme_builtin));
+
+       b->type = AO_SCHEME_BUILTIN;
+       b->func = func;
+       b->args = args;
+       return b;
+}
+
+struct builtin_func {
+       char    *name;
+       int     args;
+       enum ao_scheme_builtin_id       func;
+};
+
+#define AO_SCHEME_BUILTIN_CONSTS
+#include "ao_scheme_builtin.h"
+
+#define N_FUNC (sizeof funcs / sizeof funcs[0])
+
+struct ao_scheme_frame *globals;
+
+static int
+is_atom(int offset)
+{
+       struct ao_scheme_atom *a;
+
+       for (a = ao_scheme_atoms; a; a = ao_scheme_poly_atom(a->next))
+               if (((uint8_t *) a->name - ao_scheme_const) == offset)
+                       return strlen(a->name);
+       return 0;
+}
+
+#define AO_FEC_CRC_INIT        0xffff
+
+static inline uint16_t
+ao_fec_crc_byte(uint8_t byte, uint16_t crc)
+{
+       uint8_t bit;
+
+       for (bit = 0; bit < 8; bit++) {
+               if (((crc & 0x8000) >> 8) ^ (byte & 0x80))
+                       crc = (crc << 1) ^ 0x8005;
+               else
+                       crc = (crc << 1);
+               byte <<= 1;
+       }
+       return crc;
+}
+
+uint16_t
+ao_fec_crc(const uint8_t *bytes, uint8_t len)
+{
+       uint16_t        crc = AO_FEC_CRC_INIT;
+
+       while (len--)
+               crc = ao_fec_crc_byte(*bytes++, crc);
+       return crc;
+}
+
+struct ao_scheme_macro_stack {
+       struct ao_scheme_macro_stack *next;
+       ao_poly p;
+};
+
+struct ao_scheme_macro_stack *macro_stack;
+
+int
+ao_scheme_macro_push(ao_poly p)
+{
+       struct ao_scheme_macro_stack *m = macro_stack;
+
+       while (m) {
+               if (m->p == p)
+                       return 1;
+               m = m->next;
+       }
+       m = malloc (sizeof (struct ao_scheme_macro_stack));
+       m->p = p;
+       m->next = macro_stack;
+       macro_stack = m;
+       return 0;
+}
+
+void
+ao_scheme_macro_pop(void)
+{
+       struct ao_scheme_macro_stack *m = macro_stack;
+
+       macro_stack = m->next;
+       free(m);
+}
+
+#define DBG_MACRO 0
+#if DBG_MACRO
+int macro_scan_depth;
+
+void indent(void)
+{
+       int i;
+       for (i = 0; i < macro_scan_depth; i++)
+               printf("  ");
+}
+#define MACRO_DEBUG(a) a
+#else
+#define MACRO_DEBUG(a)
+#endif
+
+ao_poly
+ao_has_macro(ao_poly p);
+
+ao_poly
+ao_macro_test_get(ao_poly atom)
+{
+       ao_poly *ref = ao_scheme_atom_ref(atom, NULL);
+       if (ref)
+               return *ref;
+       return AO_SCHEME_NIL;
+}
+
+ao_poly
+ao_is_macro(ao_poly p)
+{
+       struct ao_scheme_builtin        *builtin;
+       struct ao_scheme_lambda *lambda;
+       ao_poly ret;
+
+       MACRO_DEBUG(indent(); printf ("is macro "); ao_scheme_poly_write(p); printf("\n"); ++macro_scan_depth);
+       switch (ao_scheme_poly_type(p)) {
+       case AO_SCHEME_ATOM:
+               if (ao_scheme_macro_push(p))
+                       ret = AO_SCHEME_NIL;
+               else {
+                       if (ao_is_macro(ao_macro_test_get(p)))
+                               ret = p;
+                       else
+                               ret = AO_SCHEME_NIL;
+                       ao_scheme_macro_pop();
+               }
+               break;
+       case AO_SCHEME_CONS:
+               ret = ao_has_macro(p);
+               break;
+       case AO_SCHEME_BUILTIN:
+               builtin = ao_scheme_poly_builtin(p);
+               if ((builtin->args & AO_SCHEME_FUNC_MASK) == AO_SCHEME_FUNC_MACRO)
+                       ret = p;
+               else
+                       ret = 0;
+               break;
+
+       case AO_SCHEME_LAMBDA:
+               lambda = ao_scheme_poly_lambda(p);
+               if (lambda->args == AO_SCHEME_FUNC_MACRO)
+                       ret = p;
+               else
+                       ret = ao_has_macro(lambda->code);
+               break;
+       default:
+               ret = AO_SCHEME_NIL;
+               break;
+       }
+       MACRO_DEBUG(--macro_scan_depth; indent(); printf ("... "); ao_scheme_poly_write(ret); printf("\n"));
+       return ret;
+}
+
+ao_poly
+ao_has_macro(ao_poly p)
+{
+       struct ao_scheme_cons   *cons;
+       struct ao_scheme_lambda *lambda;
+       ao_poly                 m;
+       ao_poly                 list;
+
+       if (p == AO_SCHEME_NIL)
+               return AO_SCHEME_NIL;
+
+       MACRO_DEBUG(indent(); printf("has macro "); ao_scheme_poly_write(p); printf("\n"); ++macro_scan_depth);
+       switch (ao_scheme_poly_type(p)) {
+       case AO_SCHEME_LAMBDA:
+               lambda = ao_scheme_poly_lambda(p);
+               p = ao_has_macro(lambda->code);
+               break;
+       case AO_SCHEME_CONS:
+               cons = ao_scheme_poly_cons(p);
+               if ((p = ao_is_macro(cons->car)))
+                       break;
+
+               list = cons->cdr;
+               p = AO_SCHEME_NIL;
+               while (list != AO_SCHEME_NIL && ao_scheme_poly_type(list) == AO_SCHEME_CONS) {
+                       cons = ao_scheme_poly_cons(list);
+                       m = ao_has_macro(cons->car);
+                       if (m) {
+                               p = m;
+                               break;
+                       }
+                       list = cons->cdr;
+               }
+               break;
+
+       default:
+               p = AO_SCHEME_NIL;
+               break;
+       }
+       MACRO_DEBUG(--macro_scan_depth; indent(); printf("... "); ao_scheme_poly_write(p); printf("\n"));
+       return p;
+}
+
+int
+ao_scheme_read_eval_abort(void)
+{
+       ao_poly in, out = AO_SCHEME_NIL;
+       for(;;) {
+               in = ao_scheme_read();
+               if (in == _ao_scheme_atom_eof)
+                       break;
+               out = ao_scheme_eval(in);
+               if (ao_scheme_exception)
+                       return 0;
+               ao_scheme_poly_write(out);
+               putchar ('\n');
+       }
+       return 1;
+}
+
+static FILE    *in;
+static FILE    *out;
+
+int
+ao_scheme_getc(void)
+{
+       return getc(in);
+}
+
+static const struct option options[] = {
+       { .name = "out", .has_arg = 1, .val = 'o' },
+       { 0, 0, 0, 0 }
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s [--out=<output>] [input]\n", program);
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int     f, o;
+       ao_poly val;
+       struct ao_scheme_atom   *a;
+       struct ao_scheme_builtin        *b;
+       int     in_atom = 0;
+       char    *out_name = NULL;
+       int     c;
+       enum ao_scheme_builtin_id       prev_func;
+
+       in = stdin;
+       out = stdout;
+
+       while ((c = getopt_long(argc, argv, "o:", options, NULL)) != -1) {
+               switch (c) {
+               case 'o':
+                       out_name = optarg;
+                       break;
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+
+       ao_scheme_frame_init();
+
+       /* Boolean values #f and #t */
+       ao_scheme_bool_get(0);
+       ao_scheme_bool_get(1);
+
+       prev_func = _builtin_last;
+       for (f = 0; f < (int) N_FUNC; f++) {
+               if (funcs[f].func != prev_func)
+                       b = ao_scheme_make_builtin(funcs[f].func, funcs[f].args);
+               a = ao_scheme_atom_intern(funcs[f].name);
+               ao_scheme_atom_def(ao_scheme_atom_poly(a),
+                                ao_scheme_builtin_poly(b));
+       }
+
+       /* end of file value */
+       a = ao_scheme_atom_intern("eof");
+       ao_scheme_atom_def(ao_scheme_atom_poly(a),
+                        ao_scheme_atom_poly(a));
+
+       /* 'else' */
+       a = ao_scheme_atom_intern("else");
+
+       if (argv[optind]){
+               in = fopen(argv[optind], "r");
+               if (!in) {
+                       perror(argv[optind]);
+                       exit(1);
+               }
+       }
+       if (!ao_scheme_read_eval_abort()) {
+               fprintf(stderr, "eval failed\n");
+               exit(1);
+       }
+
+       /* Reduce to referenced values */
+       ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
+
+       for (f = 0; f < ao_scheme_frame_global->num; f++) {
+               struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(ao_scheme_frame_global->vals);
+               val = ao_has_macro(vals->vals[f].val);
+               if (val != AO_SCHEME_NIL) {
+                       printf("error: function %s contains unresolved macro: ",
+                              ao_scheme_poly_atom(vals->vals[f].atom)->name);
+                       ao_scheme_poly_write(val);
+                       printf("\n");
+                       exit(1);
+               }
+       }
+
+       if (out_name) {
+               out = fopen(out_name, "w");
+               if (!out) {
+                       perror(out_name);
+                       exit(1);
+               }
+       }
+
+       fprintf(out, "/* Generated file, do not edit */\n\n");
+
+       fprintf(out, "#define AO_SCHEME_POOL_CONST %d\n", ao_scheme_top);
+       fprintf(out, "extern const uint8_t ao_scheme_const[AO_SCHEME_POOL_CONST] __attribute__((aligned(4)));\n");
+       fprintf(out, "#define ao_builtin_atoms 0x%04x\n", ao_scheme_atom_poly(ao_scheme_atoms));
+       fprintf(out, "#define ao_builtin_frame 0x%04x\n", ao_scheme_frame_poly(ao_scheme_frame_global));
+       fprintf(out, "#define ao_scheme_const_checksum ((uint16_t) 0x%04x)\n", ao_fec_crc(ao_scheme_const, ao_scheme_top));
+
+       fprintf(out, "#define _ao_scheme_bool_false 0x%04x\n", ao_scheme_bool_poly(ao_scheme_false));
+       fprintf(out, "#define _ao_scheme_bool_true 0x%04x\n", ao_scheme_bool_poly(ao_scheme_true));
+
+       for (a = ao_scheme_atoms; a; a = ao_scheme_poly_atom(a->next)) {
+               char    *n = a->name, c;
+               fprintf(out, "#define _ao_scheme_atom_");
+               while ((c = *n++)) {
+                       if (isalnum(c))
+                               fprintf(out, "%c", c);
+                       else
+                               fprintf(out, "%02x", c);
+               }
+               fprintf(out, "  0x%04x\n", ao_scheme_atom_poly(a));
+       }
+       fprintf(out, "#ifdef AO_SCHEME_CONST_BITS\n");
+       fprintf(out, "const uint8_t ao_scheme_const[AO_SCHEME_POOL_CONST] __attribute((aligned(4))) = {");
+       for (o = 0; o < ao_scheme_top; o++) {
+               uint8_t c;
+               if ((o & 0xf) == 0)
+                       fprintf(out, "\n\t");
+               else
+                       fprintf(out, " ");
+               c = ao_scheme_const[o];
+               if (!in_atom)
+                       in_atom = is_atom(o);
+               if (in_atom) {
+                       fprintf(out, " '%c',", c);
+                       in_atom--;
+               } else {
+                       fprintf(out, "0x%02x,", c);
+               }
+       }
+       fprintf(out, "\n};\n");
+       fprintf(out, "#endif /* AO_SCHEME_CONST_BITS */\n");
+       exit(0);
+}
diff --git a/src/scheme/ao_scheme_mem.c b/src/scheme/ao_scheme_mem.c
new file mode 100644 (file)
index 0000000..45d4de9
--- /dev/null
@@ -0,0 +1,969 @@
+/*
+ * 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.
+ */
+
+#define AO_SCHEME_CONST_BITS
+
+#include "ao_scheme.h"
+#include <stdio.h>
+#include <assert.h>
+
+#ifdef AO_SCHEME_MAKE_CONST
+
+/*
+ * When building the constant table, it is the
+ * pool for allocations.
+ */
+
+#include <stdlib.h>
+uint8_t ao_scheme_const[AO_SCHEME_POOL_CONST] __attribute__((aligned(4)));
+#define ao_scheme_pool ao_scheme_const
+#undef AO_SCHEME_POOL
+#define AO_SCHEME_POOL AO_SCHEME_POOL_CONST
+
+#else
+
+uint8_t        ao_scheme_pool[AO_SCHEME_POOL + AO_SCHEME_POOL_EXTRA] __attribute__((aligned(4)));
+
+#endif
+
+#ifndef DBG_MEM_STATS
+#define DBG_MEM_STATS  DBG_MEM
+#endif
+
+#if DBG_MEM
+int dbg_move_depth;
+int dbg_mem = DBG_MEM_START;
+int dbg_validate = 0;
+
+struct ao_scheme_record {
+       struct ao_scheme_record         *next;
+       const struct ao_scheme_type     *type;
+       void                            *addr;
+       int                             size;
+};
+
+static struct ao_scheme_record *record_head, **record_tail;
+
+static void
+ao_scheme_record_free(struct ao_scheme_record *record)
+{
+       while (record) {
+               struct ao_scheme_record *next = record->next;
+               free(record);
+               record = next;
+       }
+}
+
+static void
+ao_scheme_record_reset(void)
+{
+       ao_scheme_record_free(record_head);
+       record_head = NULL;
+       record_tail = &record_head;
+}
+
+static void
+ao_scheme_record(const struct ao_scheme_type   *type,
+              void                             *addr,
+              int                              size)
+{
+       struct ao_scheme_record *r = malloc(sizeof (struct ao_scheme_record));
+
+       r->next = NULL;
+       r->type = type;
+       r->addr = addr;
+       r->size = size;
+       *record_tail = r;
+       record_tail = &r->next;
+}
+
+static struct ao_scheme_record *
+ao_scheme_record_save(void)
+{
+       struct ao_scheme_record *r = record_head;
+
+       record_head = NULL;
+       record_tail = &record_head;
+       return r;
+}
+
+static void
+ao_scheme_record_compare(char *where,
+                      struct ao_scheme_record *a,
+                      struct ao_scheme_record *b)
+{
+       while (a && b) {
+               if (a->type != b->type || a->size != b->size) {
+                       printf("%s record difers %d %s %d -> %d %s %d\n",
+                              where,
+                              MDBG_OFFSET(a->addr),
+                              a->type->name,
+                              a->size,
+                              MDBG_OFFSET(b->addr),
+                              b->type->name,
+                              b->size);
+                       ao_scheme_abort();
+               }
+               a = a->next;
+               b = b->next;
+       }
+       if (a) {
+               printf("%s record differs %d %s %d -> NULL\n",
+                      where,
+                      MDBG_OFFSET(a->addr),
+                      a->type->name,
+                      a->size);
+               ao_scheme_abort();
+       }
+       if (b) {
+               printf("%s record differs NULL -> %d %s %d\n",
+                      where,
+                      MDBG_OFFSET(b->addr),
+                      b->type->name,
+                      b->size);
+               ao_scheme_abort();
+       }
+}
+
+#else
+#define ao_scheme_record_reset()
+#endif
+
+uint8_t        ao_scheme_exception;
+
+struct ao_scheme_root {
+       const struct ao_scheme_type     *type;
+       void                            **addr;
+};
+
+static struct ao_scheme_cons   *save_cons[2];
+static char                    *save_string[2];
+static struct ao_scheme_frame  *save_frame[1];
+static ao_poly                 save_poly[3];
+
+static const struct ao_scheme_root     ao_scheme_root[] = {
+       {
+               .type = &ao_scheme_cons_type,
+               .addr = (void **) &save_cons[0],
+       },
+       {
+               .type = &ao_scheme_cons_type,
+               .addr = (void **) &save_cons[1],
+       },
+       {
+               .type = &ao_scheme_string_type,
+               .addr = (void **) &save_string[0],
+       },
+       {
+               .type = &ao_scheme_string_type,
+               .addr = (void **) &save_string[1],
+       },
+       {
+               .type = &ao_scheme_frame_type,
+               .addr = (void **) &save_frame[0],
+       },
+       {
+               .type = NULL,
+               .addr = (void **) (void *) &save_poly[0]
+       },
+       {
+               .type = NULL,
+               .addr = (void **) (void *) &save_poly[1]
+       },
+       {
+               .type = NULL,
+               .addr = (void **) (void *) &save_poly[2]
+       },
+       {
+               .type = &ao_scheme_atom_type,
+               .addr = (void **) &ao_scheme_atoms
+       },
+       {
+               .type = &ao_scheme_frame_type,
+               .addr = (void **) &ao_scheme_frame_global,
+       },
+       {
+               .type = &ao_scheme_frame_type,
+               .addr = (void **) &ao_scheme_frame_current,
+       },
+       {
+               .type = &ao_scheme_stack_type,
+               .addr = (void **) &ao_scheme_stack,
+       },
+       {
+               .type = NULL,
+               .addr = (void **) (void *) &ao_scheme_v,
+       },
+       {
+               .type = &ao_scheme_cons_type,
+               .addr = (void **) &ao_scheme_read_cons,
+       },
+       {
+               .type = &ao_scheme_cons_type,
+               .addr = (void **) &ao_scheme_read_cons_tail,
+       },
+       {
+               .type = &ao_scheme_cons_type,
+               .addr = (void **) &ao_scheme_read_stack,
+       },
+#ifdef AO_SCHEME_MAKE_CONST
+       {
+               .type = &ao_scheme_bool_type,
+               .addr = (void **) &ao_scheme_false,
+       },
+       {
+               .type = &ao_scheme_bool_type,
+               .addr = (void **) &ao_scheme_true,
+       },
+#endif
+};
+
+#define AO_SCHEME_ROOT (sizeof (ao_scheme_root) / sizeof (ao_scheme_root[0]))
+
+static const void ** const ao_scheme_cache[] = {
+       (const void **) &ao_scheme_cons_free_list,
+       (const void **) &ao_scheme_stack_free_list,
+       (const void **) &ao_scheme_frame_free_list[0],
+       (const void **) &ao_scheme_frame_free_list[1],
+       (const void **) &ao_scheme_frame_free_list[2],
+       (const void **) &ao_scheme_frame_free_list[3],
+       (const void **) &ao_scheme_frame_free_list[4],
+       (const void **) &ao_scheme_frame_free_list[5],
+};
+
+#if AO_SCHEME_FRAME_FREE != 6
+#error Unexpected AO_SCHEME_FRAME_FREE value
+#endif
+
+#define AO_SCHEME_CACHE        (sizeof (ao_scheme_cache) / sizeof (ao_scheme_cache[0]))
+
+#define AO_SCHEME_BUSY_SIZE    ((AO_SCHEME_POOL + 31) / 32)
+
+static uint8_t ao_scheme_busy[AO_SCHEME_BUSY_SIZE];
+static uint8_t ao_scheme_cons_note[AO_SCHEME_BUSY_SIZE];
+static uint8_t ao_scheme_cons_last[AO_SCHEME_BUSY_SIZE];
+static uint8_t ao_scheme_cons_noted;
+
+uint16_t       ao_scheme_top;
+
+struct ao_scheme_chunk {
+       uint16_t                old_offset;
+       union {
+               uint16_t        size;
+               uint16_t        new_offset;
+       };
+};
+
+#define AO_SCHEME_NCHUNK       64
+
+static struct ao_scheme_chunk ao_scheme_chunk[AO_SCHEME_NCHUNK];
+
+/* Offset of an address within the pool. */
+static inline uint16_t pool_offset(void *addr) {
+#if DBG_MEM
+       if (!AO_SCHEME_IS_POOL(addr))
+               ao_scheme_abort();
+#endif
+       return ((uint8_t *) addr) - ao_scheme_pool;
+}
+
+static inline void mark(uint8_t *tag, int offset) {
+       int     byte = offset >> 5;
+       int     bit = (offset >> 2) & 7;
+       tag[byte] |= (1 << bit);
+}
+
+static inline void clear(uint8_t *tag, int offset) {
+       int     byte = offset >> 5;
+       int     bit = (offset >> 2) & 7;
+       tag[byte] &= ~(1 << bit);
+}
+
+static inline int busy(uint8_t *tag, int offset) {
+       int     byte = offset >> 5;
+       int     bit = (offset >> 2) & 7;
+       return (tag[byte] >> bit) & 1;
+}
+
+static inline int min(int a, int b) { return a < b ? a : b; }
+static inline int max(int a, int b) { return a > b ? a : b; }
+
+static inline int limit(int offset) {
+       return min(AO_SCHEME_POOL, max(offset, 0));
+}
+
+static void
+note_cons(uint16_t offset)
+{
+       MDBG_MOVE("note cons %d\n", offset);
+       ao_scheme_cons_noted = 1;
+       mark(ao_scheme_cons_note, offset);
+}
+
+static uint16_t        chunk_low, chunk_high;
+static uint16_t        chunk_first, chunk_last;
+
+static int
+find_chunk(uint16_t offset)
+{
+       int l, r;
+       /* Binary search for the location */
+       l = chunk_first;
+       r = chunk_last - 1;
+       while (l <= r) {
+               int m = (l + r) >> 1;
+               if (ao_scheme_chunk[m].old_offset < offset)
+                       l = m + 1;
+               else
+                       r = m - 1;
+       }
+       return l;
+}
+
+static void
+note_chunk(uint16_t offset, uint16_t size)
+{
+       int l;
+
+       if (offset < chunk_low || chunk_high <= offset)
+               return;
+
+       l = find_chunk(offset);
+
+       /*
+        * The correct location is always in 'l', with r = l-1 being
+        * the entry before the right one
+        */
+
+#if DBG_MEM
+       /* Off the right side */
+       if (l >= AO_SCHEME_NCHUNK)
+               ao_scheme_abort();
+
+       /* Off the left side */
+       if (l == 0 && chunk_last && offset > ao_scheme_chunk[0].old_offset)
+               ao_scheme_abort();
+#endif
+
+       /* Shuffle existing entries right */
+       int end = min(AO_SCHEME_NCHUNK, chunk_last + 1);
+
+       memmove(&ao_scheme_chunk[l+1],
+               &ao_scheme_chunk[l],
+               (end - (l+1)) * sizeof (struct ao_scheme_chunk));
+
+       /* Add new entry */
+       ao_scheme_chunk[l].old_offset = offset;
+       ao_scheme_chunk[l].size = size;
+
+       /* Increment the number of elements up to the size of the array */
+       if (chunk_last < AO_SCHEME_NCHUNK)
+               chunk_last++;
+
+       /* Set the top address if the array is full */
+       if (chunk_last == AO_SCHEME_NCHUNK)
+               chunk_high = ao_scheme_chunk[AO_SCHEME_NCHUNK-1].old_offset +
+                       ao_scheme_chunk[AO_SCHEME_NCHUNK-1].size;
+}
+
+static void
+reset_chunks(void)
+{
+       chunk_high = ao_scheme_top;
+       chunk_last = 0;
+       chunk_first = 0;
+}
+
+/*
+ * Walk all referenced objects calling functions on each one
+ */
+
+static void
+walk(int (*visit_addr)(const struct ao_scheme_type *type, void **addr),
+     int (*visit_poly)(ao_poly *p, uint8_t do_note_cons))
+{
+       int i;
+
+       ao_scheme_record_reset();
+       memset(ao_scheme_busy, '\0', sizeof (ao_scheme_busy));
+       memset(ao_scheme_cons_note, '\0', sizeof (ao_scheme_cons_note));
+       ao_scheme_cons_noted = 0;
+       for (i = 0; i < (int) AO_SCHEME_ROOT; i++) {
+               if (ao_scheme_root[i].type) {
+                       void **a = ao_scheme_root[i].addr, *v;
+                       if (a && (v = *a)) {
+                               MDBG_MOVE("root ptr %d\n", MDBG_OFFSET(v));
+                               visit_addr(ao_scheme_root[i].type, a);
+                       }
+               } else {
+                       ao_poly *a = (ao_poly *) ao_scheme_root[i].addr, p;
+                       if (a && (p = *a)) {
+                               MDBG_MOVE("root poly %d\n", MDBG_OFFSET(ao_scheme_ref(p)));
+                               visit_poly(a, 0);
+                       }
+               }
+       }
+       while (ao_scheme_cons_noted) {
+               memcpy(ao_scheme_cons_last, ao_scheme_cons_note, sizeof (ao_scheme_cons_note));
+               memset(ao_scheme_cons_note, '\0', sizeof (ao_scheme_cons_note));
+               ao_scheme_cons_noted = 0;
+               for (i = 0; i < AO_SCHEME_POOL; i += 4) {
+                       if (busy(ao_scheme_cons_last, i)) {
+                               void *v = ao_scheme_pool + i;
+                               MDBG_MOVE("root cons %d\n", MDBG_OFFSET(v));
+                               visit_addr(&ao_scheme_cons_type, &v);
+                       }
+               }
+       }
+}
+
+#if MDBG_DUMP
+static void
+dump_busy(void)
+{
+       int     i;
+       MDBG_MOVE("busy:");
+       for (i = 0; i < ao_scheme_top; i += 4) {
+               if ((i & 0xff) == 0) {
+                       MDBG_MORE("\n");
+                       MDBG_MOVE("%s", "");
+               }
+               else if ((i & 0x1f) == 0)
+                       MDBG_MORE(" ");
+               if (busy(ao_scheme_busy, i))
+                       MDBG_MORE("*");
+               else
+                       MDBG_MORE("-");
+       }
+       MDBG_MORE ("\n");
+}
+#define DUMP_BUSY()    dump_busy()
+#else
+#define DUMP_BUSY()
+#endif
+
+static const struct ao_scheme_type * const ao_scheme_types[AO_SCHEME_NUM_TYPE] = {
+       [AO_SCHEME_CONS] = &ao_scheme_cons_type,
+       [AO_SCHEME_INT] = NULL,
+       [AO_SCHEME_STRING] = &ao_scheme_string_type,
+       [AO_SCHEME_OTHER] = (void *) 0x1,
+       [AO_SCHEME_ATOM] = &ao_scheme_atom_type,
+       [AO_SCHEME_BUILTIN] = &ao_scheme_builtin_type,
+       [AO_SCHEME_FRAME] = &ao_scheme_frame_type,
+       [AO_SCHEME_FRAME_VALS] = &ao_scheme_frame_vals_type,
+       [AO_SCHEME_LAMBDA] = &ao_scheme_lambda_type,
+       [AO_SCHEME_STACK] = &ao_scheme_stack_type,
+       [AO_SCHEME_BOOL] = &ao_scheme_bool_type,
+       [AO_SCHEME_BIGINT] = &ao_scheme_bigint_type,
+       [AO_SCHEME_FLOAT] = &ao_scheme_float_type,
+       [AO_SCHEME_VECTOR] = &ao_scheme_vector_type,
+};
+
+static int
+ao_scheme_mark_ref(const struct ao_scheme_type *type, void **ref)
+{
+       return ao_scheme_mark(type, *ref);
+}
+
+static int
+ao_scheme_poly_mark_ref(ao_poly *p, uint8_t do_note_cons)
+{
+       return ao_scheme_poly_mark(*p, do_note_cons);
+}
+
+#if DBG_MEM_STATS
+uint64_t ao_scheme_collects[2];
+uint64_t ao_scheme_freed[2];
+uint64_t ao_scheme_loops[2];
+#endif
+
+int ao_scheme_last_top;
+
+int
+ao_scheme_collect(uint8_t style)
+{
+       int     i;
+       int     top;
+#if DBG_MEM_STATS
+       int     loops = 0;
+#endif
+#if DBG_MEM
+       struct ao_scheme_record *mark_record = NULL, *move_record = NULL;
+
+       MDBG_MOVE("collect %d\n", ao_scheme_collects[style]);
+#endif
+       MDBG_DO(ao_scheme_frame_write(ao_scheme_frame_poly(ao_scheme_frame_global)));
+
+       /* The first time through, we're doing a full collect */
+       if (ao_scheme_last_top == 0)
+               style = AO_SCHEME_COLLECT_FULL;
+
+       /* Clear references to all caches */
+       for (i = 0; i < (int) AO_SCHEME_CACHE; i++)
+               *ao_scheme_cache[i] = NULL;
+       if (style == AO_SCHEME_COLLECT_FULL) {
+               chunk_low = top = 0;
+       } else {
+               chunk_low = top = ao_scheme_last_top;
+       }
+       for (;;) {
+#if DBG_MEM_STATS
+               loops++;
+#endif
+               MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top);
+               /* Find the sizes of the first chunk of objects to move */
+               reset_chunks();
+               walk(ao_scheme_mark_ref, ao_scheme_poly_mark_ref);
+#if DBG_MEM
+
+               ao_scheme_record_free(mark_record);
+               mark_record = ao_scheme_record_save();
+               if (mark_record && move_record)
+                       ao_scheme_record_compare("mark", move_record, mark_record);
+#endif
+
+               DUMP_BUSY();
+
+               /* Find the first moving object */
+               for (i = 0; i < chunk_last; i++) {
+                       uint16_t        size = ao_scheme_chunk[i].size;
+
+#if DBG_MEM
+                       if (!size)
+                               ao_scheme_abort();
+#endif
+
+                       if (ao_scheme_chunk[i].old_offset > top)
+                               break;
+
+                       MDBG_MOVE("chunk %d %d not moving\n",
+                                 ao_scheme_chunk[i].old_offset,
+                                 ao_scheme_chunk[i].size);
+#if DBG_MEM
+                       if (ao_scheme_chunk[i].old_offset != top)
+                               ao_scheme_abort();
+#endif
+                       top += size;
+               }
+
+               /*
+                * Limit amount of chunk array used in mapping moves
+                * to the active region
+                */
+               chunk_first = i;
+               chunk_low = ao_scheme_chunk[i].old_offset;
+
+               /* Copy all of the objects */
+               for (; i < chunk_last; i++) {
+                       uint16_t        size = ao_scheme_chunk[i].size;
+
+#if DBG_MEM
+                       if (!size)
+                               ao_scheme_abort();
+#endif
+
+                       MDBG_MOVE("chunk %d %d -> %d\n",
+                                 ao_scheme_chunk[i].old_offset,
+                                 size,
+                                 top);
+                       ao_scheme_chunk[i].new_offset = top;
+
+                       memmove(&ao_scheme_pool[top],
+                               &ao_scheme_pool[ao_scheme_chunk[i].old_offset],
+                               size);
+
+                       top += size;
+               }
+
+               if (chunk_first < chunk_last) {
+                       /* Relocate all references to the objects */
+                       walk(ao_scheme_move, ao_scheme_poly_move);
+
+#if DBG_MEM
+                       ao_scheme_record_free(move_record);
+                       move_record = ao_scheme_record_save();
+                       if (mark_record && move_record)
+                               ao_scheme_record_compare("move", mark_record, move_record);
+#endif
+               }
+
+               /* If we ran into the end of the heap, then
+                * there's no need to keep walking
+                */
+               if (chunk_last != AO_SCHEME_NCHUNK)
+                       break;
+
+               /* Next loop starts right above this loop */
+               chunk_low = chunk_high;
+       }
+
+#if DBG_MEM_STATS
+       /* Collect stats */
+       ++ao_scheme_collects[style];
+       ao_scheme_freed[style] += ao_scheme_top - top;
+       ao_scheme_loops[style] += loops;
+#endif
+
+       ao_scheme_top = top;
+       if (style == AO_SCHEME_COLLECT_FULL)
+               ao_scheme_last_top = top;
+
+       MDBG_DO(memset(ao_scheme_chunk, '\0', sizeof (ao_scheme_chunk));
+               walk(ao_scheme_mark_ref, ao_scheme_poly_mark_ref));
+
+       return AO_SCHEME_POOL - ao_scheme_top;
+}
+
+#if DBG_FREE_CONS
+void
+ao_scheme_cons_check(struct ao_scheme_cons *cons)
+{
+       ao_poly cdr;
+       int offset;
+
+       chunk_low = 0;
+       reset_chunks();
+       walk(ao_scheme_mark_ref, ao_scheme_poly_mark_ref);
+       while (cons) {
+               if (!AO_SCHEME_IS_POOL(cons))
+                       break;
+               offset = pool_offset(cons);
+               if (busy(ao_scheme_busy, offset)) {
+                       ao_scheme_printf("cons at %p offset %d poly %d is busy\n\t%v\n", cons, offset, ao_scheme_cons_poly(cons), ao_scheme_cons_poly(cons));
+                       abort();
+               }
+               cdr = cons->cdr;
+               if (!ao_scheme_is_pair(cdr))
+                       break;
+               cons = ao_scheme_poly_cons(cdr);
+       }
+}
+#endif
+
+/*
+ * Mark interfaces for objects
+ */
+
+
+/*
+ * Mark a block of memory with an explicit size
+ */
+
+int
+ao_scheme_mark_block(void *addr, int size)
+{
+       int offset;
+       if (!AO_SCHEME_IS_POOL(addr))
+               return 1;
+
+       offset = pool_offset(addr);
+       MDBG_MOVE("mark memory %d\n", MDBG_OFFSET(addr));
+       if (busy(ao_scheme_busy, offset)) {
+               MDBG_MOVE("already marked\n");
+               return 1;
+       }
+       mark(ao_scheme_busy, offset);
+       note_chunk(offset, size);
+       return 0;
+}
+
+/*
+ * Note a reference to memory and collect information about a few
+ * object sizes at a time
+ */
+
+int
+ao_scheme_mark_memory(const struct ao_scheme_type *type, void *addr)
+{
+       int offset;
+       if (!AO_SCHEME_IS_POOL(addr))
+               return 1;
+
+       offset = pool_offset(addr);
+       MDBG_MOVE("mark memory %d\n", MDBG_OFFSET(addr));
+       if (busy(ao_scheme_busy, offset)) {
+               MDBG_MOVE("already marked\n");
+               return 1;
+       }
+       mark(ao_scheme_busy, offset);
+       note_chunk(offset, ao_scheme_size(type, addr));
+       return 0;
+}
+
+/*
+ * Mark an object and all that it refereces
+ */
+int
+ao_scheme_mark(const struct ao_scheme_type *type, void *addr)
+{
+       int ret;
+       MDBG_MOVE("mark %d\n", MDBG_OFFSET(addr));
+       MDBG_MOVE_IN();
+       ret = ao_scheme_mark_memory(type, addr);
+       if (!ret) {
+               MDBG_MOVE("mark recurse\n");
+               type->mark(addr);
+       }
+       MDBG_MOVE_OUT();
+       return ret;
+}
+
+/*
+ * Mark an object, unless it is a cons cell and
+ * do_note_cons is set. In that case, just
+ * set a bit in the cons note array; those
+ * will be marked in a separate pass to avoid
+ * deep recursion in the collector
+ */
+int
+ao_scheme_poly_mark(ao_poly p, uint8_t do_note_cons)
+{
+       uint8_t type;
+       void    *addr;
+
+       type = ao_scheme_poly_base_type(p);
+
+       if (type == AO_SCHEME_INT)
+               return 1;
+
+       addr = ao_scheme_ref(p);
+       if (!AO_SCHEME_IS_POOL(addr))
+               return 1;
+
+       if (type == AO_SCHEME_CONS && do_note_cons) {
+               note_cons(pool_offset(addr));
+               return 1;
+       } else {
+               if (type == AO_SCHEME_OTHER)
+                       type = ao_scheme_other_type(addr);
+
+               const struct ao_scheme_type *lisp_type = ao_scheme_types[type];
+#if DBG_MEM
+               if (!lisp_type)
+                       ao_scheme_abort();
+#endif
+
+               return ao_scheme_mark(lisp_type, addr);
+       }
+}
+
+/*
+ * Find the current location of an object
+ * based on the original location. For unmoved
+ * objects, this is simple. For moved objects,
+ * go search for it
+ */
+
+static uint16_t
+move_map(uint16_t offset)
+{
+       int             l;
+
+       if (offset < chunk_low || chunk_high <= offset)
+               return offset;
+
+       l = find_chunk(offset);
+
+#if DBG_MEM
+       if (ao_scheme_chunk[l].old_offset != offset)
+               ao_scheme_abort();
+#endif
+       return ao_scheme_chunk[l].new_offset;
+}
+
+int
+ao_scheme_move_memory(const struct ao_scheme_type *type, void **ref)
+{
+       void            *addr = *ref;
+       uint16_t        offset, orig_offset;
+
+       if (!AO_SCHEME_IS_POOL(addr))
+               return 1;
+
+       (void) type;
+
+       MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr));
+       orig_offset = pool_offset(addr);
+       offset = move_map(orig_offset);
+       if (offset != orig_offset) {
+               MDBG_MOVE("update ref %d %d -> %d\n",
+                         AO_SCHEME_IS_POOL(ref) ? MDBG_OFFSET(ref) : -1,
+                         orig_offset, offset);
+               *ref = ao_scheme_pool + offset;
+       }
+       if (busy(ao_scheme_busy, offset)) {
+               MDBG_MOVE("already moved\n");
+               return 1;
+       }
+       mark(ao_scheme_busy, offset);
+       MDBG_DO(ao_scheme_record(type, addr, ao_scheme_size(type, addr)));
+       return 0;
+}
+
+int
+ao_scheme_move(const struct ao_scheme_type *type, void **ref)
+{
+       int ret;
+       MDBG_MOVE("move object %d\n", MDBG_OFFSET(*ref));
+       MDBG_MOVE_IN();
+       ret = ao_scheme_move_memory(type, ref);
+       if (!ret) {
+               MDBG_MOVE("move recurse\n");
+               type->move(*ref);
+       }
+       MDBG_MOVE_OUT();
+       return ret;
+}
+
+int
+ao_scheme_poly_move(ao_poly *ref, uint8_t do_note_cons)
+{
+       uint8_t         type;
+       ao_poly         p = *ref;
+       int             ret;
+       void            *addr;
+       uint16_t        offset, orig_offset;
+       uint8_t         base_type;
+
+       base_type = type = ao_scheme_poly_base_type(p);
+
+       if (type == AO_SCHEME_INT)
+               return 1;
+
+       addr = ao_scheme_ref(p);
+       if (!AO_SCHEME_IS_POOL(addr))
+               return 1;
+
+       orig_offset = pool_offset(addr);
+       offset = move_map(orig_offset);
+
+       if (type == AO_SCHEME_CONS && do_note_cons) {
+               note_cons(orig_offset);
+               ret = 1;
+       } else {
+               if (type == AO_SCHEME_OTHER)
+                       type = ao_scheme_other_type(ao_scheme_pool + offset);
+
+               const struct ao_scheme_type *lisp_type = ao_scheme_types[type];
+#if DBG_MEM
+               if (!lisp_type)
+                       ao_scheme_abort();
+#endif
+
+               ret = ao_scheme_move(lisp_type, &addr);
+       }
+
+       /* Re-write the poly value */
+       if (offset != orig_offset) {
+               ao_poly np = ao_scheme_poly(ao_scheme_pool + offset, base_type);
+               MDBG_MOVE("poly %d moved %d -> %d\n",
+                         type, orig_offset, offset);
+               *ref = np;
+       }
+       return ret;
+}
+
+#if DBG_MEM
+void
+ao_scheme_validate(void)
+{
+       chunk_low = 0;
+       memset(ao_scheme_chunk, '\0', sizeof (ao_scheme_chunk));
+       walk(ao_scheme_mark_ref, ao_scheme_poly_mark_ref);
+}
+
+int dbg_allocs;
+
+#endif
+
+void *
+ao_scheme_alloc(int size)
+{
+       void    *addr;
+
+       MDBG_DO(++dbg_allocs);
+       MDBG_DO(if (dbg_validate) ao_scheme_validate());
+       size = ao_scheme_size_round(size);
+       if (AO_SCHEME_POOL - ao_scheme_top < size &&
+           ao_scheme_collect(AO_SCHEME_COLLECT_INCREMENTAL) < size &&
+           ao_scheme_collect(AO_SCHEME_COLLECT_FULL) < size)
+       {
+               ao_scheme_error(AO_SCHEME_OOM, "out of memory");
+               return NULL;
+       }
+       addr = ao_scheme_pool + ao_scheme_top;
+       ao_scheme_top += size;
+       MDBG_MOVE("alloc %d size %d\n", MDBG_OFFSET(addr), size);
+       return addr;
+}
+
+void
+ao_scheme_cons_stash(int id, struct ao_scheme_cons *cons)
+{
+       assert(save_cons[id] == 0);
+       save_cons[id] = cons;
+}
+
+struct ao_scheme_cons *
+ao_scheme_cons_fetch(int id)
+{
+       struct ao_scheme_cons *cons = save_cons[id];
+       save_cons[id] = NULL;
+       return cons;
+}
+
+void
+ao_scheme_poly_stash(int id, ao_poly poly)
+{
+       assert(save_poly[id] == AO_SCHEME_NIL);
+       save_poly[id] = poly;
+}
+
+ao_poly
+ao_scheme_poly_fetch(int id)
+{
+       ao_poly poly = save_poly[id];
+       save_poly[id] = AO_SCHEME_NIL;
+       return poly;
+}
+
+void
+ao_scheme_string_stash(int id, char *string)
+{
+       assert(save_string[id] == NULL);
+       save_string[id] = string;
+}
+
+char *
+ao_scheme_string_fetch(int id)
+{
+       char *string = save_string[id];
+       save_string[id] = NULL;
+       return string;
+}
+
+void
+ao_scheme_frame_stash(int id, struct ao_scheme_frame *frame)
+{
+       assert(save_frame[id] == NULL);
+       save_frame[id] = frame;
+}
+
+struct ao_scheme_frame *
+ao_scheme_frame_fetch(int id)
+{
+       struct ao_scheme_frame *frame = save_frame[id];
+       save_frame[id] = NULL;
+       return frame;
+}
diff --git a/src/scheme/ao_scheme_poly.c b/src/scheme/ao_scheme_poly.c
new file mode 100644 (file)
index 0000000..553585d
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
+struct ao_scheme_funcs {
+       void (*write)(ao_poly);
+       void (*display)(ao_poly);
+};
+
+static const struct ao_scheme_funcs ao_scheme_funcs[AO_SCHEME_NUM_TYPE] = {
+       [AO_SCHEME_CONS] = {
+               .write = ao_scheme_cons_write,
+               .display = ao_scheme_cons_display,
+       },
+       [AO_SCHEME_STRING] = {
+               .write = ao_scheme_string_write,
+               .display = ao_scheme_string_display,
+       },
+       [AO_SCHEME_INT] = {
+               .write = ao_scheme_int_write,
+               .display = ao_scheme_int_write,
+       },
+       [AO_SCHEME_ATOM] = {
+               .write = ao_scheme_atom_write,
+               .display = ao_scheme_atom_write,
+       },
+       [AO_SCHEME_BUILTIN] = {
+               .write = ao_scheme_builtin_write,
+               .display = ao_scheme_builtin_write,
+       },
+       [AO_SCHEME_FRAME] = {
+               .write = ao_scheme_frame_write,
+               .display = ao_scheme_frame_write,
+       },
+       [AO_SCHEME_FRAME_VALS] = {
+               .write = NULL,
+               .display = NULL,
+       },
+       [AO_SCHEME_LAMBDA] = {
+               .write = ao_scheme_lambda_write,
+               .display = ao_scheme_lambda_write,
+       },
+       [AO_SCHEME_STACK] = {
+               .write = ao_scheme_stack_write,
+               .display = ao_scheme_stack_write,
+       },
+       [AO_SCHEME_BOOL] = {
+               .write = ao_scheme_bool_write,
+               .display = ao_scheme_bool_write,
+       },
+       [AO_SCHEME_BIGINT] = {
+               .write = ao_scheme_bigint_write,
+               .display = ao_scheme_bigint_write,
+       },
+       [AO_SCHEME_FLOAT] = {
+               .write = ao_scheme_float_write,
+               .display = ao_scheme_float_write,
+       },
+       [AO_SCHEME_VECTOR] = {
+               .write = ao_scheme_vector_write,
+               .display = ao_scheme_vector_display
+       },
+};
+
+static const struct ao_scheme_funcs *
+funcs(ao_poly p)
+{
+       uint8_t type = ao_scheme_poly_type(p);
+
+       if (type < AO_SCHEME_NUM_TYPE)
+               return &ao_scheme_funcs[type];
+       return NULL;
+}
+
+void
+ao_scheme_poly_write(ao_poly p)
+{
+       const struct ao_scheme_funcs *f = funcs(p);
+
+       if (f && f->write)
+               f->write(p);
+}
+
+void
+ao_scheme_poly_display(ao_poly p)
+{
+       const struct ao_scheme_funcs *f = funcs(p);
+
+       if (f && f->display)
+               f->display(p);
+}
+
+void *
+ao_scheme_ref(ao_poly poly) {
+       if (poly == AO_SCHEME_NIL)
+               return NULL;
+       if (poly & AO_SCHEME_CONST)
+               return (void *) (ao_scheme_const + (poly & AO_SCHEME_REF_MASK) - 4);
+       return (void *) (ao_scheme_pool + (poly & AO_SCHEME_REF_MASK) - 4);
+}
+
+ao_poly
+ao_scheme_poly(const void *addr, ao_poly type) {
+       const uint8_t   *a = addr;
+       if (a == NULL)
+               return AO_SCHEME_NIL;
+       if (AO_SCHEME_IS_CONST(a))
+               return AO_SCHEME_CONST | (a - ao_scheme_const + 4) | type;
+       return (a - ao_scheme_pool + 4) | type;
+}
diff --git a/src/scheme/ao_scheme_read.c b/src/scheme/ao_scheme_read.c
new file mode 100644 (file)
index 0000000..9ed54b9
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+#include "ao_scheme_read.h"
+#include <math.h>
+#include <stdlib.h>
+
+static const uint16_t  lex_classes[128] = {
+       IGNORE,         /* ^@ */
+       IGNORE,         /* ^A */
+       IGNORE,         /* ^B */
+       IGNORE,         /* ^C */
+       IGNORE,         /* ^D */
+       IGNORE,         /* ^E */
+       IGNORE,         /* ^F */
+       IGNORE,         /* ^G */
+       IGNORE,         /* ^H */
+       WHITE,          /* ^I */
+       WHITE,          /* ^J */
+       WHITE,          /* ^K */
+       WHITE,          /* ^L */
+       WHITE,          /* ^M */
+       IGNORE,         /* ^N */
+       IGNORE,         /* ^O */
+       IGNORE,         /* ^P */
+       IGNORE,         /* ^Q */
+       IGNORE,         /* ^R */
+       IGNORE,         /* ^S */
+       IGNORE,         /* ^T */
+       IGNORE,         /* ^U */
+       IGNORE,         /* ^V */
+       IGNORE,         /* ^W */
+       IGNORE,         /* ^X */
+       IGNORE,         /* ^Y */
+       IGNORE,         /* ^Z */
+       IGNORE,         /* ^[ */
+       IGNORE,         /* ^\ */
+       IGNORE,         /* ^] */
+       IGNORE,         /* ^^ */
+       IGNORE,         /* ^_ */
+       PRINTABLE|WHITE,        /*    */
+       PRINTABLE,              /* ! */
+       PRINTABLE|STRINGC,      /* " */
+       PRINTABLE|POUND,        /* # */
+       PRINTABLE,              /* $ */
+       PRINTABLE,              /* % */
+       PRINTABLE,              /* & */
+       PRINTABLE|SPECIAL,      /* ' */
+       PRINTABLE|SPECIAL,      /* ( */
+       PRINTABLE|SPECIAL,      /* ) */
+       PRINTABLE,              /* * */
+       PRINTABLE|SIGN,         /* + */
+       PRINTABLE|SPECIAL,      /* , */
+       PRINTABLE|SIGN,         /* - */
+       PRINTABLE|DOTC|FLOATC,  /* . */
+       PRINTABLE,              /* / */
+       PRINTABLE|DIGIT,        /* 0 */
+       PRINTABLE|DIGIT,        /* 1 */
+       PRINTABLE|DIGIT,        /* 2 */
+       PRINTABLE|DIGIT,        /* 3 */
+       PRINTABLE|DIGIT,        /* 4 */
+       PRINTABLE|DIGIT,        /* 5 */
+       PRINTABLE|DIGIT,        /* 6 */
+       PRINTABLE|DIGIT,        /* 7 */
+       PRINTABLE|DIGIT,        /* 8 */
+       PRINTABLE|DIGIT,        /* 9 */
+       PRINTABLE,              /* : */
+       PRINTABLE|COMMENT,      /* ; */
+       PRINTABLE,              /* < */
+       PRINTABLE,              /* = */
+       PRINTABLE,              /* > */
+       PRINTABLE,              /* ? */
+       PRINTABLE,              /*  @ */
+       PRINTABLE,              /*  A */
+       PRINTABLE,              /*  B */
+       PRINTABLE,              /*  C */
+       PRINTABLE,              /*  D */
+       PRINTABLE|FLOATC,       /*  E */
+       PRINTABLE,              /*  F */
+       PRINTABLE,              /*  G */
+       PRINTABLE,              /*  H */
+       PRINTABLE,              /*  I */
+       PRINTABLE,              /*  J */
+       PRINTABLE,              /*  K */
+       PRINTABLE,              /*  L */
+       PRINTABLE,              /*  M */
+       PRINTABLE,              /*  N */
+       PRINTABLE,              /*  O */
+       PRINTABLE,              /*  P */
+       PRINTABLE,              /*  Q */
+       PRINTABLE,              /*  R */
+       PRINTABLE,              /*  S */
+       PRINTABLE,              /*  T */
+       PRINTABLE,              /*  U */
+       PRINTABLE,              /*  V */
+       PRINTABLE,              /*  W */
+       PRINTABLE,              /*  X */
+       PRINTABLE,              /*  Y */
+       PRINTABLE,              /*  Z */
+       PRINTABLE,              /*  [ */
+       PRINTABLE|BACKSLASH,    /*  \ */
+       PRINTABLE,              /*  ] */
+       PRINTABLE,              /*  ^ */
+       PRINTABLE,              /*  _ */
+       PRINTABLE|SPECIAL,      /*  ` */
+       PRINTABLE,              /*  a */
+       PRINTABLE,              /*  b */
+       PRINTABLE,              /*  c */
+       PRINTABLE,              /*  d */
+       PRINTABLE|FLOATC,       /*  e */
+       PRINTABLE,              /*  f */
+       PRINTABLE,              /*  g */
+       PRINTABLE,              /*  h */
+       PRINTABLE,              /*  i */
+       PRINTABLE,              /*  j */
+       PRINTABLE,              /*  k */
+       PRINTABLE,              /*  l */
+       PRINTABLE,              /*  m */
+       PRINTABLE,              /*  n */
+       PRINTABLE,              /*  o */
+       PRINTABLE,              /*  p */
+       PRINTABLE,              /*  q */
+       PRINTABLE,              /*  r */
+       PRINTABLE,              /*  s */
+       PRINTABLE,              /*  t */
+       PRINTABLE,              /*  u */
+       PRINTABLE,              /*  v */
+       PRINTABLE,              /*  w */
+       PRINTABLE,              /*  x */
+       PRINTABLE,              /*  y */
+       PRINTABLE,              /*  z */
+       PRINTABLE,              /*  { */
+       PRINTABLE,              /*  | */
+       PRINTABLE,              /*  } */
+       PRINTABLE,              /*  ~ */
+       IGNORE,                 /*  ^? */
+};
+
+static int lex_unget_c;
+
+static inline int
+lex_get(void)
+{
+       int     c;
+       if (lex_unget_c) {
+               c = lex_unget_c;
+               lex_unget_c = 0;
+       } else {
+               c = ao_scheme_getc();
+       }
+       return c;
+}
+
+static inline void
+lex_unget(int c)
+{
+       if (c != EOF)
+               lex_unget_c = c;
+}
+
+static uint16_t        lex_class;
+
+static int
+lexc(void)
+{
+       int     c;
+       do {
+               c = lex_get();
+               if (c == EOF) {
+                       c = 0;
+                       lex_class = ENDOFFILE;
+               } else {
+                       c &= 0x7f;
+                       lex_class = lex_classes[c];
+               }
+       } while (lex_class & IGNORE);
+       return c;
+}
+
+static int
+lex_quoted(void)
+{
+       int     c;
+       int     v;
+       int     count;
+
+       c = lex_get();
+       if (c == EOF) {
+               lex_class = ENDOFFILE;
+               return 0;
+       }
+       lex_class = 0;
+       c &= 0x7f;
+       switch (c) {
+       case 'n':
+               return '\n';
+       case 'f':
+               return '\f';
+       case 'b':
+               return '\b';
+       case 'r':
+               return '\r';
+       case 'v':
+               return '\v';
+       case 't':
+               return '\t';
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+               v = c - '0';
+               count = 1;
+               while (count <= 3) {
+                       c = lex_get();
+                       if (c == EOF)
+                               return EOF;
+                       c &= 0x7f;
+                       if (c < '0' || '7' < c) {
+                               lex_unget(c);
+                               break;
+                       }
+                       v = (v << 3) + c - '0';
+                       ++count;
+               }
+               return v;
+       default:
+               return c;
+       }
+}
+
+#define AO_SCHEME_TOKEN_MAX    128
+
+static char    token_string[AO_SCHEME_TOKEN_MAX];
+static int32_t token_int;
+static int     token_len;
+static float   token_float;
+
+static inline void add_token(int c) {
+       if (c && token_len < AO_SCHEME_TOKEN_MAX - 1)
+               token_string[token_len++] = c;
+}
+
+static inline void del_token(void) {
+       if (token_len > 0)
+               token_len--;
+}
+
+static inline void end_token(void) {
+       token_string[token_len] = '\0';
+}
+
+struct namedfloat {
+       const char      *name;
+       float           value;
+};
+
+static const struct namedfloat namedfloats[] = {
+       { .name = "+inf.0", .value = INFINITY },
+       { .name = "-inf.0", .value = -INFINITY },
+       { .name = "+nan.0", .value = NAN },
+       { .name = "-nan.0", .value = NAN },
+};
+
+#define NUM_NAMED_FLOATS       (sizeof namedfloats / sizeof namedfloats[0])
+
+static int
+_lex(void)
+{
+       int     c;
+
+       token_len = 0;
+       for (;;) {
+               c = lexc();
+               if (lex_class & ENDOFFILE)
+                       return END;
+
+               if (lex_class & WHITE)
+                       continue;
+
+               if (lex_class & COMMENT) {
+                       while ((c = lexc()) != '\n') {
+                               if (lex_class & ENDOFFILE)
+                                       return END;
+                       }
+                       continue;
+               }
+
+               if (lex_class & (SPECIAL|DOTC)) {
+                       add_token(c);
+                       end_token();
+                       switch (c) {
+                       case '(':
+                       case '[':
+                               return OPEN;
+                       case ')':
+                       case ']':
+                               return CLOSE;
+                       case '\'':
+                               return QUOTE;
+                       case '.':
+                               return DOT;
+                       case '`':
+                               return QUASIQUOTE;
+                       case ',':
+                               c = lexc();
+                               if (c == '@') {
+                                       add_token(c);
+                                       end_token();
+                                       return UNQUOTE_SPLICING;
+                               } else {
+                                       lex_unget(c);
+                                       return UNQUOTE;
+                               }
+                       }
+               }
+               if (lex_class & POUND) {
+                       c = lexc();
+                       switch (c) {
+                       case 't':
+                               add_token(c);
+                               end_token();
+                               return BOOL;
+                       case 'f':
+                               add_token(c);
+                               end_token();
+                               return BOOL;
+                       case '(':
+                               return OPEN_VECTOR;
+                       case '\\':
+                               for (;;) {
+                                       int alphabetic;
+                                       c = lexc();
+                                       alphabetic = (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
+                                       if (token_len == 0) {
+                                               add_token(c);
+                                               if (!alphabetic)
+                                                       break;
+                                       } else {
+                                               if (alphabetic)
+                                                       add_token(c);
+                                               else {
+                                                       lex_unget(c);
+                                                       break;
+                                               }
+                                       }
+                               }
+                               end_token();
+                               if (token_len == 1)
+                                       token_int = token_string[0];
+                               else if (!strcmp(token_string, "space"))
+                                       token_int = ' ';
+                               else if (!strcmp(token_string, "newline"))
+                                       token_int = '\n';
+                               else if (!strcmp(token_string, "tab"))
+                                       token_int = '\t';
+                               else if (!strcmp(token_string, "return"))
+                                       token_int = '\r';
+                               else if (!strcmp(token_string, "formfeed"))
+                                       token_int = '\f';
+                               else {
+                                       ao_scheme_error(AO_SCHEME_INVALID, "invalid character token #\\%s", token_string);
+                                       continue;
+                               }
+                               return NUM;
+                       }
+               }
+               if (lex_class & STRINGC) {
+                       for (;;) {
+                               c = lexc();
+                               if (lex_class & BACKSLASH)
+                                       c = lex_quoted();
+                               if (lex_class & (STRINGC|ENDOFFILE)) {
+                                       end_token();
+                                       return STRING;
+                               }
+                               add_token(c);
+                       }
+               }
+               if (lex_class & PRINTABLE) {
+                       int     isfloat;
+                       int     hasdigit;
+                       int     isneg;
+                       int     isint;
+                       int     epos;
+
+                       isfloat = 1;
+                       isint = 1;
+                       hasdigit = 0;
+                       token_int = 0;
+                       isneg = 0;
+                       epos = 0;
+                       for (;;) {
+                               if (!(lex_class & NUMBER)) {
+                                       isint = 0;
+                                       isfloat = 0;
+                               } else {
+                                       if (!(lex_class & INTEGER))
+                                               isint = 0;
+                                       if (token_len != epos &&
+                                           (lex_class & SIGN))
+                                       {
+                                               isint = 0;
+                                               isfloat = 0;
+                                       }
+                                       if (c == '-')
+                                               isneg = 1;
+                                       if (c == '.' && epos != 0)
+                                               isfloat = 0;
+                                       if (c == 'e' || c == 'E') {
+                                               if (token_len == 0)
+                                                       isfloat = 0;
+                                               else
+                                                       epos = token_len + 1;
+                                       }
+                                       if (lex_class & DIGIT) {
+                                               hasdigit = 1;
+                                               if (isint)
+                                                       token_int = token_int * 10 + c - '0';
+                                       }
+                               }
+                               add_token (c);
+                               c = lexc ();
+                               if ((lex_class & (NOTNAME)) && (c != '.' || !isfloat)) {
+                                       unsigned int u;
+//                                     if (lex_class & ENDOFFILE)
+//                                             clearerr (f);
+                                       lex_unget(c);
+                                       end_token ();
+                                       if (isint && hasdigit) {
+                                               if (isneg)
+                                                       token_int = -token_int;
+                                               return NUM;
+                                       }
+                                       if (isfloat && hasdigit) {
+                                               token_float = strtof(token_string, NULL);
+                                               return FLOAT;
+                                       }
+                                       for (u = 0; u < NUM_NAMED_FLOATS; u++)
+                                               if (!strcmp(namedfloats[u].name, token_string)) {
+                                                       token_float = namedfloats[u].value;
+                                                       return FLOAT;
+                                               }
+                                       return NAME;
+                               }
+                       }
+               }
+       }
+}
+
+static inline int lex(void)
+{
+       int     parse_token = _lex();
+       RDBGI("token %d (%s)\n", parse_token, token_string);
+       return parse_token;
+}
+
+static int parse_token;
+
+int                    ao_scheme_read_list;
+struct ao_scheme_cons  *ao_scheme_read_cons;
+struct ao_scheme_cons  *ao_scheme_read_cons_tail;
+struct ao_scheme_cons  *ao_scheme_read_stack;
+static int             ao_scheme_read_state;
+
+#define READ_IN_QUOTE  0x01
+#define READ_SAW_DOT   0x02
+#define READ_DONE_DOT  0x04
+#define READ_SAW_VECTOR        0x08
+
+static int
+push_read_stack(int read_state)
+{
+       RDBGI("push read stack %p 0x%x\n", ao_scheme_read_cons, read_state);
+       RDBG_IN();
+       if (ao_scheme_read_list) {
+               ao_scheme_read_stack = ao_scheme_cons_cons(ao_scheme_cons_poly(ao_scheme_read_cons),
+                                                      ao_scheme__cons(ao_scheme_int_poly(read_state),
+                                                                    ao_scheme_cons_poly(ao_scheme_read_stack)));
+               if (!ao_scheme_read_stack)
+                       return 0;
+       } else
+               ao_scheme_read_state = read_state;
+       ao_scheme_read_cons = NULL;
+       ao_scheme_read_cons_tail = NULL;
+       return 1;
+}
+
+static int
+pop_read_stack(void)
+{
+       int     read_state = 0;
+       if (ao_scheme_read_list) {
+               ao_scheme_read_cons = ao_scheme_poly_cons(ao_scheme_read_stack->car);
+               ao_scheme_read_stack = ao_scheme_poly_cons(ao_scheme_read_stack->cdr);
+               read_state = ao_scheme_poly_int(ao_scheme_read_stack->car);
+               ao_scheme_read_stack = ao_scheme_poly_cons(ao_scheme_read_stack->cdr);
+               for (ao_scheme_read_cons_tail = ao_scheme_read_cons;
+                    ao_scheme_read_cons_tail && ao_scheme_read_cons_tail->cdr;
+                    ao_scheme_read_cons_tail = ao_scheme_poly_cons(ao_scheme_read_cons_tail->cdr))
+                       ;
+       } else {
+               ao_scheme_read_cons = 0;
+               ao_scheme_read_cons_tail = 0;
+               ao_scheme_read_stack = 0;
+               read_state = ao_scheme_read_state;
+       }
+       RDBG_OUT();
+       RDBGI("pop read stack %p %d\n", ao_scheme_read_cons, read_state);
+       return read_state;
+}
+
+ao_poly
+ao_scheme_read(void)
+{
+       struct ao_scheme_atom   *atom;
+       char                    *string;
+       int                     read_state;
+       ao_poly                 v = AO_SCHEME_NIL;
+
+       ao_scheme_read_list = 0;
+       read_state = 0;
+       ao_scheme_read_cons = ao_scheme_read_cons_tail = ao_scheme_read_stack = 0;
+       for (;;) {
+               parse_token = lex();
+               while (parse_token == OPEN || parse_token == OPEN_VECTOR) {
+                       if (parse_token == OPEN_VECTOR)
+                               read_state |= READ_SAW_VECTOR;
+                       if (!push_read_stack(read_state))
+                               return AO_SCHEME_NIL;
+                       ao_scheme_read_list++;
+                       read_state = 0;
+                       parse_token = lex();
+               }
+
+               switch (parse_token) {
+               case END:
+               default:
+                       if (ao_scheme_read_list)
+                               ao_scheme_error(AO_SCHEME_EOF, "unexpected end of file");
+                       return _ao_scheme_atom_eof;
+                       break;
+               case NAME:
+                       atom = ao_scheme_atom_intern(token_string);
+                       if (atom)
+                               v = ao_scheme_atom_poly(atom);
+                       else
+                               v = AO_SCHEME_NIL;
+                       break;
+               case NUM:
+                       v = ao_scheme_integer_poly(token_int);
+                       break;
+               case FLOAT:
+                       v = ao_scheme_float_get(token_float);
+                       break;
+               case BOOL:
+                       if (token_string[0] == 't')
+                               v = _ao_scheme_bool_true;
+                       else
+                               v = _ao_scheme_bool_false;
+                       break;
+               case STRING:
+                       string = ao_scheme_string_copy(token_string);
+                       if (string)
+                               v = ao_scheme_string_poly(string);
+                       else
+                               v = AO_SCHEME_NIL;
+                       break;
+               case QUOTE:
+               case QUASIQUOTE:
+               case UNQUOTE:
+               case UNQUOTE_SPLICING:
+                       if (!push_read_stack(read_state))
+                               return AO_SCHEME_NIL;
+                       ao_scheme_read_list++;
+                       read_state = READ_IN_QUOTE;
+                       switch (parse_token) {
+                       case QUOTE:
+                               v = _ao_scheme_atom_quote;
+                               break;
+                       case QUASIQUOTE:
+                               v = _ao_scheme_atom_quasiquote;
+                               break;
+                       case UNQUOTE:
+                               v = _ao_scheme_atom_unquote;
+                               break;
+                       case UNQUOTE_SPLICING:
+                               v = _ao_scheme_atom_unquote2dsplicing;
+                               break;
+                       }
+                       break;
+               case CLOSE:
+                       if (!ao_scheme_read_list) {
+                               v = AO_SCHEME_NIL;
+                               break;
+                       }
+                       v = ao_scheme_cons_poly(ao_scheme_read_cons);
+                       --ao_scheme_read_list;
+                       read_state = pop_read_stack();
+                       if (read_state & READ_SAW_VECTOR)
+                               v = ao_scheme_vector_poly(ao_scheme_list_to_vector(ao_scheme_poly_cons(v)));
+                       break;
+               case DOT:
+                       if (!ao_scheme_read_list) {
+                               ao_scheme_error(AO_SCHEME_INVALID, ". outside of cons");
+                               return AO_SCHEME_NIL;
+                       }
+                       if (!ao_scheme_read_cons) {
+                               ao_scheme_error(AO_SCHEME_INVALID, ". first in cons");
+                               return AO_SCHEME_NIL;
+                       }
+                       read_state |= READ_SAW_DOT;
+                       continue;
+               }
+
+               /* loop over QUOTE ends */
+               for (;;) {
+                       if (!ao_scheme_read_list)
+                               return v;
+
+                       if (read_state & READ_DONE_DOT) {
+                               ao_scheme_error(AO_SCHEME_INVALID, ". not last in cons");
+                               return AO_SCHEME_NIL;
+                       }
+
+                       if (read_state & READ_SAW_DOT) {
+                               read_state |= READ_DONE_DOT;
+                               ao_scheme_read_cons_tail->cdr = v;
+                       } else {
+                               struct ao_scheme_cons   *read = ao_scheme_cons_cons(v, AO_SCHEME_NIL);
+                               if (!read)
+                                       return AO_SCHEME_NIL;
+
+                               if (ao_scheme_read_cons_tail)
+                                       ao_scheme_read_cons_tail->cdr = ao_scheme_cons_poly(read);
+                               else
+                                       ao_scheme_read_cons = read;
+                               ao_scheme_read_cons_tail = read;
+                       }
+
+                       if (!(read_state & READ_IN_QUOTE) || !ao_scheme_read_cons->cdr)
+                               break;
+
+                       v = ao_scheme_cons_poly(ao_scheme_read_cons);
+                       --ao_scheme_read_list;
+                       read_state = pop_read_stack();
+               }
+       }
+       return v;
+}
diff --git a/src/scheme/ao_scheme_read.h b/src/scheme/ao_scheme_read.h
new file mode 100644 (file)
index 0000000..e10a7d0
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_SCHEME_READ_H_
+#define _AO_SCHEME_READ_H_
+
+/*
+ * token classes
+ */
+
+# define END                   0
+# define NAME                  1
+# define OPEN                          2
+# define CLOSE                 3
+# define QUOTE                 4
+# define QUASIQUOTE            5
+# define UNQUOTE               6
+# define UNQUOTE_SPLICING      7
+# define STRING                        8
+# define NUM                   9
+# define FLOAT                 10
+# define DOT                   11
+# define BOOL                  12
+# define OPEN_VECTOR           13
+
+/*
+ * character classes
+ */
+
+# define PRINTABLE     0x0001  /* \t \n ' ' - ~ */
+# define SPECIAL       0x0002  /* ( [ { ) ] } ' ` , */
+# define DOTC          0x0004  /* . */
+# define WHITE         0x0008  /* ' ' \t \n */
+# define DIGIT         0x0010  /* [0-9] */
+# define SIGN          0x0020  /* +- */
+# define FLOATC                0x0040  /* . e E */
+# define ENDOFFILE     0x0080  /* end of file */
+# define COMMENT       0x0100  /* ; */
+# define IGNORE                0x0200  /* \0 - ' ' */
+# define BACKSLASH     0x0400  /* \ */
+# define STRINGC       0x0800  /* " */
+# define POUND         0x1000  /* # */
+
+# define NOTNAME       (STRINGC|COMMENT|ENDOFFILE|WHITE|SPECIAL)
+# define INTEGER       (DIGIT|SIGN)
+# define NUMBER                (INTEGER|FLOATC)
+
+#endif /* _AO_SCHEME_READ_H_ */
diff --git a/src/scheme/ao_scheme_rep.c b/src/scheme/ao_scheme_rep.c
new file mode 100644 (file)
index 0000000..5b94d94
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
+ao_poly
+ao_scheme_read_eval_print(void)
+{
+       ao_poly in, out = AO_SCHEME_NIL;
+
+       ao_scheme_exception = 0;
+       for(;;) {
+               in = ao_scheme_read();
+               if (in == _ao_scheme_atom_eof)
+                       break;
+               out = ao_scheme_eval(in);
+               if (ao_scheme_exception) {
+                       if (ao_scheme_exception & AO_SCHEME_EXIT)
+                               break;
+                       ao_scheme_exception = 0;
+               } else {
+                       ao_scheme_poly_write(out);
+                       putchar ('\n');
+               }
+       }
+       return out;
+}
diff --git a/src/scheme/ao_scheme_save.c b/src/scheme/ao_scheme_save.c
new file mode 100644 (file)
index 0000000..af9345b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
+ao_poly
+ao_scheme_do_save(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_save, cons, 0, 0))
+               return AO_SCHEME_NIL;
+
+#ifdef AO_SCHEME_SAVE
+       struct ao_scheme_os_save *os = (struct ao_scheme_os_save *) (void *) &ao_scheme_pool[AO_SCHEME_POOL];
+
+       ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
+       os->atoms = ao_scheme_atom_poly(ao_scheme_atoms);
+       os->globals = ao_scheme_frame_poly(ao_scheme_frame_global);
+       os->const_checksum = ao_scheme_const_checksum;
+       os->const_checksum_inv = (uint16_t) ~ao_scheme_const_checksum;
+
+       if (ao_scheme_os_save())
+               return _ao_scheme_bool_true;
+#endif
+       return _ao_scheme_bool_false;
+}
+
+ao_poly
+ao_scheme_do_restore(struct ao_scheme_cons *cons)
+{
+       if (!ao_scheme_check_argc(_ao_scheme_atom_save, cons, 0, 0))
+               return AO_SCHEME_NIL;
+
+#ifdef AO_SCHEME_SAVE
+       struct ao_scheme_os_save save;
+       struct ao_scheme_os_save *os = (struct ao_scheme_os_save *) (void *) &ao_scheme_pool[AO_SCHEME_POOL];
+
+       if (!ao_scheme_os_restore_save(&save, AO_SCHEME_POOL))
+               return ao_scheme_error(AO_SCHEME_INVALID, "header restore failed");
+
+       if (save.const_checksum != ao_scheme_const_checksum ||
+           save.const_checksum_inv != (uint16_t) ~ao_scheme_const_checksum)
+       {
+               return ao_scheme_error(AO_SCHEME_INVALID, "image is corrupted or stale");
+       }
+
+       if (ao_scheme_os_restore()) {
+
+               ao_scheme_atoms = ao_scheme_poly_atom(os->atoms);
+               ao_scheme_frame_global = ao_scheme_poly_frame(os->globals);
+
+               /* Clear the eval global variabls */
+               ao_scheme_eval_clear_globals();
+
+               /* Reset the allocator */
+               ao_scheme_top = AO_SCHEME_POOL;
+               ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
+
+               /* Re-create the evaluator stack */
+               if (!ao_scheme_eval_restart())
+                       return _ao_scheme_bool_false;
+
+               return _ao_scheme_bool_true;
+       }
+#endif
+       return _ao_scheme_bool_false;
+}
diff --git a/src/scheme/ao_scheme_stack.c b/src/scheme/ao_scheme_stack.c
new file mode 100644 (file)
index 0000000..d19dd6d
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+
+const struct ao_scheme_type ao_scheme_stack_type;
+
+static int
+stack_size(void *addr)
+{
+       (void) addr;
+       return sizeof (struct ao_scheme_stack);
+}
+
+static void
+stack_mark(void *addr)
+{
+       struct ao_scheme_stack  *stack = addr;
+       for (;;) {
+               ao_scheme_poly_mark(stack->sexprs, 0);
+               ao_scheme_poly_mark(stack->values, 0);
+               /* no need to mark values_tail */
+               ao_scheme_poly_mark(stack->frame, 0);
+               ao_scheme_poly_mark(stack->list, 0);
+               stack = ao_scheme_poly_stack(stack->prev);
+               if (ao_scheme_mark_memory(&ao_scheme_stack_type, stack))
+                       break;
+       }
+}
+
+static void
+stack_move(void *addr)
+{
+       struct ao_scheme_stack  *stack = addr;
+
+       while (stack) {
+               struct ao_scheme_stack  *prev;
+               int                     ret;
+               (void) ao_scheme_poly_move(&stack->sexprs, 0);
+               (void) ao_scheme_poly_move(&stack->values, 0);
+               (void) ao_scheme_poly_move(&stack->values_tail, 0);
+               (void) ao_scheme_poly_move(&stack->frame, 0);
+               (void) ao_scheme_poly_move(&stack->list, 0);
+               prev = ao_scheme_poly_stack(stack->prev);
+               if (!prev)
+                       break;
+               ret = ao_scheme_move_memory(&ao_scheme_stack_type, (void **) &prev);
+               if (prev != ao_scheme_poly_stack(stack->prev))
+                       stack->prev = ao_scheme_stack_poly(prev);
+               if (ret)
+                       break;
+               stack = prev;
+       }
+}
+
+const struct ao_scheme_type ao_scheme_stack_type = {
+       .size = stack_size,
+       .mark = stack_mark,
+       .move = stack_move,
+       .name = "stack"
+};
+
+struct ao_scheme_stack         *ao_scheme_stack_free_list;
+
+void
+ao_scheme_stack_reset(struct ao_scheme_stack *stack)
+{
+       stack->state = eval_sexpr;
+       stack->sexprs = AO_SCHEME_NIL;
+       stack->values = AO_SCHEME_NIL;
+       stack->values_tail = AO_SCHEME_NIL;
+}
+
+static struct ao_scheme_stack *
+ao_scheme_stack_new(void)
+{
+       struct ao_scheme_stack *stack;
+
+       if (ao_scheme_stack_free_list) {
+               stack = ao_scheme_stack_free_list;
+               ao_scheme_stack_free_list = ao_scheme_poly_stack(stack->prev);
+       } else {
+               stack = ao_scheme_alloc(sizeof (struct ao_scheme_stack));
+               if (!stack)
+                       return 0;
+               stack->type = AO_SCHEME_STACK;
+       }
+       ao_scheme_stack_reset(stack);
+       return stack;
+}
+
+int
+ao_scheme_stack_push(void)
+{
+       struct ao_scheme_stack  *stack;
+
+       stack = ao_scheme_stack_new();
+
+       if (!stack)
+               return 0;
+
+       stack->prev = ao_scheme_stack_poly(ao_scheme_stack);
+       stack->frame = ao_scheme_frame_poly(ao_scheme_frame_current);
+       stack->list = AO_SCHEME_NIL;
+
+       ao_scheme_stack = stack;
+
+       DBGI("stack push\n");
+       DBG_FRAMES();
+       DBG_IN();
+       return 1;
+}
+
+void
+ao_scheme_stack_pop(void)
+{
+       ao_poly                 prev;
+       struct ao_scheme_frame  *prev_frame;
+
+       if (!ao_scheme_stack)
+               return;
+       prev = ao_scheme_stack->prev;
+       if (!ao_scheme_stack_marked(ao_scheme_stack)) {
+               ao_scheme_stack->prev = ao_scheme_stack_poly(ao_scheme_stack_free_list);
+               ao_scheme_stack_free_list = ao_scheme_stack;
+       }
+
+       ao_scheme_stack = ao_scheme_poly_stack(prev);
+       prev_frame = ao_scheme_frame_current;
+       if (ao_scheme_stack)
+               ao_scheme_frame_current = ao_scheme_poly_frame(ao_scheme_stack->frame);
+       else
+               ao_scheme_frame_current = NULL;
+       if (ao_scheme_frame_current != prev_frame)
+               ao_scheme_frame_free(prev_frame);
+       DBG_OUT();
+       DBGI("stack pop\n");
+       DBG_FRAMES();
+}
+
+void
+ao_scheme_stack_clear(void)
+{
+       ao_scheme_stack = NULL;
+       ao_scheme_frame_current = NULL;
+       ao_scheme_v = AO_SCHEME_NIL;
+}
+
+void
+ao_scheme_stack_write(ao_poly poly)
+{
+       struct ao_scheme_stack *s = ao_scheme_poly_stack(poly);
+
+       while (s) {
+               if (s->type & AO_SCHEME_STACK_PRINT) {
+                       printf("[recurse...]");
+                       return;
+               }
+               s->type |= AO_SCHEME_STACK_PRINT;
+               printf("\t[\n");
+               printf("\t\texpr:   "); ao_scheme_poly_write(s->list); printf("\n");
+               printf("\t\tstate:  %s\n", ao_scheme_state_names[s->state]);
+               ao_scheme_error_poly ("values: ", s->values, s->values_tail);
+               ao_scheme_error_poly ("sexprs: ", s->sexprs, AO_SCHEME_NIL);
+               ao_scheme_error_frame(2, "frame:  ", ao_scheme_poly_frame(s->frame));
+               printf("\t]\n");
+               s->type &= ~AO_SCHEME_STACK_PRINT;
+               s = ao_scheme_poly_stack(s->prev);
+       }
+}
+
+/*
+ * Copy a stack, being careful to keep everybody referenced
+ */
+static struct ao_scheme_stack *
+ao_scheme_stack_copy(struct ao_scheme_stack *old)
+{
+       struct ao_scheme_stack *new = NULL;
+       struct ao_scheme_stack *n, *prev = NULL;
+
+       while (old) {
+               ao_scheme_stack_stash(0, old);
+               ao_scheme_stack_stash(1, new);
+               ao_scheme_stack_stash(2, prev);
+               n = ao_scheme_stack_new();
+               prev = ao_scheme_stack_fetch(2);
+               new = ao_scheme_stack_fetch(1);
+               old = ao_scheme_stack_fetch(0);
+               if (!n)
+                       return NULL;
+
+               ao_scheme_stack_mark(old);
+               ao_scheme_frame_mark(ao_scheme_poly_frame(old->frame));
+               *n = *old;
+
+               if (prev)
+                       prev->prev = ao_scheme_stack_poly(n);
+               else
+                       new = n;
+               prev = n;
+
+               old = ao_scheme_poly_stack(old->prev);
+       }
+       return new;
+}
+
+/*
+ * Evaluate a continuation invocation
+ */
+ao_poly
+ao_scheme_stack_eval(void)
+{
+       struct ao_scheme_stack  *new = ao_scheme_stack_copy(ao_scheme_poly_stack(ao_scheme_v));
+       if (!new)
+               return AO_SCHEME_NIL;
+
+       struct ao_scheme_cons   *cons = ao_scheme_poly_cons(ao_scheme_stack->values);
+
+       if (!cons || !cons->cdr)
+               return ao_scheme_error(AO_SCHEME_INVALID, "continuation requires a value");
+
+       new->state = eval_val;
+
+       ao_scheme_stack = new;
+       ao_scheme_frame_current = ao_scheme_poly_frame(ao_scheme_stack->frame);
+
+       return ao_scheme_poly_cons(cons->cdr)->car;
+}
+
+/*
+ * Call with current continuation. This calls a lambda, passing
+ * it a single argument which is the current continuation
+ */
+ao_poly
+ao_scheme_do_call_cc(struct ao_scheme_cons *cons)
+{
+       struct ao_scheme_stack  *new;
+       ao_poly                 v;
+
+       /* Make sure the single parameter is a lambda */
+       if (!ao_scheme_check_argc(_ao_scheme_atom_call2fcc, cons, 1, 1))
+               return AO_SCHEME_NIL;
+       if (!ao_scheme_check_argt(_ao_scheme_atom_call2fcc, cons, 0, AO_SCHEME_LAMBDA, 0))
+               return AO_SCHEME_NIL;
+
+       /* go get the lambda */
+       ao_scheme_v = ao_scheme_arg(cons, 0);
+
+       /* Note that the whole call chain now has
+        * a reference to it which may escape
+        */
+       new = ao_scheme_stack_copy(ao_scheme_stack);
+       if (!new)
+               return AO_SCHEME_NIL;
+
+       /* re-fetch cons after the allocation */
+       cons = ao_scheme_poly_cons(ao_scheme_poly_cons(ao_scheme_stack->values)->cdr);
+
+       /* Reset the arg list to the current stack,
+        * and call the lambda
+        */
+
+       cons->car = ao_scheme_stack_poly(new);
+       cons->cdr = AO_SCHEME_NIL;
+       v = ao_scheme_lambda_eval();
+       ao_scheme_stack->sexprs = v;
+       ao_scheme_stack->state = eval_begin;
+       return AO_SCHEME_NIL;
+}
diff --git a/src/scheme/ao_scheme_string.c b/src/scheme/ao_scheme_string.c
new file mode 100644 (file)
index 0000000..e25306c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao_scheme.h"
+
+static void string_mark(void *addr)
+{
+       (void) addr;
+}
+
+static int string_size(void *addr)
+{
+       if (!addr)
+               return 0;
+       return strlen(addr) + 1;
+}
+
+static void string_move(void *addr)
+{
+       (void) addr;
+}
+
+const struct ao_scheme_type ao_scheme_string_type = {
+       .mark = string_mark,
+       .size = string_size,
+       .move = string_move,
+       .name = "string",
+};
+
+char *
+ao_scheme_string_copy(char *a)
+{
+       int     alen = strlen(a);
+
+       ao_scheme_string_stash(0, a);
+       char    *r = ao_scheme_alloc(alen + 1);
+       a = ao_scheme_string_fetch(0);
+       if (!r)
+               return NULL;
+       strcpy(r, a);
+       return r;
+}
+
+char *
+ao_scheme_string_cat(char *a, char *b)
+{
+       int     alen = strlen(a);
+       int     blen = strlen(b);
+
+       ao_scheme_string_stash(0, a);
+       ao_scheme_string_stash(1, b);
+       char    *r = ao_scheme_alloc(alen + blen + 1);
+       a = ao_scheme_string_fetch(0);
+       b = ao_scheme_string_fetch(1);
+       if (!r)
+               return NULL;
+       strcpy(r, a);
+       strcpy(r+alen, b);
+       return r;
+}
+
+ao_poly
+ao_scheme_string_pack(struct ao_scheme_cons *cons)
+{
+       int     len = ao_scheme_cons_length(cons);
+       ao_scheme_cons_stash(0, cons);
+       char    *r = ao_scheme_alloc(len + 1);
+       cons = ao_scheme_cons_fetch(0);
+       char    *s = r;
+
+       while (cons) {
+               if (!ao_scheme_integer_typep(ao_scheme_poly_type(cons->car)))
+                       return ao_scheme_error(AO_SCHEME_INVALID, "non-int passed to pack");
+               *s++ = ao_scheme_poly_integer(cons->car);
+               cons = ao_scheme_poly_cons(cons->cdr);
+       }
+       *s++ = 0;
+       return ao_scheme_string_poly(r);
+}
+
+ao_poly
+ao_scheme_string_unpack(char *a)
+{
+       struct ao_scheme_cons   *cons = NULL, *tail = NULL;
+       int                     c;
+       int                     i;
+
+       for (i = 0; (c = a[i]); i++) {
+               ao_scheme_cons_stash(0, cons);
+               ao_scheme_cons_stash(1, tail);
+               ao_scheme_string_stash(0, a);
+               struct ao_scheme_cons   *n = ao_scheme_cons_cons(ao_scheme_int_poly(c), AO_SCHEME_NIL);
+               a = ao_scheme_string_fetch(0);
+               cons = ao_scheme_cons_fetch(0);
+               tail = ao_scheme_cons_fetch(1);
+
+               if (!n) {
+                       cons = NULL;
+                       break;
+               }
+               if (tail)
+                       tail->cdr = ao_scheme_cons_poly(n);
+               else
+                       cons = n;
+               tail = n;
+       }
+       return ao_scheme_cons_poly(cons);
+}
+
+void
+ao_scheme_string_write(ao_poly p)
+{
+       char    *s = ao_scheme_poly_string(p);
+       char    c;
+
+       putchar('"');
+       while ((c = *s++)) {
+               switch (c) {
+               case '\n':
+                       printf ("\\n");
+                       break;
+               case '\r':
+                       printf ("\\r");
+                       break;
+               case '\t':
+                       printf ("\\t");
+                       break;
+               default:
+                       if (c < ' ')
+                               printf("\\%03o", c);
+                       else
+                               putchar(c);
+                       break;
+               }
+       }
+       putchar('"');
+}
+
+void
+ao_scheme_string_display(ao_poly p)
+{
+       char    *s = ao_scheme_poly_string(p);
+       char    c;
+
+       while ((c = *s++))
+               putchar(c);
+}
diff --git a/src/scheme/make-const/.gitignore b/src/scheme/make-const/.gitignore
new file mode 100644 (file)
index 0000000..bcd5724
--- /dev/null
@@ -0,0 +1 @@
+ao_scheme_make_const
diff --git a/src/scheme/make-const/Makefile b/src/scheme/make-const/Makefile
new file mode 100644 (file)
index 0000000..caf7acb
--- /dev/null
@@ -0,0 +1,26 @@
+include ../Makefile-inc
+
+vpath %.o .
+vpath %.c ..
+vpath %.h ..
+
+SRCS=$(SCHEME_SRCS) ao_scheme_make_const.c
+HDRS=$(SCHEME_HDRS) ao_scheme_os.h
+
+OBJS=$(SRCS:.c=.o)
+
+CC=cc
+CFLAGS=-DAO_SCHEME_MAKE_CONST -O0 -g -I. -Wall -Wextra
+
+.c.o:
+       $(CC) -c $(CFLAGS) $< -o $@
+
+all: ao_scheme_make_const
+
+ao_scheme_make_const: $(OBJS)
+       $(CC) $(CFLAGS) -o $@ $^ -lm
+
+clean:
+       rm -f $(OBJS) ao_scheme_make_const
+
+$(OBJS): $(SCHEME_HDRS)
diff --git a/src/scheme/make-const/ao_scheme_os.h b/src/scheme/make-const/ao_scheme_os.h
new file mode 100644 (file)
index 0000000..f06bbbb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_SCHEME_OS_H_
+#define _AO_SCHEME_OS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+extern int ao_scheme_getc(void);
+
+static inline void
+ao_scheme_os_flush(void) {
+       fflush(stdout);
+}
+
+static inline void
+ao_scheme_abort(void)
+{
+       abort();
+}
+
+static inline void
+ao_scheme_os_led(int led)
+{
+       printf("leds set to 0x%x\n", led);
+}
+
+#define AO_SCHEME_JIFFIES_PER_SECOND   100
+
+static inline void
+ao_scheme_os_delay(int jiffies)
+{
+       struct timespec ts = {
+               .tv_sec = jiffies / AO_SCHEME_JIFFIES_PER_SECOND,
+               .tv_nsec = (jiffies % AO_SCHEME_JIFFIES_PER_SECOND) * (1000000000L / AO_SCHEME_JIFFIES_PER_SECOND)
+       };
+       nanosleep(&ts, NULL);
+}
+
+static inline int
+ao_scheme_os_jiffy(void)
+{
+       struct timespec tp;
+       clock_gettime(CLOCK_MONOTONIC, &tp);
+       return tp.tv_sec * AO_SCHEME_JIFFIES_PER_SECOND + (tp.tv_nsec / (1000000000L / AO_SCHEME_JIFFIES_PER_SECOND));
+}
+#endif
diff --git a/src/scheme/test/.gitignore b/src/scheme/test/.gitignore
new file mode 100644 (file)
index 0000000..3cdae59
--- /dev/null
@@ -0,0 +1 @@
+ao_scheme_test
diff --git a/src/scheme/test/Makefile b/src/scheme/test/Makefile
new file mode 100644 (file)
index 0000000..c48add1
--- /dev/null
@@ -0,0 +1,22 @@
+include ../Makefile-inc
+
+vpath %.o .
+vpath %.c ..
+vpath %.h ..
+
+SRCS=$(SCHEME_SRCS) ao_scheme_test.c
+
+OBJS=$(SRCS:.c=.o)
+
+CFLAGS=-O2 -g -Wall -Wextra -I. -I..
+
+ao_scheme_test: $(OBJS)
+       cc $(CFLAGS) -o $@ $(OBJS) -lm
+
+$(OBJS): $(SCHEME_HDRS)
+
+clean::
+       rm -f $(OBJS) ao_scheme_test
+
+install: ao_scheme_test
+       cp ao_scheme_test $$HOME/bin/ao-scheme
diff --git a/src/scheme/test/ao_scheme_os.h b/src/scheme/test/ao_scheme_os.h
new file mode 100644 (file)
index 0000000..ea363fb
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_SCHEME_OS_H_
+#define _AO_SCHEME_OS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define AO_SCHEME_POOL_TOTAL   32768
+#define AO_SCHEME_SAVE         1
+#define DBG_MEM_STATS          1
+
+extern int ao_scheme_getc(void);
+
+static inline void
+ao_scheme_os_flush() {
+       fflush(stdout);
+}
+
+static inline void
+ao_scheme_abort(void)
+{
+       abort();
+}
+
+static inline void
+ao_scheme_os_led(int led)
+{
+       printf("leds set to 0x%x\n", led);
+}
+
+#define AO_SCHEME_JIFFIES_PER_SECOND   100
+
+static inline void
+ao_scheme_os_delay(int jiffies)
+{
+       struct timespec ts = {
+               .tv_sec = jiffies / AO_SCHEME_JIFFIES_PER_SECOND,
+               .tv_nsec = (jiffies % AO_SCHEME_JIFFIES_PER_SECOND) * (1000000000L / AO_SCHEME_JIFFIES_PER_SECOND)
+       };
+       nanosleep(&ts, NULL);
+}
+
+static inline int
+ao_scheme_os_jiffy(void)
+{
+       struct timespec tp;
+       clock_gettime(CLOCK_MONOTONIC, &tp);
+       return tp.tv_sec * AO_SCHEME_JIFFIES_PER_SECOND + (tp.tv_nsec / (1000000000L / AO_SCHEME_JIFFIES_PER_SECOND));
+}
+
+#endif
diff --git a/src/scheme/test/ao_scheme_test.c b/src/scheme/test/ao_scheme_test.c
new file mode 100644 (file)
index 0000000..0c77d8d
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include "ao_scheme.h"
+#include <stdio.h>
+
+static FILE *ao_scheme_file;
+static int newline = 1;
+
+static char save_file[] = "scheme.image";
+
+int
+ao_scheme_os_save(void)
+{
+       FILE    *save = fopen(save_file, "w");
+
+       if (!save) {
+               perror(save_file);
+               return 0;
+       }
+       fwrite(ao_scheme_pool, 1, AO_SCHEME_POOL_TOTAL, save);
+       fclose(save);
+       return 1;
+}
+
+int
+ao_scheme_os_restore_save(struct ao_scheme_os_save *save, int offset)
+{
+       FILE    *restore = fopen(save_file, "r");
+       size_t  ret;
+
+       if (!restore) {
+               perror(save_file);
+               return 0;
+       }
+       fseek(restore, offset, SEEK_SET);
+       ret = fread(save, sizeof (struct ao_scheme_os_save), 1, restore);
+       fclose(restore);
+       if (ret != 1)
+               return 0;
+       return 1;
+}
+
+int
+ao_scheme_os_restore(void)
+{
+       FILE    *restore = fopen(save_file, "r");
+       size_t  ret;
+
+       if (!restore) {
+               perror(save_file);
+               return 0;
+       }
+       ret = fread(ao_scheme_pool, 1, AO_SCHEME_POOL_TOTAL, restore);
+       fclose(restore);
+       if (ret != AO_SCHEME_POOL_TOTAL)
+               return 0;
+       return 1;
+}
+
+int
+ao_scheme_getc(void)
+{
+       int c;
+
+       if (ao_scheme_file)
+               return getc(ao_scheme_file);
+
+       if (newline) {
+               if (ao_scheme_read_list)
+                       printf("+ ");
+               else
+                       printf("> ");
+               newline = 0;
+       }
+       c = getchar();
+       if (c == '\n')
+               newline = 1;
+       return c;
+}
+
+int
+main (int argc, char **argv)
+{
+       (void) argc;
+
+       while (*++argv) {
+               ao_scheme_file = fopen(*argv, "r");
+               if (!ao_scheme_file) {
+                       perror(*argv);
+                       exit(1);
+               }
+               ao_scheme_read_eval_print();
+               fclose(ao_scheme_file);
+               ao_scheme_file = NULL;
+       }
+       ao_scheme_read_eval_print();
+
+       printf ("collects: full: %lu incremental %lu\n",
+               ao_scheme_collects[AO_SCHEME_COLLECT_FULL],
+               ao_scheme_collects[AO_SCHEME_COLLECT_INCREMENTAL]);
+
+       printf ("freed: full %lu incremental %lu\n",
+               ao_scheme_freed[AO_SCHEME_COLLECT_FULL],
+               ao_scheme_freed[AO_SCHEME_COLLECT_INCREMENTAL]);
+
+       printf("loops: full %lu incremental %lu\n",
+               ao_scheme_loops[AO_SCHEME_COLLECT_FULL],
+               ao_scheme_loops[AO_SCHEME_COLLECT_INCREMENTAL]);
+
+       printf("loops per collect: full %f incremental %f\n",
+              (double) ao_scheme_loops[AO_SCHEME_COLLECT_FULL] /
+              (double) ao_scheme_collects[AO_SCHEME_COLLECT_FULL],
+              (double) ao_scheme_loops[AO_SCHEME_COLLECT_INCREMENTAL] /
+              (double) ao_scheme_collects[AO_SCHEME_COLLECT_INCREMENTAL]);
+
+       printf("freed per collect: full %f incremental %f\n",
+              (double) ao_scheme_freed[AO_SCHEME_COLLECT_FULL] /
+              (double) ao_scheme_collects[AO_SCHEME_COLLECT_FULL],
+              (double) ao_scheme_freed[AO_SCHEME_COLLECT_INCREMENTAL] /
+              (double) ao_scheme_collects[AO_SCHEME_COLLECT_INCREMENTAL]);
+
+       printf("freed per loop: full %f incremental %f\n",
+              (double) ao_scheme_freed[AO_SCHEME_COLLECT_FULL] /
+              (double) ao_scheme_loops[AO_SCHEME_COLLECT_FULL],
+              (double) ao_scheme_freed[AO_SCHEME_COLLECT_INCREMENTAL] /
+              (double) ao_scheme_loops[AO_SCHEME_COLLECT_INCREMENTAL]);
+}
diff --git a/src/scheme/test/hanoi.scheme b/src/scheme/test/hanoi.scheme
new file mode 100644 (file)
index 0000000..c4ae737
--- /dev/null
@@ -0,0 +1,174 @@
+;
+; Towers of Hanoi
+;
+; 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.
+;
+
+                                       ; ANSI control sequences
+
+(define (move-to col row)
+  (for-each display (list "\033[" row ";" col "H"))
+  )
+
+(define (clear)
+  (display "\033[2J")
+  )
+
+(define (display-string x y str)
+  (move-to x y)
+  (display str)
+  )
+
+(define (make-piece num max)
+                                       ; A piece for position 'num'
+                                       ; is num + 1 + num stars
+                                       ; centered in a field of max *
+                                       ; 2 + 1 characters with spaces
+                                       ; on either side. This way,
+                                       ; every piece is the same
+                                       ; number of characters
+
+  (define (chars n c)
+    (if (zero? n) ""
+      (+ c (chars (- n 1) c))
+      )
+    )
+  (+ (chars (- max num 1) " ")
+     (chars (+ (* num 2) 1) "*")
+     (chars (- max num 1) " ")
+     )
+  )
+
+(define (make-pieces max)
+                                       ; Make a list of numbers from 0 to max-1
+  (define (nums cur max)
+    (if (= cur max) ()
+      (cons cur (nums (+ cur 1) max))
+      )
+    )
+                                       ; Create a list of pieces
+
+  (map (lambda (x) (make-piece x max)) (nums 0 max))
+  )
+
+                                       ; Here's all of the towers of pieces
+                                       ; This is generated when the program is run
+
+(define towers ())
+
+                                       ; position of the bottom of
+                                       ; the stacks set at runtime
+(define bottom-y 0)
+(define left-x 0)
+
+(define move-delay 25)
+
+                                       ; Display one tower, clearing any
+                                       ; space above it
+
+(define (display-tower x y clear tower)
+  (cond ((= 0 clear)
+        (cond ((not (null? tower))
+               (display-string x y (car tower))
+               (display-tower x (+ y 1) 0 (cdr tower))
+               )
+              )
+        )
+       (else 
+        (display-string x y "                    ")
+        (display-tower x (+ y 1) (- clear 1) tower)
+        )
+       )
+  )
+
+                                       ; Position of the top of the tower on the screen
+                                       ; Shorter towers start further down the screen
+
+(define (tower-pos tower)
+  (- bottom-y (length tower))
+  )
+
+                                       ; Display all of the towers, spaced 20 columns apart
+
+(define (display-towers x towers)
+  (cond ((not (null? towers))
+        (display-tower x 0 (tower-pos (car towers)) (car towers))
+        (display-towers (+ x 20) (cdr towers)))
+       )
+  )
+
+                                       ; Display all of the towers, then move the cursor
+                                       ; out of the way and flush the output
+
+(define (display-hanoi)
+  (display-towers left-x towers)
+  (move-to 1 23)
+  (flush-output)
+  (delay move-delay)
+  )
+
+                                       ; Reset towers to the starting state, with
+                                       ; all of the pieces in the first tower and the
+                                       ; other two empty
+
+(define (reset-towers len)
+  (set! towers (list (make-pieces len) () ()))
+  (set! bottom-y (+ len 3))
+  )
+
+                                       ; Move a piece from the top of one tower
+                                       ; to the top of another
+
+(define (move-piece from to)
+
+                                       ; references to the cons holding the two towers
+
+  (define from-tower (list-tail towers from))
+  (define to-tower (list-tail towers to))
+
+                                       ; stick the car of from-tower onto to-tower
+
+  (set-car! to-tower (cons (caar from-tower) (car to-tower)))
+
+                                       ; remove the car of from-tower
+
+  (set-car! from-tower (cdar from-tower))
+  )
+
+                                       ; The implementation of the game
+
+(define (_hanoi n from to use)
+  (cond ((= 1 n)
+        (move-piece from to)
+        (display-hanoi)
+        )
+       (else
+        (_hanoi (- n 1) from use to)
+        (_hanoi 1 from to use)
+        (_hanoi (- n 1) use to from)
+        )
+       )
+  )
+
+                                       ; A pretty interface which
+                                       ; resets the state of the game,
+                                       ; clears the screen and runs
+                                       ; the program
+
+(define (hanoi len)
+  (reset-towers len)
+  (clear)
+  (display-hanoi)
+  (_hanoi len 0 1 2)
+  #t
+  )
diff --git a/src/stm-scheme-newlib/.gitignore b/src/stm-scheme-newlib/.gitignore
new file mode 100644 (file)
index 0000000..60d664f
--- /dev/null
@@ -0,0 +1,4 @@
+*.elf
+*.map
+*.syms
+ao_product.h
diff --git a/src/stm-scheme-newlib/Makefile b/src/stm-scheme-newlib/Makefile
new file mode 100644 (file)
index 0000000..a4c249a
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+include ../scheme/Makefile-inc
+
+NEWLIB_FULL=-lm -lc -lgcc
+
+LIBS=$(NEWLIB_FULL)
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_task.h \
+       $(SCHEME_HDRS)
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+       ao_interrupt.c \
+       ao_boot_chain.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_task.c \
+       ao_led.c \
+       ao_stdio_newlib.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_dma_stm.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       $(SCHEME_SRCS)
+
+PRODUCT=StmScheme-v0.0
+PRODUCT_DEF=-DSTM_SCHEME
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os
+
+PROG=stm-scheme-$(VERSION)
+ELF=$(PROG).elf
+IHX=$(PROG).ihx
+LIBSYMS=$(PROG).syms
+MAP=$(PROG).map
+
+NEWLIB=/local/newlib-mini
+MAPFILE=-Wl,-M=$(MAP)
+LDFLAGS=-L../stm -L$(NEWLIB)/arm-none-eabi/lib/thumb/v7-m/ -Wl,-Taltos.ld $(MAPFILE) -nostartfiles
+AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I.. -I../scheme -isystem $(NEWLIB)/arm-none-eabi/include -DNEWLIB
+
+SRC=$(ALTOS_SRC) ao_demo.c
+OBJ=$(SRC:.c=.o)
+
+all: $(ELF) $(IHX) $(LIBSYMS)
+
+$(ELF): Makefile $(OBJ)
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(LIBS)
+
+$(LIBSYMS): $(ELF)
+       grep '^                         ' $(MAP) | grep -v 'size before relaxing' > $@
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+$(OBJ): $(INC)
+
+distclean:     clean
+
+clean:
+       rm -f *.o *.elf *.ihx *.map *.syms
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/stm-scheme-newlib/ao_demo.c b/src/stm-scheme-newlib/ao_demo.c
new file mode 100644 (file)
index 0000000..13a3128
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2011 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_exti.h>
+#include <ao_boot.h>
+#include <ao_scheme.h>
+
+static void scheme_cmd() {
+       ao_scheme_read_eval_print();
+}
+
+
+__code struct ao_cmds ao_demo_cmds[] = {
+       { scheme_cmd, "l\0Run scheme interpreter" },
+       { 0, NULL }
+};
+
+int
+main(void)
+{
+       ao_clock_init();
+
+       ao_task_init();
+
+       ao_led_init(LEDS_AVAILABLE);
+       ao_timer_init();
+       ao_dma_init();
+       ao_cmd_init();
+       ao_usb_init();
+
+       ao_cmd_register(&ao_demo_cmds[0]);
+
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/stm-scheme-newlib/ao_pins.h b/src/stm-scheme-newlib/ao_pins.h
new file mode 100644 (file)
index 0000000..524490f
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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_
+
+/* Bridge SB17 on the board and use the MCO from the other chip */
+#define AO_HSE         8000000
+#define AO_HSE_BYPASS          1
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL              12
+#define AO_RCC_CFGR_PLLMUL     (STM_RCC_CFGR_PLLMUL_12)
+
+/* SYSCLK = 32MHz */
+#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 HCLK/1 */
+#define AO_APB1_PRESCALER      1
+#define AO_RCC_CFGR_PPRE1_DIV  STM_RCC_CFGR_PPRE2_DIV_1
+
+/* Run APB2 at HCLK/1 */
+#define AO_APB2_PRESCALER              1
+#define AO_RCC_CFGR_PPRE2_DIV  STM_RCC_CFGR_PPRE2_DIV_1
+
+#define HAS_SERIAL_1           0
+#define USE_SERIAL_1_STDIN     0
+#define SERIAL_1_PB6_PB7       1
+#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       1
+
+#define HAS_SERIAL_3           0
+#define USE_SERIAL_3_STDIN     1
+#define SERIAL_3_PB10_PB11     0
+#define SERIAL_3_PC10_PC11     0
+#define SERIAL_3_PD8_PD9       1
+
+#define HAS_SPI_1              0
+#define SPI_1_PB3_PB4_PB5      1
+#define SPI_1_OSPEEDR          STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2              0
+
+#define HAS_USB                        1
+#define HAS_BEEP               0
+#define PACKET_HAS_SLAVE       0
+
+#define AO_BOOT_CHAIN          1
+
+#define LOW_LEVEL_DEBUG                0
+
+#define LED_PORT_ENABLE                STM_RCC_AHBENR_GPIOBEN
+#define LED_PORT               (&stm_gpiob)
+#define LED_PIN_GREEN          7
+#define LED_PIN_BLUE           6
+#define AO_LED_GREEN           (1 << LED_PIN_GREEN)
+#define AO_LED_BLUE            (1 << LED_PIN_BLUE)
+#define AO_LED_PANIC           AO_LED_BLUE
+
+#define LEDS_AVAILABLE         (AO_LED_BLUE | AO_LED_GREEN)
+
+#define HAS_ADC                        0
+
+#define AO_TICK_TYPE           uint32_t
+#define AO_TICK_SIGNED         int32_t
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/stm-scheme-newlib/ao_scheme_os.h b/src/stm-scheme-newlib/ao_scheme_os.h
new file mode 100644 (file)
index 0000000..21b6001
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_SCHEME_OS_H_
+#define _AO_SCHEME_OS_H_
+
+#include "ao.h"
+
+#define AO_SCHEME_POOL         10240
+
+#ifndef __BYTE_ORDER
+#define        __LITTLE_ENDIAN 1234
+#define        __BIG_ENDIAN    4321
+#define __BYTE_ORDER   __LITTLE_ENDIAN
+#endif
+
+static inline int
+ao_scheme_getc() {
+       static uint8_t  at_eol;
+       int c;
+
+       if (at_eol) {
+               ao_cmd_readline();
+               at_eol = 0;
+       }
+       c = ao_cmd_lex();
+       if (c == '\n')
+               at_eol = 1;
+       return c;
+}
+
+static inline void
+ao_scheme_os_flush(void)
+{
+       flush();
+}
+
+static inline void
+ao_scheme_abort(void)
+{
+       ao_panic(1);
+}
+
+static inline void
+ao_scheme_os_led(int led)
+{
+       ao_led_set(led);
+}
+
+#define AO_SCHEME_JIFFIES_PER_SECOND   AO_HERTZ
+
+static inline void
+ao_scheme_os_delay(int delay)
+{
+       ao_delay(delay);
+}
+
+static inline int
+ao_scheme_os_jiffy(void)
+{
+       return ao_tick_count;
+}
+
+#endif
diff --git a/src/stm-scheme-newlib/ao_scheme_os_save.c b/src/stm-scheme-newlib/ao_scheme_os_save.c
new file mode 100644 (file)
index 0000000..ce46f18
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include "ao_scheme.h"
+#include <ao_flash.h>
+
+extern uint8_t __flash__[];
+
+/* saved variables to rebuild the heap
+
+   ao_scheme_atoms
+   ao_scheme_frame_global
+ */
+
+int
+ao_scheme_os_save(void)
+{
+       int i;
+
+       for (i = 0; i < AO_SCHEME_POOL_TOTAL; i += 256) {
+               uint32_t        *dst = (uint32_t *) (void *) &__flash__[i];
+               uint32_t        *src = (uint32_t *) (void *) &ao_scheme_pool[i];
+
+               ao_flash_page(dst, src);
+       }
+       return 1;
+}
+
+int
+ao_scheme_os_restore_save(struct ao_scheme_os_save *save, int offset)
+{
+       memcpy(save, &__flash__[offset], sizeof (struct ao_scheme_os_save));
+       return 1;
+}
+
+int
+ao_scheme_os_restore(void)
+{
+       memcpy(ao_scheme_pool, __flash__, AO_SCHEME_POOL_TOTAL);
+       return 1;
+}
diff --git a/src/stm-scheme-newlib/flash-loader/Makefile b/src/stm-scheme-newlib/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..4c60f31
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=stm-scheme
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/stm-scheme-newlib/flash-loader/ao_pins.h b/src/stm-scheme-newlib/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..eb5fcb8
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_
+
+/* Bridge SB17 on the board and use the MCO from the other chip */
+#define AO_HSE         8000000
+#define AO_HSE_BYPASS          1
+
+#include <ao_flash_stm_pins.h>
+
+/* Use the 'user switch' to force boot loader on power on */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioa
+#define AO_BOOT_APPLICATION_PIN                0
+#define AO_BOOT_APPLICATION_VALUE      0
+#define AO_BOOT_APPLICATION_MODE       0
+
+#endif /* _AO_PINS_H_ */
index 66ed4be8d77974763e35b005adfecf340b8143f3..4d0d27c7af385f037b330b90c22868a1f322b82d 100644 (file)
@@ -1,4 +1,4 @@
-vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:../draw:../lisp:..
+vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:../draw:../scheme:..
 vpath make-altitude ../util
 vpath make-kalman ../util
 vpath kalman.5c ../kalman
index 77f121dcae435289faa3a71cba15627143d905b0..24912bb28b34849d7b2297ff8c11e6e6cd63a4fb 100644 (file)
@@ -57,6 +57,9 @@ static void ao_adc_done(int index)
 #endif
 #if HAS_MPU6000
                ao_data_ring[ao_data_head].mpu6000 = ao_mpu6000_current;
+#endif
+#if HAS_MPU9250
+               ao_data_ring[ao_data_head].mpu9250 = ao_mpu9250_current;
 #endif
                ao_data_ring[ao_data_head].tick = ao_tick_count;
                ao_data_head = ao_data_ring_next(ao_data_head);
@@ -377,7 +380,7 @@ ao_adc_init(void)
 #if AO_NUM_ADC > 18
 #error "need to finish stm_adc.sqr settings"
 #endif
-       
+
        /* Turn ADC on */
        stm_adc.cr2 = AO_ADC_CR2_VAL;
 
index 4f3e6132c44cca322e8d892249127654ec8d6e83..8aa2bdca9ad73cca16a2559ee1becd2f5c51075a 100644 (file)
@@ -21,6 +21,7 @@
 
 #define AO_EXTI_MODE_RISING    1
 #define AO_EXTI_MODE_FALLING   2
+#define AO_EXTI_MODE_PULL_NONE 0
 #define AO_EXTI_MODE_PULL_UP   4
 #define AO_EXTI_MODE_PULL_DOWN 8
 #define AO_EXTI_PRIORITY_LOW   16
index ef56231334e28894a980f08042a1e72c8530a40f..2afee5b5da3bd9cc2b9b957e3056cdd1cbc2f9b7 100644 (file)
@@ -60,13 +60,13 @@ _ao_usart_cts(struct ao_stm_usart *usart)
 #endif
 
 static void
-_ao_usart_rx(struct ao_stm_usart *usart, int stdin)
+_ao_usart_rx(struct ao_stm_usart *usart, int is_stdin)
 {
        if (usart->reg->sr & (1 << STM_USART_SR_RXNE)) {
                if (!ao_fifo_full(usart->rx_fifo)) {
                        ao_fifo_insert(usart->rx_fifo, usart->reg->dr);
                        ao_wakeup(&usart->rx_fifo);
-                       if (stdin)
+                       if (is_stdin)
                                ao_wakeup(&ao_stdin_ready);
 #if HAS_SERIAL_SW_FLOW
                        /* If the fifo is nearly full, turn off RTS and wait
@@ -84,9 +84,9 @@ _ao_usart_rx(struct ao_stm_usart *usart, int stdin)
 }
 
 static void
-ao_usart_isr(struct ao_stm_usart *usart, int stdin)
+ao_usart_isr(struct ao_stm_usart *usart, int is_stdin)
 {
-       _ao_usart_rx(usart, stdin);
+       _ao_usart_rx(usart, is_stdin);
 
        if (!_ao_usart_tx_start(usart))
                usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE);
index f2c53499347be2dcb0b1ca53432dd80cd2a09924..fa6e6e860ebc68a0d6fbd3db4ea91918678d2ab2 100644 (file)
@@ -4,7 +4,7 @@ endif
 
 include $(TOPDIR)/Makedefs
 
-vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp
+vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/scheme
 vpath make-altitude $(TOPDIR)/util
 vpath make-kalman $(TOPDIR)/util
 vpath kalman.5c $(TOPDIR)/kalman
index 746bb3ee72c55085ab30c76ef76e5bfb1db0741d..d98e85d782521039d4b3576c40d48ac51d7f1d66 100644 (file)
@@ -64,6 +64,7 @@
 #define AO_CONFIG_MAX_SIZE                     1024
 #define LOG_ERASE_MARK                         0x55
 #define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMETRUM
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
index 28ae30a47da0d0501e2ddc787272da3dcf3d8d54..873474bbab3ac074a8aefd4389c2a1139c54cbfc 100644 (file)
@@ -75,6 +75,7 @@
 #define AO_CONFIG_DEFAULT_APRS_INTERVAL                0
 #define AO_CONFIG_DEFAULT_RADIO_POWER          0xc0
 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       496 * 1024
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEGPS
 
 /*
  * GPS
index 9672ab037dbd8005b2c2efe2c9c78e2f8080f684..f3bdc0ac73f135360baaa9a5ae047dfded1b2f11 100644 (file)
@@ -77,6 +77,7 @@
 
 #define AO_CONFIG_DEFAULT_APRS_INTERVAL                0
 #define AO_CONFIG_DEFAULT_RADIO_POWER          0xc0
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEGPS
 
 /*
  * GPS
index fa175371b28f8835f462b9cb04ac17abf9bb3e07..a2e812fa51f5570762b07d0e1c8b16004ea0c9b1 100644 (file)
@@ -136,6 +136,7 @@ struct ao_adc {
 
 #define AO_CONFIG_DEFAULT_APRS_INTERVAL                0
 #define AO_CONFIG_DEFAULT_RADIO_POWER          0xc0
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEGPS
 
 /*
  * GPS
index 11c4267c9b2eb680bbd882b703dab1d5d097e61b..94e77f9864bce76cbd64887d0593a6e1bba907da 100644 (file)
@@ -69,6 +69,7 @@
 #define AO_CONFIG_MAX_SIZE                     1024
 #define LOG_ERASE_MARK                         0x55
 #define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMEGA
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
index 4decbbf7f64cfd13ef6b0916554a65475bc7b164..d44394f0aad381a684046ece8280b2de745321b4 100644 (file)
@@ -69,6 +69,7 @@
 #define AO_CONFIG_MAX_SIZE                     1024
 #define LOG_ERASE_MARK                         0x55
 #define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMEGA
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
index c7c8ad1931610aa11a265cd16536f4ed95e65b03..42c00c947924b53e354c29ee4331e4ead015c1ea 100644 (file)
@@ -69,6 +69,7 @@
 #define AO_CONFIG_MAX_SIZE                     1024
 #define LOG_ERASE_MARK                         0x55
 #define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMEGA
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
diff --git a/src/telemega-v3.0/.gitignore b/src/telemega-v3.0/.gitignore
new file mode 100644 (file)
index 0000000..e67759a
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+telemega-*.elf
diff --git a/src/telemega-v3.0/Makefile b/src/telemega-v3.0/Makefile
new file mode 100644 (file)
index 0000000..ae22bf0
--- /dev/null
@@ -0,0 +1,153 @@
+#
+# 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_ms5607.h \
+       ao_mpu9250.h \
+       ao_mma655x.h \
+       ao_cc1200_CC1200.h \
+       ao_profile.h \
+       ao_task.h \
+       ao_whiten.h \
+       ao_sample_profile.h \
+       ao_quaternion.h \
+       math.h \
+       ao_mpu.h \
+       stm32l.h \
+       math.h \
+       ao_ms5607_convert.c \
+       Makefile
+
+#
+# Common AltOS sources
+#
+
+#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
+
+MATH_SRC=\
+       ef_acos.c \
+       ef_sqrt.c \
+       ef_rem_pio2.c \
+       kf_cos.c \
+       kf_sin.c \
+       kf_rem_pio2.c \
+       sf_copysign.c \
+       sf_cos.c \
+       sf_fabs.c \
+       sf_floor.c \
+       sf_scalbn.c \
+       sf_sin.c \
+       ef_log.c
+
+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_led.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_serial_stm.c \
+       ao_gps_ublox.c \
+       ao_gps_show.c \
+       ao_gps_report_mega.c \
+       ao_ignite.c \
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c \
+       ao_cc1200.c \
+       ao_data.c \
+       ao_ms5607.c \
+       ao_mma655x.c \
+       ao_adc_stm.c \
+       ao_beep_stm.c \
+       ao_eeprom_stm.c \
+       ao_storage.c \
+       ao_m25.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       ao_report.c \
+       ao_i2c_stm.c \
+       ao_mpu9250.c \
+       ao_convert_pa.c \
+       ao_convert_volt.c \
+       ao_log.c \
+       ao_log_mega.c \
+       ao_sample.c \
+       ao_kalman.c \
+       ao_flight.c \
+       ao_telemetry.c \
+       ao_packet_slave.c \
+       ao_packet.c \
+       ao_companion.c \
+       ao_pyro.c \
+       ao_aprs.c \
+       ao_pwm_stm.c \
+       $(MATH_SRC) \
+       $(PROFILE) \
+       $(SAMPLE_PROFILE) \
+       $(STACK_GUARD)
+
+PRODUCT=TeleMega-v3.0
+PRODUCT_DEF=-DTELEMEGA
+IDPRODUCT=0x0023
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+PROGNAME=telemega-v3.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telemega.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+../altitude-pa.h: make-altitude-pa
+       nickle $< > $@
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/telemega-v3.0/ao_pins.h b/src/telemega-v3.0/ao_pins.h
new file mode 100644 (file)
index 0000000..7327860
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Copyright © 2017 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
+
+/* 8MHz High speed external crystal */
+#define AO_HSE                 8000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL              12
+#define AO_RCC_CFGR_PLLMUL     (STM_RCC_CFGR_PLLMUL_12)
+
+/* 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      1
+
+#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           1
+#define USE_SERIAL_3_STDIN     0
+#define SERIAL_3_PB10_PB11     0
+#define SERIAL_3_PC10_PC11     1
+#define SERIAL_3_PD8_PD9       0
+
+#define ao_gps_getchar         ao_serial3_getchar
+#define ao_gps_putchar         ao_serial3_putchar
+#define ao_gps_set_speed       ao_serial3_set_speed
+#define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       (1024 * 1024)
+#define AO_CONFIG_MAX_SIZE                     1024
+#define LOG_ERASE_MARK                         0x55
+#define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMEGA_3
+
+#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 HAS_RADIO              1
+#define HAS_TELEMETRY          1
+#define HAS_APRS               1
+#define HAS_COMPANION          1
+
+#define HAS_SPI_1              1
+#define SPI_1_PA5_PA6_PA7      1       /* Barometer */
+#define SPI_1_PB3_PB4_PB5      0
+#define SPI_1_PE13_PE14_PE15   1       /* Accelerometer, Gyro */
+#define SPI_1_OSPEEDR          STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2              1
+#define SPI_2_PB13_PB14_PB15   1       /* Flash, Companion */
+#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              1
+#define I2C_1_PB8_PB9          1
+
+#define HAS_I2C_2              0
+#define I2C_2_PB10_PB11                0
+
+#define PACKET_HAS_SLAVE       1
+#define PACKET_HAS_MASTER      0
+
+#define LOW_LEVEL_DEBUG                0
+
+#define LED_PORT_ENABLE                STM_RCC_AHBENR_GPIOCEN
+#define LED_PORT               (&stm_gpioc)
+#define LED_PIN_RED            8
+#define LED_PIN_GREEN          9
+#define AO_LED_RED             (1 << LED_PIN_RED)
+#define AO_LED_GREEN           (1 << LED_PIN_GREEN)
+
+#define LEDS_AVAILABLE         (AO_LED_RED | AO_LED_GREEN)
+
+#define HAS_GPS                        1
+#define HAS_FLIGHT             1
+#define HAS_ADC                        1
+#define HAS_ADC_TEMP           1
+#define HAS_LOG                        1
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE             1
+#define HAS_IGNITE_REPORT      1
+
+#define AO_SENSE_PYRO(p,n)     ((p)->adc.sense[n])
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense[4])
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense[5])
+#define AO_IGNITER_CLOSED      400
+#define AO_IGNITER_OPEN                60
+
+/* Pyro A */
+#define AO_PYRO_PORT_0 (&stm_gpiod)
+#define AO_PYRO_PIN_0  6
+
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpiod)
+#define AO_PYRO_PIN_1  7
+
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpiob)
+#define AO_PYRO_PIN_2  5
+
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpioe)
+#define AO_PYRO_PIN_3  4
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioe)
+#define AO_IGNITER_DROGUE_PIN  6
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT   (&stm_gpioe)
+#define AO_IGNITER_MAIN_PIN    5
+
+/* Number of general purpose pyro channels available */
+#define AO_PYRO_NUM    4
+
+#define AO_IGNITER_SET_DROGUE(v)       stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v)
+#define AO_IGNITER_SET_MAIN(v)         stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v)
+
+/*
+ * ADC
+ */
+#define AO_DATA_RING           32
+#define AO_ADC_NUM_SENSE       6
+
+struct ao_adc {
+       int16_t                 sense[AO_ADC_NUM_SENSE];
+       int16_t                 v_batt;
+       int16_t                 v_pbatt;
+       int16_t                 temp;
+};
+
+#define AO_ADC_DUMP(p) \
+       printf("tick: %5u A: %5d B: %5d C: %5d D: %5d drogue: %5d main: %5d batt: %5d pbatt: %5d temp: %5d\n", \
+              (p)->tick, \
+              (p)->adc.sense[0], (p)->adc.sense[1], (p)->adc.sense[2], \
+              (p)->adc.sense[3], (p)->adc.sense[4], (p)->adc.sense[5], \
+              (p)->adc.v_batt, (p)->adc.v_pbatt, (p)->adc.temp)
+
+#define AO_ADC_SENSE_A         0
+#define AO_ADC_SENSE_A_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_A_PIN     0
+
+#define AO_ADC_SENSE_B         1
+#define AO_ADC_SENSE_B_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_B_PIN     1
+
+#define AO_ADC_SENSE_C         2
+#define AO_ADC_SENSE_C_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_C_PIN     2
+
+#define AO_ADC_SENSE_D         3
+#define AO_ADC_SENSE_D_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_D_PIN     3
+
+#define AO_ADC_SENSE_DROGUE    4
+#define AO_ADC_SENSE_DROGUE_PORT       (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN        4
+
+#define AO_ADC_SENSE_MAIN      22
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_MAIN_PIN  7
+
+#define AO_ADC_V_BATT          8
+#define AO_ADC_V_BATT_PORT     (&stm_gpiob)
+#define AO_ADC_V_BATT_PIN      0
+
+#define AO_ADC_V_PBATT         9
+#define AO_ADC_V_PBATT_PORT    (&stm_gpiob)
+#define AO_ADC_V_PBATT_PIN     1
+
+#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 + 2)
+
+#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_SENSE_C_PORT
+#define AO_ADC_PIN2_PIN                AO_ADC_SENSE_C_PIN
+#define AO_ADC_PIN3_PORT       AO_ADC_SENSE_D_PORT
+#define AO_ADC_PIN3_PIN                AO_ADC_SENSE_D_PIN
+#define AO_ADC_PIN4_PORT       AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN4_PIN                AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN5_PORT       AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN5_PIN                AO_ADC_SENSE_MAIN_PIN
+#define AO_ADC_PIN6_PORT       AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN6_PIN                AO_ADC_V_BATT_PIN
+#define AO_ADC_PIN7_PORT       AO_ADC_V_PBATT_PORT
+#define AO_ADC_PIN7_PIN                AO_ADC_V_PBATT_PIN
+
+#define AO_NUM_ADC             (AO_ADC_NUM_SENSE + 3)
+
+#define AO_ADC_SQ1             AO_ADC_SENSE_A
+#define AO_ADC_SQ2             AO_ADC_SENSE_B
+#define AO_ADC_SQ3             AO_ADC_SENSE_C
+#define AO_ADC_SQ4             AO_ADC_SENSE_D
+#define AO_ADC_SQ5             AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ6             AO_ADC_SENSE_MAIN
+#define AO_ADC_SQ7             AO_ADC_V_BATT
+#define AO_ADC_SQ8             AO_ADC_V_PBATT
+#define AO_ADC_SQ9             AO_ADC_TEMP
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    56      /* 5.6k */
+#define AO_BATTERY_DIV_MINUS   100     /* 10k */
+
+/*
+ * 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
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT      (&stm_gpioc)
+#define AO_MS5607_CS_PIN       4
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS)
+#define AO_MS5607_MISO_PORT    (&stm_gpioa)
+#define AO_MS5607_MISO_PIN     6
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO)
+#define AO_MS5607_SPI_INDEX    AO_SPI_1_PA5_PA6_PA7
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS          1
+#define AO_M25_SPI_CS_PORT     (&stm_gpiod)
+#define AO_M25_SPI_CS_MASK     (1 << 3)
+#define AO_M25_SPI_BUS         AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio (cc1120)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT   5695733
+
+#define AO_FEC_DEBUG           0
+#define AO_CC1200_SPI_CS_PORT  (&stm_gpioc)
+#define AO_CC1200_SPI_CS_PIN   5
+#define AO_CC1200_SPI_BUS      AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1200_SPI          stm_spi2
+#define AO_CC1200_SPI_SPEED    AO_SPI_SPEED_FAST
+
+#define AO_CC1200_INT_PORT             (&stm_gpioe)
+#define AO_CC1200_INT_PIN              1
+#define AO_CC1200_MCU_WAKEUP_PORT      (&stm_gpioc)
+#define AO_CC1200_MCU_WAKEUP_PIN       (0)
+
+#define AO_CC1200_INT_GPIO     2
+#define AO_CC1200_INT_GPIO_IOCFG       CC1200_IOCFG2
+
+#define AO_CC1200_MARC_GPIO    3
+#define AO_CC1200_MARC_GPIO_IOCFG      CC1200_IOCFG3
+
+#define HAS_BOOT_RADIO         0
+
+/*
+ * mpu9250
+ */
+
+#define HAS_MPU9250            1
+#define AO_MPU9250_INT_PORT    (&stm_gpioe)
+#define AO_MPU9250_INT_PIN     0
+#define AO_MPU9250_SPI_BUS     AO_SPI_1_PE13_PE14_PE15
+#define AO_MPU9250_SPI_CS_PORT (&stm_gpiod)
+#define AO_MPU9250_SPI_CS_PIN  2
+#define HAS_IMU                        1
+
+/*
+ * mma655x
+ */
+
+#define HAS_MMA655X            1
+#define AO_MMA655X_INVERT      0
+#define AO_MMA655X_SPI_INDEX   AO_SPI_1_PE13_PE14_PE15
+#define AO_MMA655X_CS_PORT     (&stm_gpiod)
+#define AO_MMA655X_CS_PIN      4
+
+#define NUM_CMDS               16
+
+/*
+ * Companion
+ */
+
+#define AO_COMPANION_CS_PORT   (&stm_gpiob)
+#define AO_COMPANION_CS_PIN_0  (6)
+#define AO_COMPANION_CS_PIN    AO_COMPANION_CS_PIN_0
+#define AO_COMPANION_CS_PIN_1  (7)
+#define AO_COMPANION_SPI_BUS   AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Monitor
+ */
+
+#define HAS_MONITOR            0
+#define LEGACY_MONITOR         0
+#define HAS_MONITOR_PUT                1
+#define AO_MONITOR_LED         0
+#define HAS_RSSI               0
+
+/*
+ * Profiling Viterbi decoding
+ */
+
+#ifndef AO_PROFILE
+#define AO_PROFILE             0
+#endif
+
+/*
+ * PWM output
+ */
+
+#define NUM_PWM                        4
+#define PWM_MAX                        20000
+#define AO_PWM_TIMER           stm_tim4
+#define AO_PWM_TIMER_ENABLE    STM_RCC_APB1ENR_TIM4EN
+#define AO_PWM_TIMER_SCALE     32
+
+#define AO_PWM_0_GPIO          (&stm_gpiod)
+#define AO_PWM_0_PIN           12
+
+#define AO_PWM_1_GPIO          (&stm_gpiod)
+#define AO_PWM_1_PIN           13
+
+#define AO_PWM_2_GPIO          (&stm_gpiod)
+#define AO_PWM_2_PIN           14
+
+#define AO_PWM_3_GPIO          (&stm_gpiod)
+#define AO_PWM_3_PIN           15
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telemega-v3.0/ao_telemega.c b/src/telemega-v3.0/ao_telemega.c
new file mode 100644 (file)
index 0000000..2259c75
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2017 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_mpu9250.h>
+#include <ao_mma655x.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_packet.h>
+#include <ao_companion.h>
+#include <ao_profile.h>
+#include <ao_eeprom.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#include <ao_pyro.h>
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+#include <ao_pwm.h>
+
+int
+main(void)
+{
+       ao_clock_init();
+
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+
+       ao_task_init();
+       ao_serial_init();
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(LEDS_AVAILABLE);
+       ao_timer_init();
+
+       ao_i2c_init();
+       ao_spi_init();
+       ao_dma_init();
+       ao_exti_init();
+
+       ao_adc_init();
+#if HAS_BEEP
+       ao_beep_init();
+#endif
+       ao_cmd_init();
+
+#if HAS_MS5607
+       ao_ms5607_init();
+#endif
+#if HAS_MPU9250
+       ao_mpu9250_init();
+#endif
+#if HAS_MMA655X
+       ao_mma655x_init();
+#endif
+
+       ao_eeprom_init();
+       ao_storage_init();
+
+       ao_flight_init();
+       ao_log_init();
+       ao_report_init();
+
+       ao_usb_init();
+       ao_gps_init();
+       ao_gps_report_mega_init();
+       ao_telemetry_init();
+       ao_radio_init();
+       ao_packet_slave_init(FALSE);
+       ao_igniter_init();
+       ao_companion_init();
+       ao_pyro_init();
+
+       ao_config_init();
+#if AO_PROFILE
+       ao_profile_init();
+#endif
+#if HAS_SAMPLE_PROFILE
+       ao_sample_profile_init();
+#endif
+
+       ao_pwm_init();
+
+       ao_led_off(LEDS_AVAILABLE);
+
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/telemega-v3.0/flash-loader/Makefile b/src/telemega-v3.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..9e00293
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telemega-v3.0
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/telemega-v3.0/flash-loader/ao_pins.h b/src/telemega-v3.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..6e9bba5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2017 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 8MHz */
+#define AO_HSE         8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port cs_companion0 PB6 */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpiob
+#define AO_BOOT_APPLICATION_PIN                6
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
index d906317309db1c4ff7d30f91cf28f05198e22445..d26a5193950d50e5015cb3e02c3650a595e5249a 100644 (file)
@@ -64,6 +64,7 @@
 #define AO_CONFIG_MAX_SIZE                     1024
 #define LOG_ERASE_MARK                         0x55
 #define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMETRUM
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
index b937b4222f3c8f4e482910613540adf3ba9b606c..6d4369c92f1056b21b249c793b908f1d594f7a1a 100644 (file)
@@ -64,6 +64,7 @@
 #define AO_CONFIG_MAX_SIZE                     1024
 #define LOG_ERASE_MARK                         0x55
 #define LOG_MAX_ERASE                          128
+#define AO_LOG_FORMAT                          AO_LOG_FORMAT_TELEMETRUM
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
index c78766cdefa398847eec50df67418575d3696e50..29f16114062dac893e3680477affbf0da103e138 100644 (file)
 #define HAS_ADC                        1
 #define HAS_ADC_TEMP           1
 #define HAS_LOG                        1
+#define AO_LOG_FORMAT          AO_LOG_FORMAT_TELESCIENCE
 
 /*
  * SPI Flash memory
index 8d9f7a2f1c0f55b579140aa7bbd292d58d4ebc13..5bcf2c8a383c654d4db625e916127a0fa9cbd93b 100644 (file)
@@ -75,6 +75,8 @@
        #define HAS_TELEMETRY           0
 
        #define AO_VALUE_32             0
+
+       #define AO_LOG_FORMAT           AO_LOG_FORMAT_TELEMETRY
 #endif
 
 #if DBG_ON_P1
index 088084303edc74cea9d6ff108e12a803aa63daa8..7bd13db9a461d8095ccd46c2b3b28eab112a7ede 100644 (file)
@@ -1,10 +1,13 @@
-vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product:../lisp
+vpath %.o .
+vpath %.c ..:../kernel:../drivers:../util:../micropeak:../aes:../product
+vpath %.h ..:../kernel:../drivers:../util:../micropeak:../aes:../product
+vpath make-kalman ..:../kernel:../drivers:../util:../micropeak:../aes:../product
 
 PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \
        ao_flight_test_metrum ao_flight_test_mini \
        ao_gps_test ao_gps_test_skytraq ao_gps_test_ublox ao_convert_test ao_convert_pa_test ao_fec_test \
        ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \
-       ao_ms5607_convert_test ao_quaternion_test ao_lisp_test
+       ao_ms5607_convert_test ao_quaternion_test
 
 INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h ao_eeprom_read.h
 TEST_SRC=ao_flight_test.c
@@ -17,7 +20,7 @@ CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -
 
 all: $(PROGS) ao_aprs_data.wav
 
-clean:
+clean::
        rm -f $(PROGS) ao_aprs_data.wav run-out.baro run-out.full
 
 install:
@@ -94,12 +97,3 @@ ao_ms5607_convert_test: ao_ms5607_convert_test.c ao_ms5607_convert_8051.c ao_int
 ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h
        cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm
 
-AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o  ao_lisp_cons.o ao_lisp_string.o \
-       ao_lisp_atom.o ao_lisp_int.o ao_lisp_eval.o ao_lisp_poly.o \
-       ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o \
-       ao_lisp_lambda.o ao_lisp_error.o ao_lisp_save.o ao_lisp_stack.o
-
-ao_lisp_test: $(AO_LISP_OBJS)
-       cc $(CFLAGS) -o $@ $(AO_LISP_OBJS)
-
-$(AO_LISP_OBJS): ao_lisp.h ao_lisp_const.h ao_lisp_os.h
index 298848d6a46b4a7921bd8fddb9ba4605020e3e25..2d862f82a944f5663281273bbcf52b1c45b859a7 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <getopt.h>
 #include <math.h>
+#define log ao_log_data
 
 #define GRAVITY 9.80665
 
@@ -370,7 +371,7 @@ extern int16_t ao_accel_2g;
 typedef int16_t        accel_t;
 
 uint16_t       ao_serial_number;
-uint16_t       ao_flight_number;
+int16_t                ao_flight_number;
 
 extern uint16_t        ao_sample_tick;
 
@@ -998,7 +999,7 @@ main (int argc, char **argv)
 #else
        emulator_app="baro";
 #endif
-       while ((c = getopt_long(argc, argv, "sdi:", options, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "sdpi:", options, NULL)) != -1) {
                switch (c) {
                case 's':
                        summary = 1;
@@ -1006,6 +1007,11 @@ main (int argc, char **argv)
                case 'd':
                        ao_flight_debug = 1;
                        break;
+               case 'p':
+#if PYRO_DBG
+                       pyro_dbg = 1;
+#endif
+                       break;
                case 'i':
                        info = optarg;
                        break;
diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h
deleted file mode 100644 (file)
index 9ff2e1f..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright © 2016 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_LISP_OS_H_
-#define _AO_LISP_OS_H_
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-#define AO_LISP_POOL_TOTAL     3072
-#define AO_LISP_SAVE           1
-#define DBG_MEM_STATS          1
-
-extern int ao_lisp_getc(void);
-
-static inline void
-ao_lisp_os_flush() {
-       fflush(stdout);
-}
-
-static inline void
-ao_lisp_abort(void)
-{
-       abort();
-}
-
-static inline void
-ao_lisp_os_led(int led)
-{
-       printf("leds set to 0x%x\n", led);
-}
-
-static inline void
-ao_lisp_os_delay(int delay)
-{
-       if (!delay)
-               return;
-       struct timespec ts = {
-               .tv_sec = delay / 1000,
-               .tv_nsec = (delay % 1000) * 1000000,
-       };
-       nanosleep(&ts, NULL);
-}
-#endif
diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c
deleted file mode 100644 (file)
index 68e3a20..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.
- */
-
-#include "ao_lisp.h"
-#include <stdio.h>
-
-static FILE *ao_lisp_file;
-static int newline = 1;
-
-static char save_file[] = "lisp.image";
-
-int
-ao_lisp_os_save(void)
-{
-       FILE    *save = fopen(save_file, "w");
-
-       if (!save) {
-               perror(save_file);
-               return 0;
-       }
-       fwrite(ao_lisp_pool, 1, AO_LISP_POOL_TOTAL, save);
-       fclose(save);
-       return 1;
-}
-
-int
-ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset)
-{
-       FILE    *restore = fopen(save_file, "r");
-       size_t  ret;
-
-       if (!restore) {
-               perror(save_file);
-               return 0;
-       }
-       fseek(restore, offset, SEEK_SET);
-       ret = fread(save, sizeof (struct ao_lisp_os_save), 1, restore);
-       fclose(restore);
-       if (ret != 1)
-               return 0;
-       return 1;
-}
-
-int
-ao_lisp_os_restore(void)
-{
-       FILE    *restore = fopen(save_file, "r");
-       size_t  ret;
-
-       if (!restore) {
-               perror(save_file);
-               return 0;
-       }
-       ret = fread(ao_lisp_pool, 1, AO_LISP_POOL_TOTAL, restore);
-       fclose(restore);
-       if (ret != AO_LISP_POOL_TOTAL)
-               return 0;
-       return 1;
-}
-
-int
-ao_lisp_getc(void)
-{
-       int c;
-
-       if (ao_lisp_file)
-               return getc(ao_lisp_file);
-
-       if (newline) {
-               printf("> ");
-               newline = 0;
-       }
-       c = getchar();
-       if (c == '\n')
-               newline = 1;
-       return c;
-}
-
-int
-main (int argc, char **argv)
-{
-       while (*++argv) {
-               ao_lisp_file = fopen(*argv, "r");
-               if (!ao_lisp_file) {
-                       perror(*argv);
-                       exit(1);
-               }
-               ao_lisp_read_eval_print();
-               fclose(ao_lisp_file);
-               ao_lisp_file = NULL;
-       }
-       ao_lisp_read_eval_print();
-
-       printf ("collects: full: %d incremental %d\n",
-               ao_lisp_collects[AO_LISP_COLLECT_FULL],
-               ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]);
-
-       printf ("freed: full %d incremental %d\n",
-               ao_lisp_freed[AO_LISP_COLLECT_FULL],
-               ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL]);
-
-       printf("loops: full %d incremental %d\n",
-               ao_lisp_loops[AO_LISP_COLLECT_FULL],
-               ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL]);
-
-       printf("loops per collect: full %f incremental %f\n",
-              (double) ao_lisp_loops[AO_LISP_COLLECT_FULL] /
-              (double) ao_lisp_collects[AO_LISP_COLLECT_FULL],
-              (double) ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL] /
-              (double) ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]);
-
-       printf("freed per collect: full %f incremental %f\n",
-              (double) ao_lisp_freed[AO_LISP_COLLECT_FULL] /
-              (double) ao_lisp_collects[AO_LISP_COLLECT_FULL],
-              (double) ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL] /
-              (double) ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]);
-
-       printf("freed per loop: full %f incremental %f\n",
-              (double) ao_lisp_freed[AO_LISP_COLLECT_FULL] /
-              (double) ao_lisp_loops[AO_LISP_COLLECT_FULL],
-              (double) ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL] /
-              (double) ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL]);
-}
diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp
deleted file mode 100644 (file)
index e2eb0fa..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-;
-; Towers of Hanoi
-;
-; 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.
-;
-
-                                       ; ANSI control sequences
-
-(defun move-to (col row)
-  (patom "\033[" row ";" col "H")
-  )
-
-(defun clear ()
-  (patom "\033[2J")
-  )
-
-(defun display-string (x y str)
-  (move-to x y)
-  (patom str)
-  )
-
-                                       ; Here's the pieces to display
-
-(setq stack '("     *     " "    ***    " "   *****   " "  *******  " " ********* " "***********"))
-
-                                       ; Here's all of the stacks of pieces
-                                       ; This is generated when the program is run
-
-(setq stacks nil)
-
-                                       ; Display one stack, clearing any
-                                       ; space above it
-
-(defun display-stack (x y clear stack)
-  (cond ((= 0 clear)
-        (cond (stack 
-               (display-string x y (car stack))
-               (display-stack x (1+ y) 0 (cdr stack))
-               )
-              )
-        )
-       (t 
-        (display-string x y "                   ")
-        (display-stack x (1+ y) (1- clear) stack)
-        )
-       )
-  )
-
-                                       ; Position of the top of the stack on the screen
-                                       ; Shorter stacks start further down the screen
-
-(defun stack-pos (y stack)
-  (- y (length stack))
-  )
-
-                                       ; Display all of the stacks, spaced 20 columns apart
-
-(defun display-stacks (x y stacks)
-  (cond (stacks
-        (display-stack x 0 (stack-pos y (car stacks)) (car stacks))
-        (display-stacks (+ x 20) y (cdr stacks)))
-       )
-  )
-
-                                       ; Display all of the stacks, then move the cursor
-                                       ; out of the way and flush the output
-
-(defun display ()
-  (display-stacks 0 top stacks)
-  (move-to 1 21)
-  (flush)
-  )
-
-                                       ; Reset stacks to the starting state, with
-                                       ; all of the pieces in the first stack and the
-                                       ; other two empty
-
-(defun reset-stacks ()
-  (setq stacks (list stack nil nil))
-  (setq top (+ (length stack) 3))
-  (length stack)
-  )
-
-                                       ; more functions which could usefully
-                                       ; be in the rom image
-
-(defun min (a b)
-  (cond ((< a b) a)
-       (b)
-       )
-  )
-
-                                       ; Replace a stack in the list of stacks
-                                       ; with a new value
-
-(defun replace (list pos member)
-  (cond ((= pos 0) (cons member (cdr list)))
-       ((cons (car list) (replace (cdr list) (1- pos) member)))
-       )
-  )
-
-                                       ; Move a piece from the top of one stack
-                                       ; to the top of another
-
-(setq move-delay 100)
-
-(defun move-piece (from to)
-  (let ((from-stack (nth stacks from))
-       (to-stack (nth stacks to))
-       (piece (car from-stack)))
-    (setq from-stack (cdr from-stack))
-    (setq to-stack (cons piece to-stack))
-    (setq stacks (replace stacks from from-stack))
-    (setq stacks (replace stacks to to-stack))
-    (display)
-    (delay move-delay)
-    )
-  )
-
-; The implementation of the game
-
-(defun _hanoi (n from to use)
-  (cond ((= 1 n)
-        (move-piece from to)
-        )
-       (t
-        (_hanoi (1- n) from use to)
-        (_hanoi 1 from to use)
-        (_hanoi (1- n) use to from)
-        )
-       )
-  )
-
-                                       ; A pretty interface which
-                                       ; resets the state of the game,
-                                       ; clears the screen and runs
-                                       ; the program
-
-(defun hanoi ()
-  (setq len (reset-stacks))
-  (clear)
-  (_hanoi len 0 1 2)
-  (move-to 0 23)
-  t
-  )
index 3646f000a450d2b65a8c1304520a7a84098f248c..1433c9e164c01bade972e009d7a7b42f6c13d0e8 100644 (file)
@@ -30,7 +30,7 @@ import org.altusmetrum.altosuilib_12.*;
 
 public class TeleGPS
        extends AltosUIFrame
-       implements AltosFlightDisplay, AltosFontListener, AltosUnitsListener, ActionListener
+       implements AltosFlightDisplay, AltosFontListener, AltosUnitsListener, ActionListener, AltosEepromGrapher
 {
 
        static String[] telegps_icon_names = {
@@ -280,7 +280,7 @@ public class TeleGPS
        }
 
        void download(){
-               new AltosEepromManage(this, AltosLib.product_telegps);
+               new AltosEepromManage(this, this, AltosLib.product_telegps);
        }
 
        void configure() {
@@ -316,6 +316,21 @@ public class TeleGPS
                }
        }
 
+       public void graph_flights(AltosEepromList list) {
+               for (AltosEepromLog log : list) {
+                       if (log.file != null) {
+                               AltosRecordSet set = record_set(log.file);
+                               if (set != null) {
+                                       try {
+                                               new TeleGPSGraphUI(set, log.file);
+                                       } catch (InterruptedException ie) {
+                                       } catch (IOException ie) {
+                                       }
+                               }
+                       }
+               }
+       }
+
        void flash() {
                AltosFlashUI.show(this);
        }
index 9d8c6bf5a4ae1444ae616d7c3cbf1f6c19ebdba0..c68f2badbdaf3a06a00e35454fa5b69e7a58fe85 100644 (file)
@@ -34,7 +34,7 @@ import org.jfree.chart.ChartPanel;
 import org.jfree.chart.JFreeChart;
 import org.jfree.ui.RefineryUtilities;
 
-public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener
+public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener
 {
        JTabbedPane             pane;
        AltosGraph              graph;
@@ -92,20 +92,38 @@ public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, A
                        enable.units_changed(imperial_units);
        }
 
+       AltosUIFlightSeries flight_series;
+
+       public void filter_changed(double speed_filter, double accel_filter) {
+               flight_series.set_filter(speed_filter, accel_filter);
+               graph.filter_changed();
+               stats = new AltosFlightStats(flight_series);
+               statsTable.filter_changed(stats);
+       }
+
+       public double speed_filter() {
+               return flight_series.speed_filter_width;
+       }
+
+       public double accel_filter() {
+               return flight_series.accel_filter_width;
+       }
+
        TeleGPSGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException {
                super(file.getName());
                AltosCalData cal_data = set.cal_data();
 
-               AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data);
+               flight_series = new AltosUIFlightSeries(cal_data);
                set.capture_series(flight_series);
                flight_series.finish();
 
                pane = new JTabbedPane();
 
-               enable = new AltosUIEnable();
+               graph = new AltosGraph(enable, stats, flight_series);
+
                stats = new AltosFlightStats(flight_series);
 
-               graph = new AltosGraph(enable, stats, flight_series);
+               enable = new AltosUIEnable(this);
 
                statsTable = new AltosFlightStatsTable(stats);