Merge branch 'branch-1.7' into debian
authorBdale Garbee <bdale@gag.com>
Tue, 25 Apr 2017 00:22:03 +0000 (18:22 -0600)
committerBdale Garbee <bdale@gag.com>
Tue, 25 Apr 2017 00:22:03 +0000 (18:22 -0600)
243 files changed:
ChangeLog
altoslib/AltosConvert.java
altoslib/AltosEepromChunk.java
altoslib/AltosEepromFile.java
altoslib/AltosEepromFireTwo.java [new file with mode: 0644]
altoslib/AltosEepromMini.java
altoslib/AltosIdleFetch.java
altoslib/AltosLib.java
altoslib/AltosSensorTMini.java [deleted file]
altoslib/AltosSensorTMini2.java [new file with mode: 0644]
altoslib/AltosSensorTMini3.java [new file with mode: 0644]
altoslib/AltosTelemetry.java
altoslib/AltosTelemetryMini.java [deleted file]
altoslib/AltosTelemetryMini2.java [new file with mode: 0644]
altoslib/AltosTelemetryMini3.java [new file with mode: 0644]
altoslib/AltosTelemetryStandard.java
altoslib/Makefile.am
ao-bringup/test-chaoskey
ao-bringup/test-easymini
ao-bringup/test-telemini [new file with mode: 0755]
ao-bringup/turnon_easymega
ao-bringup/turnon_easymini
ao-bringup/turnon_teledongle
ao-bringup/turnon_teledongle_v0.2
ao-bringup/turnon_telegps
ao-bringup/turnon_telemetrum
ao-bringup/turnon_telemetrum_v1.1 [new file with mode: 0755]
ao-bringup/turnon_telemini
ao-tools/ao-flash/ao-flash-stm
ao-tools/ao-test-baro/ao-test-baro.c
ao-tools/lib/ao-selfload.c
configure.ac
doc/Makefile
doc/altosdroid.inc
doc/altosui.inc
doc/altusmetrum-docinfo.xml
doc/altusmetrum.txt
doc/fix-html [new file with mode: 0755]
doc/flight-data-recording.inc
doc/installation.inc
doc/intro.inc
doc/release-notes-1.7.inc [new file with mode: 0644]
doc/release-notes.inc
doc/specs.inc
doc/system-operation.inc
doc/telemetry.txt
doc/telemini-outline.txt [deleted file]
doc/telemini-v1-outline.txt [new file with mode: 0644]
doc/telemini-v1.0.inc [deleted file]
doc/telemini-v1.svg [new file with mode: 0644]
doc/telemini-v3-outline.txt [new file with mode: 0644]
doc/telemini-v3.0-bottom.jpg [new file with mode: 0644]
doc/telemini-v3.0-top.jpg [new file with mode: 0644]
doc/telemini-v3.svg [new file with mode: 0644]
doc/telemini.inc [new file with mode: 0644]
doc/telemini.svg [deleted file]
doc/updating-firmware.inc
src/avr/ao_avr_stdio.c
src/cc1111/ao_launch.c
src/cc1111/ao_launch.h [new file with mode: 0644]
src/cc1111/ao_timer.c
src/chaoskey-v1.0/.gitignore
src/chaoskey-v1.0/Makefile
src/chaoskey-v1.0/chaoskey-connector.svg [new file with mode: 0644]
src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in [new file with mode: 0644]
src/cortexelf-v1/Makefile [new file with mode: 0644]
src/cortexelf-v1/ao_1802.c [new file with mode: 0644]
src/cortexelf-v1/ao_1802.h [new file with mode: 0644]
src/cortexelf-v1/ao_cortexelf.c [new file with mode: 0644]
src/cortexelf-v1/ao_flip_bits.5c [new file with mode: 0644]
src/cortexelf-v1/ao_hex.c [new file with mode: 0644]
src/cortexelf-v1/ao_hex.h [new file with mode: 0644]
src/cortexelf-v1/ao_lisp_os.h [new file with mode: 0644]
src/cortexelf-v1/ao_lisp_os_save.c [new file with mode: 0644]
src/cortexelf-v1/ao_pins.h [new file with mode: 0644]
src/cortexelf-v1/cortexelf.ld [new file with mode: 0644]
src/cortexelf-v1/flash-loader/Makefile [new file with mode: 0644]
src/cortexelf-v1/flash-loader/ao_pins.h [new file with mode: 0644]
src/draw/5x7.bdf [new file with mode: 0644]
src/draw/Makefile [new file with mode: 0644]
src/draw/ao_blt.c [new file with mode: 0644]
src/draw/ao_copy.c [new file with mode: 0644]
src/draw/ao_draw.h [new file with mode: 0644]
src/draw/ao_draw_int.h [new file with mode: 0644]
src/draw/ao_font.h [new file with mode: 0644]
src/draw/ao_line.c [new file with mode: 0644]
src/draw/ao_pattern.c [new file with mode: 0644]
src/draw/ao_rect.c [new file with mode: 0644]
src/draw/ao_text.c [new file with mode: 0644]
src/draw/font-convert [new file with mode: 0755]
src/draw/line.5c [new file with mode: 0644]
src/drivers/ao_as1107.c [new file with mode: 0644]
src/drivers/ao_as1107.h [new file with mode: 0644]
src/drivers/ao_button.c
src/drivers/ao_cc115l.c
src/drivers/ao_cc1200.c
src/drivers/ao_console.c [new file with mode: 0644]
src/drivers/ao_console.h [new file with mode: 0644]
src/drivers/ao_event.h
src/drivers/ao_fat.c
src/drivers/ao_lco.c
src/drivers/ao_lco_cmd.c
src/drivers/ao_lco_func.c
src/drivers/ao_lco_func.h
src/drivers/ao_lco_two.c
src/drivers/ao_matrix.c [new file with mode: 0644]
src/drivers/ao_matrix.h [new file with mode: 0644]
src/drivers/ao_pad.c
src/drivers/ao_pad.h
src/drivers/ao_ps2.c [new file with mode: 0644]
src/drivers/ao_ps2.h [new file with mode: 0644]
src/drivers/ao_sdcard.c
src/drivers/ao_vga.c [new file with mode: 0644]
src/drivers/ao_vga.h [new file with mode: 0644]
src/kernel/ao.h
src/kernel/ao_cmd.c
src/kernel/ao_log.h
src/kernel/ao_log_firetwo.c [new file with mode: 0644]
src/kernel/ao_pyro.c
src/kernel/ao_report.c
src/kernel/ao_stdio.c
src/kernel/ao_task.c
src/kernel/ao_telemetry.c
src/kernel/ao_telemetry.h
src/lambdakey-v1.0/.gitignore [new file with mode: 0644]
src/lambdakey-v1.0/Makefile [new file with mode: 0644]
src/lambdakey-v1.0/ao_lambdakey.c [new file with mode: 0644]
src/lambdakey-v1.0/ao_lisp_os.h [new file with mode: 0644]
src/lambdakey-v1.0/ao_lisp_os_save.c [new file with mode: 0644]
src/lambdakey-v1.0/ao_pins.h [new file with mode: 0644]
src/lambdakey-v1.0/flash-loader/.gitignore [new file with mode: 0644]
src/lambdakey-v1.0/flash-loader/Makefile [new file with mode: 0644]
src/lambdakey-v1.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/lambdakey-v1.0/lambda.ld [new file with mode: 0644]
src/lisp/.gitignore [new file with mode: 0644]
src/lisp/Makefile [new file with mode: 0644]
src/lisp/Makefile-inc [new file with mode: 0644]
src/lisp/Makefile-lisp [new file with mode: 0644]
src/lisp/ao_lisp.h [new file with mode: 0644]
src/lisp/ao_lisp_atom.c [new file with mode: 0644]
src/lisp/ao_lisp_builtin.c [new file with mode: 0644]
src/lisp/ao_lisp_cons.c [new file with mode: 0644]
src/lisp/ao_lisp_const.lisp [new file with mode: 0644]
src/lisp/ao_lisp_error.c [new file with mode: 0644]
src/lisp/ao_lisp_eval.c [new file with mode: 0644]
src/lisp/ao_lisp_frame.c [new file with mode: 0644]
src/lisp/ao_lisp_int.c [new file with mode: 0644]
src/lisp/ao_lisp_lambda.c [new file with mode: 0644]
src/lisp/ao_lisp_lex.c [new file with mode: 0644]
src/lisp/ao_lisp_make_const.c [new file with mode: 0644]
src/lisp/ao_lisp_mem.c [new file with mode: 0644]
src/lisp/ao_lisp_os.h [new file with mode: 0644]
src/lisp/ao_lisp_poly.c [new file with mode: 0644]
src/lisp/ao_lisp_read.c [new file with mode: 0644]
src/lisp/ao_lisp_read.h [new file with mode: 0644]
src/lisp/ao_lisp_rep.c [new file with mode: 0644]
src/lisp/ao_lisp_save.c [new file with mode: 0644]
src/lisp/ao_lisp_stack.c [new file with mode: 0644]
src/lisp/ao_lisp_string.c [new file with mode: 0644]
src/lpc/Makefile-lpc.defs
src/lpc/ao_arch_funcs.h
src/nucleao-32/.gitignore [new file with mode: 0644]
src/nucleao-32/Makefile [new file with mode: 0644]
src/nucleao-32/ao_nucleo.c [new file with mode: 0644]
src/nucleao-32/ao_pins.h [new file with mode: 0644]
src/nucleao-32/flash-loader/.gitignore [new file with mode: 0644]
src/nucleao-32/flash-loader/Makefile [new file with mode: 0644]
src/nucleao-32/flash-loader/ao_pins.h [new file with mode: 0644]
src/pnpservo-v1/Makefile [new file with mode: 0644]
src/pnpservo-v1/ao_pins.h [new file with mode: 0644]
src/pnpservo-v1/ao_pnpservo.c [new file with mode: 0644]
src/pnpservo-v1/flash-loader/.gitignore [new file with mode: 0644]
src/pnpservo-v1/flash-loader/Makefile [new file with mode: 0644]
src/pnpservo-v1/flash-loader/ao_pins.h [new file with mode: 0644]
src/pnpservo-v1/lambda.ld [new file with mode: 0644]
src/stm-vga/Makefile [new file with mode: 0644]
src/stm-vga/ao_demo.c [new file with mode: 0644]
src/stm-vga/ao_lisp_os.h [new file with mode: 0644]
src/stm-vga/ao_lisp_os_save.c [new file with mode: 0644]
src/stm-vga/ao_pins.h [new file with mode: 0644]
src/stm/Makefile.defs
src/stm/altos-512.ld [new file with mode: 0644]
src/stm/ao_arch.h
src/stm/ao_arch_funcs.h
src/stm/ao_dma_stm.c
src/stm/ao_exti_stm.c
src/stm/ao_flash_stm.c
src/stm/ao_i2c_stm.c
src/stm/ao_serial_stm.c
src/stm/ao_timer.c
src/stm/ao_usb_stm.c
src/stm/stm32l.h
src/stmf0/Makefile-stmf0.defs
src/stmf0/altos-raw.ld [new file with mode: 0644]
src/stmf0/altos.ld
src/stmf0/ao_adc_stm.c [new file with mode: 0644]
src/stmf0/ao_arch.h
src/stmf0/ao_arch_funcs.h
src/stmf0/ao_beep_stm.c [new file with mode: 0644]
src/stmf0/ao_crc.h
src/stmf0/ao_flash_stm.c
src/stmf0/ao_interrupt.c
src/stmf0/ao_serial_stm.c [new file with mode: 0644]
src/stmf0/ao_spi_stm.c
src/stmf0/ao_spi_stm_slave.c [new file with mode: 0644]
src/stmf0/stm32f0.h
src/telebt-v3.0/Makefile
src/telebt-v3.0/ao_pins.h
src/telebt-v3.0/ao_telebt.c
src/teledongle-v3.0/ao_pins.h
src/telefiretwo-v0.1/ao_pins.h
src/telefiretwo-v0.2/ao_pins.h
src/telefiretwo-v1.0/Makefile [new file with mode: 0644]
src/telefiretwo-v1.0/ao_pins.h [new file with mode: 0644]
src/telefiretwo-v1.0/ao_telefiretwo.c [new file with mode: 0644]
src/telefiretwo-v1.0/flash-loader/.gitignore [new file with mode: 0644]
src/telefiretwo-v1.0/flash-loader/Makefile [new file with mode: 0644]
src/telefiretwo-v1.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/telegps-v0.1/ao_pins.h
src/telegps-v0.1/ao_telegps.c
src/telegps-v0.3/ao_pins.h
src/telegps-v1.0/ao_pins.h
src/telegps-v2.0/Makefile [new file with mode: 0644]
src/telegps-v2.0/ao_pins.h [new file with mode: 0644]
src/telegps-v2.0/ao_telegps.c [new file with mode: 0644]
src/telegps-v2.0/flash-loader/Makefile [new file with mode: 0644]
src/telegps-v2.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/telelco-v0.3/ao_pins.h
src/telelcotwo-v0.1/ao_pins.h
src/telemega-v2.0/ao_pins.h
src/telemetrum-v3.0/ao_pins.h
src/telemini-v2.0/ao_pins.h
src/telemini-v3.0/Makefile [new file with mode: 0644]
src/telemini-v3.0/ao_pins.h [new file with mode: 0644]
src/telemini-v3.0/ao_telemini.c [new file with mode: 0644]
src/telemini-v3.0/flash-loader/Makefile [new file with mode: 0644]
src/telemini-v3.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/test/Makefile
src/test/ao_aprs_test.c
src/test/ao_flight_test.c
src/test/ao_lisp_os.h [new file with mode: 0644]
src/test/ao_lisp_test.c [new file with mode: 0644]
src/test/hanoi.lisp [new file with mode: 0644]

index 9eb8703ff93e2838913c6a77f851bb5d95837ed0..69451886b7401d7b3d00306e5538d82ce33460bd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
-commit c0ad087008856cfc2233b977abfc3f1dcbaccdcc
-Merge: 148b013 4fdf8ca
+commit 9c95bed92a45741e6c1ad0ab4941f13370b77648
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 24 15:47:08 2017 -0700
+
+    Bump to version 1.7
+    
+    TeleMini v3.0 support
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3544c33c2f386fb292de9e74982717a002f37440
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 24 17:11:03 2017 -0700
+
+    altoslib: renamed AltosSensorTMini2, but didn't update AltosIdleFetch
+    
+    Because Java found the old installed version of this library. Thanks!
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5914231bfe8220a92dde17901b952e919a40d568
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Apr 24 17:18:10 2017 -0600
+
+    update copyright year in docs
+
+commit 8e5b4359050701513a807131564ae54f2e6b919b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 24 16:40:46 2017 -0700
+
+    altos/ao_pad.c: Use #if HAS_LOG instead of #ifdef HAS_LOG
+    
+    TeleFire v0.1 defines HAS_LOG to 0.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c57a5c018e4bd0a0033c8759132a648977bf45f7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 24 15:59:23 2017 -0700
+
+    doc: Errors in the TeleMini v3.0 updates found by Bdale
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b6b58aa2fbae1e7782b5a0b700544efe319fe34e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 22 22:04:31 2017 -0700
+
+    altos: Move old AO_LAUNCH defines to cc1111/ao_launch.h
+    
+    These were getting accidentally used by ao_pad.c
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cd291d38b92b31c3612e6de6cdf4e5988fc01c12
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Apr 23 00:02:47 2017 -0600
+
+    allow multiple tests to be logged on telefiretwo without rebooting
+
+commit d75351c5a07241bcbb951758796b4f639ace6b1f
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 23:42:23 2017 -0600
+
+    implement static test start and stop protocol for telefiretwo+telebt
+
+commit 6cfd9411026d536b5b75098b8c9ec3ceb3d945aa
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 23:02:53 2017 -0600
+
+    eliminate spurious close braces
+
+commit e3b30d4bd6faf68c885791fb87229558cc1157a6
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 23:01:44 2017 -0600
+
+    add static test start and stop commands to radio protocol for telefiretwo
+
+commit e5e0ce18b2ae684896a6d7d0a4c10269199d95b5
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 23:01:26 2017 -0600
+
+    enable logging support in telefiretwo
+
+commit e05b281e6d1a7a4fa92d52f2491f27266045df96
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 17:20:41 2017 -0600
+
+    cobble up a command to toggle logging on/off on TeleFireTwo
+
+commit db12c17e9538bd82f2c2bf21357887ee7d894a1c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 16:59:03 2017 -0600
+
+    a stab at turning on rudimentary logging for telefiretwo
+
+commit 6804ead7f7e54ff34b257e10e381dc52d5a61b06
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 22 15:55:48 2017 -0700
+
+    altoslib: Add TeleFireTwo eeprom support
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 359e2d6eca5258f4fabc59772f1320e195a7397c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 16:36:18 2017 -0600
+
+    fleshing out logging for telefiretwo
+
+commit 439a51ed503b74c1739cf150cdc91685653deed0
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 15:45:52 2017 -0600
+
+    enable spi flash on telefiretwo
+
+commit ffc90fa3f932aef4dd85147817949aa9474b6d26
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 22 11:38:08 2017 -0600
+
+    fix TeleFireTwo product name in ao-list output
+
+commit 4682323a4bf147b9a908f5f9104bf01ab2cf0533
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 23:02:57 2017 -0700
+
+    altos/stmf0: Pull beeper pin low when beeper is off
+    
+    This avoids having the pin float and pick up noise from any adjacent
+    signals, like TeleMini's radio.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eb1c2bf5244840049c0a58e0ceecfcd9f5c290dd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 22:24:00 2017 -0700
+
+    doc: Finish updates for v1.7
+    
+    Scrub all TeleMini references and make sure they're fixed for v3.  No
+    'emergency' mode yet.  No reflashing yet.
+    
+    Add v1.7 release notes.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5849ee6c09669e6d2e6940a76bcb5cc23178fc68
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 21:32:26 2017 -0700
+
+    altos/lpc: Really fix aes entry in lpc vpath
+    
+    I added another entry instead of fixing the existing one. Not ideal.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c833c93e812936125cfe9532523ea36b5046e58d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 18:16:45 2017 -0700
+
+    Replace turnon_telemini with v3 version. Add test-teleminiv3
+    
+    Prepare for TeleMini v3.0 release.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8978687dc2ae90e4005a8f7d598940b7df6a4359
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 18:08:25 2017 -0700
+
+    doc: Update TeleMini v3 photos to production unit
+    
+    Replace prototype photos
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 86a54146b58be86c58fb45386c7abcfa0bb11677
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 17:15:05 2017 -0700
+
+    alots/stmf0: Fix vpath entry for AES directory
+    
+    Mis-placed )
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 64ac93f5495db7a8b06f1eb4fe4eb2418125d792
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 17:06:23 2017 -0700
+
+    altos/lpc,altos/stmf0: Use -n flag to work around link editor issue
+    
+    Something changed in the link editor which makes it complain about 'no
+    space for program headers' on LPC and STMF0 builds. Somehow, adding
+    the '-n' flag to the linking step fixes it. It doesn't appear to break
+    the build, so I guess it's ok?
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77c76e429074a53c1c5230a7b5e665d1715b296f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 17:04:28 2017 -0700
+
+    altos/telemini-v3.0: Remove vestiges of the pre-USB code
+    
+    Pre-USB telemini v3 designs had a separate firmware load for radio
+    calibration. Now that we've got enough USB to perform flash/cal/test,
+    we don't need that other firmware load, so we can remove the remaining
+    Makefile remnants of the calibration load.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit adb842b64b04a7d70e543bad7ae59807d549e85a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 16:40:58 2017 -0700
+
+    altos/lpc: Add (void *) cast to fix alignment warning
+    
+    The -Wcast-align warning is generated when this cast is not present.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 51ce352d179835ca08e4cf9326e9e77d6b972fb7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 09:18:48 2017 -0700
+
+    altos/lpc: Fix up Makefile definitions
+    
+    vpath reference to aes was busted.
+    WARN_CFLAGS needs -Wcast-align.
+    Wrap AO_CFLAGS.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ec319edd2cda321d7542784b997acd0da040fa3d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 21 09:17:18 2017 -0700
+
+    ao-test-baro: Be more lax about altitude checks
+    
+    High pressure here today and the altimeter is reading -69m. Allow down
+    to -100m when testing baro values.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7db49a2052ec905cdc02f626c0933ca6889d64a4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 19 23:08:56 2017 -0700
+
+    altos/telemini-v3.0: Add flash loader
+    
+    Now that telemini has USB, use the boot loader to make it easy to
+    update firmware.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d1ba276c6e54564f82920f65bf4c19df85c9ea56
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 19 23:08:06 2017 -0700
+
+    altos/telemini-v3.0: Update to production hardware
+    
+    Removed LEDs. Added USB. Flipped lots of pins around.
+    
+    This appears to make telemini work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 93983730a6628a2a85b6fc543df236b35d501ee9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 19 16:00:24 2017 -0700
+
+    altos/telebt-v3.0: Add LCO bits for testing
+    
+    Add the USB commands for LCO testing to TeleBT v3.0
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 944d8466a31842c34304b77364d632e259238018
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 19 14:19:28 2017 -0700
+
+    altos/telefiretwo-v0.2: Add AO_CC1200_SPI_SPEED
+    
+    Needed for products with different SPI speed options.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1e7143e5d448cd05c355f4a323ae4892b02022ac
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Apr 19 15:08:15 2017 -0600
+
+    add new ADC channels for telefiretwo
+
+commit 6e699fa4971668bbe569d2a0e2ed9f891877d140
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Apr 18 16:47:43 2017 -0600
+
+    need top level Makefile too
+
+commit 9fa46346d576081f99860cad96c91bcf63233649
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Apr 18 16:47:05 2017 -0600
+
+    builds, loads, runs, not very useful yet
+
+commit 207403e53cc80b0649ce3c004f97d8e1dad824c8
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Apr 18 16:33:27 2017 -0600
+
+    copy telefiretwo-v0.2 to start firmware for v1.0
+
+commit f69d85e2b32370ab68e2725e739417cad6d7a590
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 13 21:48:46 2017 -0600
+
+    telegps-v2.0: Remove fec_tx code and ADC logging.
+    
+    This gets telegps-v2.0 to link.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e561ae43a734d870470e36c41232482bd5f398f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 13 21:47:14 2017 -0600
+
+    altos/stmf0: Split up rom load in altos.ld to make linker happy
+    
+    The linker isn't happy when the .ld file tries to add text, the .exidx
+    and .rodata segments in the same block. Split them up for success.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a5c8b8c59f99108233d99ceceb6f85315694e4b1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 13 21:18:58 2017 -0600
+
+    cortexelf-v1: Fetch data at TPB rising when MWR or MRD are low
+    
+    This should get the right value at least.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3390c62b6d0761764ec5249d72bda33b984a8f90
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 13 21:16:52 2017 -0600
+
+    altos/telegps: Inherit LDFLAGS from lpc make specification
+    
+    Somethings messed up with cortex-M0 linking, and this isn't helping as
+    it overrides the LDFLAGS coming from the architecture.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f18793efb1fbfd17963b9146fae084f2b843d7a3
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Apr 13 19:36:49 2017 -0600
+
+    initial cut at telegps-v2.0 firmware
+
+commit eb0b2b4e9f56d1d6fc2b06e39c8372dfcdf3b1f5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 13:03:50 2017 -0700
+
+    cortexelf-v1: Initialize key matrix code
+    
+    This gets the hex keypad working.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6efa53bafda18313742849a6c4992f09c3e403c3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 12:59:07 2017 -0700
+
+    cortexelf-v1: Bump SPI pin speed to 40MHz to for sdcard. Fix VGA DMA.
+    
+    Tell the DMA code to leave the DMA engine enabled so the VGA output
+    can use it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c97b4c65d66078a4e187b782669e6b36ee92d30c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 12:56:59 2017 -0700
+
+    altos: Use MP switch in cortexelf boot loader for force loader mode
+    
+    Provide a way to get to the boot loader on the cortexelf board by
+    turning the MP switch on.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9e80b8bd10433ecc6ebe7c295e16b62b3883987d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 12:55:34 2017 -0700
+
+    altos: Escape lisp REP loop with () input
+    
+    Provide a way to get out of a lisp read-eval-print loop that can be
+    easily input from the keyboard.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 83c1e4e8ca684f555cba252efd3882f811d8e154
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 12:54:57 2017 -0700
+
+    altos: Document a few more SPI mode bits in VGA driver
+    
+    Just comment changes
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 24cd5dd33ccf65c1b277911c460a89ec2b52e421
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 12:53:34 2017 -0700
+
+    altos: Drive row low instead of high in matrix driver
+    
+    Driving it high won't work all that well as we're looking for zero bits.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a68fb412589819980759d49565a084b23eee8b8f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 12:51:49 2017 -0700
+
+    altos: Place AS1107 in 'normal' mode at end of init sequence
+    
+    This makes sure the device is out of reset mode while initializing,
+    and then placed in normal mode to turn on the display.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 04d4b17635fc9395c70aa0840971c00082f509ba
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 9 12:48:54 2017 -0700
+
+    ao-elftohex: Add conditions for skipping ELF sections
+    
+    Skip sections with size 0, or which are of type SHT_NOBITS or which
+    don't have the SHF_ALLOC flag set.
+    
+    This avoids crashing on sections which don't have any data to copy.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 86d5119f19b5f3131d224982e011fd233b48aa22
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Apr 4 16:05:15 2017 -0700
+
+    cortexelf-v1: More 1802 noodling
+    
+    Add code to track the address and data displays, change how 1802 pin
+    tracking works
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 301b724d2169f4ac46d921f518455c783e1dd894
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Apr 4 16:04:25 2017 -0700
+
+    stm: Add more mask-based GPIO controls
+    
+    Lets cortexelf do more things with groups of pins, rather than one pin
+    at a time.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 71e430bb39fc97e543778f7bc1f1bef554ba8b75
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Apr 4 16:03:36 2017 -0700
+
+    altos: Allow programs to enable SDCARD debugging if desired
+    
+    Provides for per-application control over SDCARD debugging
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4eced9224f40e48d7057352b3424c18025f43f25
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Apr 4 16:02:46 2017 -0700
+
+    altos: Disable FAT commands unless requested
+    
+    This are debugging commands; don't provide them unless requested
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d4ff161e89d852c07934704ea2cbea20a48259a7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Apr 4 16:00:56 2017 -0700
+
+    telegps-v0.1: Hack up for SDCARD debugging
+    
+    Disable everything not SDCARD related for debugging.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 920b70fd5f6b78461c7ebae6b1e6490a0e050bc2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Apr 4 15:59:56 2017 -0700
+
+    altos: Define CC115L spi speed in each product
+    
+    Different SoCs have different SPI speeds available; have each product
+    specify the speed to use instead of trying to use 4Mhz everywhere.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 280eefc8f86e90e742c536a074d7284cce03af15
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 3 11:41:51 2017 -0700
+
+    cortexelf-v1: Add pin definitions for 1802 connections
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0197157a295d848bac65cf7f4457dd5a99af24e3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 3 11:37:21 2017 -0700
+
+    stm: Add a few more GPIO functions to make dealing with the 1802 easier
+    
+    ao_gpio_set_mask and ao_gpio_get_all
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 89c8e0299504e66fc416a778055958cff467e008
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 3 11:36:52 2017 -0700
+
+    cortexelf-v1: Make bit flipping array constant
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 47004dfe8ee8c8b31085b066d3d0fd5142fd49da
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 3 09:36:00 2017 -0700
+
+    cortexelf-v1: doodling with 1802 bits
+    
+    Just some random ideas about how to manage the 1802
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5bb9cf38c84663713c178f54b684d40b6c00b11d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 20:33:49 2017 -0700
+
+    cortexelf-v1: Add bit flipping array generator
+    
+    Someone hooked up the data lines between the systems backwards, so we
+    get to swizzle the bits in software.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8c1478b55f5dbe9711b31a34d4f5e3563f1f42d2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 19:32:17 2017 -0700
+
+    cortexelf-v1: Hook up hex keypad using matrix input driver
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 79215de60d3e11b4abd1ecd2fa9575a323b76754
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 19:31:45 2017 -0700
+
+    altos: Allow buttons to be high when pressed rather than low
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 09f8710eb320f37f20dda8c635497c2b505d25e2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 19:30:57 2017 -0700
+
+    altos: add button matrix driver
+    
+    Scans the matrix once per clock tick queuing events for changed keys.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 17ec1c510ccc42bbc387940b5805f452697f78d6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 17:39:26 2017 -0700
+
+    cortexelf-v1: Hook up AS1107 in test mode
+    
+    Provide a 'L' command to display values
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cc1b56faa88c75c9c86af89c77d7f1349573b7b0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 17:39:05 2017 -0700
+
+    altos: Add AS1107 LED display driver
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bc48b075f76bfef258f516549573429b24f284c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 16:37:42 2017 -0700
+
+    cortexelf-v1: Add buttons
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8284d3639cd24e2fa0faf1e35e7276ba35a24f8f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 16:22:28 2017 -0700
+
+    cortexelf-v1: Add serialblather command.
+    
+    This reads from stdin and dumps it to both serial ports until you type ~
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6fb817f218a69b28973b0d059d71809717b1e2d1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 16:17:33 2017 -0700
+
+    lisp: Fix up lisp build so projects can get ao_lisp_const.h built as needed
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3ce663875d69739cc2d43fcd88b22820cd9d6500
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 15:56:17 2017 -0700
+
+    stm: Use common flash wait loop instead of inlining
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1f5f0638f283fbb784021873c649109d4ed0257c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 15:53:17 2017 -0700
+
+    cortexelf: Add lisp interpreter
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 54c76d48924fecc2aeabbc352c553822a87f9d19
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 15:40:03 2017 -0700
+
+    cortexelf-v1: Use new memory map to access all flash and ram. Add fat.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7b031d5a86213364196b67f7e3f92865da8adbf9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 15:28:45 2017 -0700
+
+    cortexelf-v1: Hook up serial consoles for debugging
+    
+    This will make playing with serial ports easier for now.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 62b0228aed5191c8d769f9f34143a13036e210a7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 15:18:34 2017 -0700
+
+    cortexelf-v1: Fix clock to drive VGA at 640/480. Add sdcard, remove others
+    
+    VGA requires the CPU to run at 24MHz.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 637d522c6a15b47051103ccc3626be3206a7a2df
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 2 15:04:09 2017 -0700
+
+    cortexelf-v1: Add ps/2 and vga with graphics
+    
+    Start hooking up devices with known drivers.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f451db9889cd578c3032356fd2aa4b5ed45878d
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Apr 2 15:47:31 2017 -0600
+
+    capture pnpservo makefiles too
+
+commit bc150497de8539827177805c7f4430c67ca6762f
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Apr 2 15:47:14 2017 -0600
+
+    makefiles too
+
+commit 66b06332dadd83c309bbfe02240b7a071fd57ff2
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Apr 2 15:41:56 2017 -0600
+
+    initial skeleton of CortexELF support
+
+commit d318b5cfc1a0312697739576d35cc1a190d88849
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Apr 1 12:23:24 2017 -0600
+
+    first rough cut at skeleton of code for pnpservo .. altos boots and runs
+
+commit 190cdaa5cb18e78caeeaaaaed6a9d304e939eb6b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 5 22:42:37 2017 -0800
+
+    doc: Rename telemini doc file from telemini-v1.0.inc to telemini.inc
+    
+    This file now contains information on both TeleMini versions.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7bb4dbab45f98dd5fd85d9daf12d27b153c0ef3a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 5 22:33:36 2017 -0800
+
+    ao-tools/ao-flash-stm: Use openocd instead of st-utils
+    
+    openocd upstream and debian package can both flash stm32l processors,
+    so use that in preference to st-flash.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f004eaa2c26b4c61a8c3de2c0667a4e9865e704d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Mar 2 13:37:12 2017 -0800
+
+    ao-tools/ao-flash-lpc: Adapt to current openocd LPC support
+    
+    Openocd 0.9.0 has generalized the lpc11xx support for all lpc11xx
+    processors, not just the lpc11u14. This replaces the specific
+    lpc11u14.cfg with the general lpc11xx.cfg file.
+    
+    Unlike the build we were using, this doesn't adjust the
+    'verify' command to adapt for the checksum which gets added during the
+    flashing process. Hence, we disable verification and trust that if the
+    flash loader works to load the OS, it's fine.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 59aaac44e3e164b326518b324b52d115fbb76fca
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Mar 1 14:01:59 2017 -0800
+
+    telemini outline svg had wrong version number
+
+commit b5a42665d7811707b6bd4a67d7d8e6532daa29e4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Mar 1 13:53:36 2017 -0800
+
+    Add initial TeleMini v3 docs
+    
+    Uses pictures of the prototype.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d1c2a5729da00be9d393015bbaa2d2f58e936d84
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 17:34:43 2017 -0800
+
+    altos/nucleo-32: Update lisp files, add beeper support
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d1956000ba2e6260977aa669475d3ff725578b55
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 17:32:09 2017 -0800
+
+    altos/lisp: Not quite ready to start making it look like scheme yet
+    
+    Lots more code to write before these symbols can be exposed.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9603d737e9ea58217ff2c2dd7c350c7a29fba980
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 17:29:15 2017 -0800
+
+    altos/stmf0: Support timer 2/3 for the beeper
+    
+    Tested on timer 2, all four channels.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 003e9479ad4364d9f7acf189b35f32ccdfd43be0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 16:51:09 2017 -0800
+
+    altos/stmf0: Support tim1 beeper channel other than 3
+    
+    ch1 was broken and ch2 didn't have any code at all.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3c3f5e316c0c2464568db883d50881f5b898abac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 17:33:37 2017 -0800
+
+    altos/telemini-v3.0: Add beeper defines needed for more general beeper code
+    
+    The beeper code now wants to know which timer, port and pin are in use.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dc4bee9600be22531fd3c5bec15f712eb2e7ed2d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:18:58 2017 -0800
+
+    altos: Add stm-vga demo project
+    
+    Uses the VGA and PS/2 drivers to provide an interactive console.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0eadc2d50417408beebd50e4a0e7e12430ed67ef
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:16:27 2017 -0800
+
+    altos/stm: Add draw and lisp to make search paths.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c296acd643698d0128e2f58f91a9cfeea63f580a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:21:39 2017 -0800
+
+    altos: Add console driver using VGA and PS/2
+    
+    Provides an interactive text console.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c1d52178ce63ebdc44c83d1bca5027942e2d778c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:19:42 2017 -0800
+
+    altos: Add PS/2 keyboard driver
+    
+    Interrupt driven, includes standard US keymap.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6b39d3093c3b87689717bb03988d160473c53c64
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 20 00:04:27 2016 -0800
+
+    altos: Add VGA driver for STM32L processors
+    
+    Generates vsync/hsync using timers and pixel data using the SPI port.
+    320x240 video using 640x480 mode and a 24MHz "pixel" clock.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1301d576d9bface4cc625e4a4187401f93f54444
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:17:42 2017 -0800
+
+    altos: Add bitmap drawing code
+    
+    Includes solid fills, text and lines.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a487d2fcba57141f6b083d5612c76bac5ad1ac7c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:15:45 2017 -0800
+
+    altos/stm: Add nvic priority register fields. Add more TIM234 defines.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 80fd7f7bef5320ce86048d74dc4a72e1ec361120
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:14:10 2017 -0800
+
+    altos/stm: Make i2c code handle PCLK1 of 24MHz
+    
+    Just adds the necessary defines to the code.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 72ea90d28817549c4343d2fea03a4c951f849cbe
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 20 12:12:43 2017 -0800
+
+    altos/stm: Allow DMA channels to be hijacked by other code
+    
+    This lets code which needs finer control over DMA to use the channel
+    without interference, and leaves the DMA engine running so that it can.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5dc5e2e238f8c1a8ca35d85ec046124afa9385ad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jan 10 14:45:25 2017 -0800
+
+    altos: Allow for console to be used for stdio
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e6fb0f13ba230ad9ce86cfa7f56491a0a3bd4b3d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jan 10 14:43:07 2017 -0800
+
+    altos/avr: Avoid warning about unused args in stdio_put and stdio_get
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 839eadbc8e5694842eb498c6e47cfbf08ba8fbf4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 20 02:59:40 2016 -0800
+
+    altos/stm: Allow use basepri instead of primask for masking interrupts
+    
+    This allows for high priority interrupts (priority 0) to run, even
+    when other interrupts are blocked. Code executing in such interrupt
+    handlers must not attempt to control task execution as that will race
+    with the scheduler.
+    
+    Select this by defining AO_NONMASK_INTERRUPT in ao_pins.h.
+    non-maskable interrupt priority is AO_STM_NVIC_NONMASK_PRIORITY
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 088ddbb177efc8be2fc467524dc1668553080d3b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 20 20:54:10 2016 -0800
+
+    altos/stm: Interrupt priority is in the upper bits of the priority mask
+    
+    Because the STM32L only offers 16 priority levels, the bottom four
+    bits of each priority mask are not used. All of the interrupt priority
+    settings in the system were using values < 16, making them all
+    effectively the same. Fix that by moving them into the upper 4 bits
+    and using symbolic constants everywhere.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 992eee8e0b4c6c774f3355af107fb422019ff4e5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 20 20:56:01 2016 -0800
+
+    altos: Don't wait while idle if trying to minimize interrupt latency
+    
+    Keeping the scanout running reasonably means keeping interrupt latency
+    constant, and that requires leaving the CPU running. Don't wait for
+    interrupts when the system is running in this mode.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f0c187dd6479996b83f85b6decf303ec0fc70fe5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jan 6 09:10:23 2017 -0800
+
+    ao-tools/ao-usbload: Pad image with 0xff instead of random bits
+    
+    Clear the temporary block to 0xff before copying in the target data so
+    that any unused bytes end up being left at 0xff instead of inheriting
+    whatever data was in the block before.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 61f729567ff6355ab52c3e83399761103022a41a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 17 20:57:38 2016 -0800
+
+    altos/cc1111: Remove unneeded initialization in ao_timer.c
+    
+    The timers are all stopped when the chip boots, so no need to stop
+    them. This saves some text space, allowing the current code to (just
+    barely) fit.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1029a6e4a61b20698e00e29fc0c8c3877f1e7b0f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 19 17:36:04 2017 -0800
+
+    altoslib: Add TeleMini v3 support
+    
+    eeprom, telemetry and monitor idle. This is just like TeleMini v2,
+    except the ADC ranges are all difference as the voltage dividers are
+    different and the ADC itself has a different range.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5c272d8e50d0b23f31a6a9ebdad81fc514936222
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 19 17:40:28 2017 -0800
+
+    altos/telemini-v3.0: Swap main and apogee sense pins.
+    
+    These were just hooked up wrong in the software.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 59ac667c4ae14e0fa699fb0f398d31763a237646
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 19 17:39:21 2017 -0800
+
+    altos: Split out TeleMini v3 log/telem labeling
+    
+    Allow the ground software to know which TeleMini version is in use,
+    even though they are very similar with only ADC values differing.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c75736c9cd8f869c257a3024efda843cf0edf2a3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Feb 18 22:56:49 2017 -0800
+
+    altos/telemini-v3.0: Finish initial turn-on
+    
+    TeleMini v3.0 is nearly working; there are some ADC issues still, and
+    lots of altosui work left to decode the new telemetry packet.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit efdeb402d04e7f04ad4bd2764f8f1ca7270b3dff
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Feb 3 06:52:57 2017 +0100
+
+    altos/telemini-v3.0: Update to second prototype version
+    
+    Separate radio xtal means we run the processor at 48MHz.
+    Fix the battery monitoring voltage divider resistor values.
+    Disable most of the code until we've got the radio working.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 97c814bc12893bee40f9dc38fabbaa69e0dc6aed
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jan 28 15:35:48 2017 -0800
+
+    altos: Initial TeleMini v3.0 code
+    
+    For first prototype, which attempted to use the SoC clock for the radio.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b94fe9915b33283df6b86bcdc96ceada1fc71ce6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 19 17:42:05 2017 -0800
+
+    altos/stmf0: Add adc and beep support for TeleMini v3.0
+    
+    Note that the ADC code is running very slowly as required by the high
+    impedance dividers on the TeleMini v3.0 pyro circuits.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1dc31a46f1d1adfdeab444664e581a780d995bf7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Feb 18 22:49:34 2017 -0800
+
+    altos: Require SPI speed to be declared for cc1200
+    
+    The cc1200 can't run SPI faster than 10MHz, so make sure every device
+    picks a SPI clock slower than that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0bf267a6e2d401c8bd6a06d995e3d000777d622a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Feb 18 22:55:41 2017 -0800
+
+    altos: Allow applications to define LEDs for ao_report.c
+    
+    In case they don't have both a red and green LED.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cf10239e5485a101fcd7a12b28be927af94d577a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Feb 18 22:54:35 2017 -0800
+
+    altos/stmf0: Allow projects to not use the USB boot loader
+    
+    Let applications define HAS_BOOT_LOADER on their own if desired.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3770a5f527cb6d519ce22fe91e0cc4078bf72661
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Feb 18 22:53:03 2017 -0800
+
+    altos/stmf0: Complain if the SPI configuration isn't complete
+    
+    If the pin usage values SPI_1_PA5_PA6_PA7 or SPI_1_PB3_PB4_PB5 aren't
+    defined, then the speed values for the pins aren't going to get set
+    correctly, which results in erratic SPI behaviour.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f85997eb53779e637dca697d0d96da7d1235fa80
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Feb 3 06:51:11 2017 +0100
+
+    altos/stmf0: Allow apps to leave interrupt vectors at 0
+    
+    TeleMini v3.0 doesn't need a boot loader, so we'll have the app run
+    its interrupt vector right at the bottom of the address space instead
+    of copying it to the bottom of ram and reconfiguring the chip to use that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f43c3ad0c643f714c523e513bdc8585c6d5a4050
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Feb 18 22:46:29 2017 -0800
+
+    ao-bringup: test-chaoskey needs to use the SerialNumber dmesg line
+    
+    I had a locally hacked kernel which was reporting the serial number
+    along with the device name. Instead of depending on that, just look
+    for the regular SerialNumber report which is in all kernel versions
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a21c7b5156e428a4f8e029fdb652c8ca1c63823b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Feb 3 06:47:32 2017 +0100
+
+    ao-bringup: Allow serial number on turnon_easymega cmdline
+    
+    This makes it a bit quicker to do a batch of them.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 51edc29f5ba758ef8ba4fdd5f53fdabc6a31c98a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jan 28 15:33:53 2017 -0800
+
+    altos: Eliminate printf format warning with long vs int
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d96224c2fdc535d08de23aec30d62d4ada9fb8d3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jan 22 15:29:13 2017 -0800
+
+    altos/chaoskey: use both halves of the CRC
+    
+    When pulling 16 bits from the 32-bit crc, instead of just using the
+    low bits, xor the two halves together. This appears to even out the
+    number of zero and one bits.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bc076747f6cc00508aef909a3a5bd3edf8c9bd66
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Feb 18 12:14:59 2017 -0800
+
+    altos/lisp: Start adding scheme symbols
+    
+    Migrating to something more like scheme
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9c85c9d60334edc2af65a47124873e94e0ff1e9c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jan 10 14:47:03 2017 -0800
+
+    altos/lisp: Add casts to keep the latest GCC from whinging
+    
+    Something about alignment issues.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 399ba0a62422f71ff9669ba03b6a058bb2981c27
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jan 10 14:45:59 2017 -0800
+
+    altos/lisp: Tell compiler that the two lisp memory pools are aligned
+    
+    Otherwise, it will generate unaligned accesses to things fetched from
+    them. Sigh.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 30d6b241447cb922b9316e86817f6e31eb973eed
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 20 01:41:59 2016 -0800
+
+    altos/lisp: Clean up hanoi.lisp demo a bit
+    
+    No serious changes.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 329f76d5e2732ab1c1b10223842d7816275c7e8b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 23:37:44 2016 -0800
+
+    altos/lisp: Move stack recursion check after null check
+    
+    Don't crash when printing null stack this way.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1999b2c915bd5b7df70cffa7777e411d3032d2d5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 22:57:22 2016 -0800
+
+    altos/lisp: Include memory stats for test program
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 129e07ccc9b8a33491a905a91ca6c5b0509aba9c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 22:53:36 2016 -0800
+
+    altos/lisp: Cleanup some DBG defines
+    
+    Get rid of the remaining duplicate defines.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2c80fea1936ff956df127b43e65139afec3929a0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 22:52:53 2016 -0800
+
+    altos/lisp: Share binary search for memory chunk between mark and move
+    
+    Save some text space.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1b1bc92e6781c563e3d3b117b9cda2dddccc44de
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 22:52:10 2016 -0800
+
+    altos/lisp: Add builtin 'collect'
+    
+    Collect memory, return amount free.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c3a4d7721f0f5d082336b8cc9c9d765ad2f7d17e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 22:41:46 2016 -0800
+
+    altos/lisp: Sort frames by atom
+    
+    Fortunately, the collector always retains the relative order between
+    addresses, so we can sort based on the atom address itself. This
+    reduces the time spent looking for names in larger (e.g. global)
+    frames.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8f833f31f625526a5f1e9a1bd561733b5bb2bcaa
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 21:17:54 2016 -0800
+
+    altos/lisp: Build new ao_lisp_stack.c into test and lambdakey
+    
+    Helpful to include the new source file.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 35424031747b41b1125e715a975f1679b89fc27a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 21:16:11 2016 -0800
+
+    altos/lisp: bounds check in move_map plus binary search
+    
+    This makes move_map faster by skipping all addresses which aren't
+    changing.
+    
+    Also changed the interface from address to offset to avoid computing
+    the offset multiple times.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 85db6d68a273859482e036b60fec7e2b84e9c262
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 21:15:33 2016 -0800
+
+    altos/lisp: Empty lambda body is not an error
+    
+    It's not very exciting, but it's still legal
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ecef616599d5ec4fd5d42e67d0dc779a0630079b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 21:14:47 2016 -0800
+
+    altos/lisp: Use poly stashes for stacks
+    
+    Saves some memory.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4c812b8c903bd7e689572f8800ecc092af9cfe18
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 21:12:50 2016 -0800
+
+    altos/lisp: Make DBG settings global
+    
+    This avoids having different values in different files, which wasn't useful.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e600fc409c577eec02af612a36431c477a9c875e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 18 19:04:05 2016 -0800
+
+    altos/lisp: Add continuations
+    
+    This provides call/cc and makes 'stacks' visible to the application.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2cc8ca2b781be0a6e7ce14405eb4611bc00a3a3e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 18:45:31 2016 -0800
+
+    altos/lisp: Take advantage of implicit progns in hanoi demo
+    
+    Remove extra progn wrappers now that cond, lambda and while all
+    support implicit ones.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 11c79167cdd56015bbd1645db2d4394dcb4f0fbb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:52:30 2016 -0800
+
+    altos/lisp: have 'while' return the last body value
+    
+    Instead of always returning 'nil', let while return the last body
+    value.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9126ae10b3c5acf0055caa31b1f08215675af784
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:51:34 2016 -0800
+
+    altos/lisp: Take advantage of implicit progn in ROM code
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eaa528e4e62ba1d9765888760d387303487b2e01
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:08:15 2016 -0800
+
+    altos/lisp: Make lambda, cond and while all have implicit progns
+    
+    This lets all of these execute more than one sexpr, returning the
+    value of the last.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ffaf73407bcdf6bc4120c90212de4a2f52cf7991
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:07:42 2016 -0800
+
+    altos/lisp: Compile ao_lisp_make_const -no-pie
+    
+    Makes debugging easier
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 51bdee662fdfad1937c576daadd2e5eacac17905
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:06:55 2016 -0800
+
+    altos/lisp: Fix uninitialized values in ao_lisp_make_const
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 84732aebd10c293101727ba567bfc733dc30efca
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:06:05 2016 -0800
+
+    altos/lisp: Dump globals on error
+    
+    Useful for debugging
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 05ac336ea954c0f5eefabdefb0c8c5747be3fd32
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:05:29 2016 -0800
+
+    altos/lisp: Fix error atom name in ao_lisp_length
+    
+    Cut&paste error.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2ce7ab37df07b3c1ea1ca9befc06477e3b6cdeac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 16:04:38 2016 -0800
+
+    altos/lisp: Remove some stale frame debugging checks
+    
+    No-one sets frame->_num to 0xff to hit these
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d37945f1404043e6bd287ce7ad7a57bc3289609b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 16 14:59:08 2016 -0800
+
+    altos/lisp: Clean up hanoi.lisp comments.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bcf5eb5825b1217d74f117b02d09b4ce4b007beb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 16 14:12:59 2016 -0800
+
+    altos/lisp: Eliminate compiler warning about array bounds at -O3
+    
+    Using ao_lisp_pool - 4 caused the compiler to whinge about computing
+    an address outside the bounds of the array. Sigh. Restructure the code
+    to do the adjustment-by-4 in the integer computations instead of the
+    pointer ones.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a5ef084659205700aab33e81d20fb89833c03249
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 16 14:00:38 2016 -0800
+
+    altos/lisp: binary search for chunk in collect
+    
+    Speeds up collect a bit
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f19cb10cd12f86b12d0599bab5c2ee351d814ae
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 16 13:59:54 2016 -0800
+
+    altos/test: Disable position independent executables
+    
+    This makes debugging programs so much harder
+
+commit a7fcf80e22e70516d0b2da314fb17ced20a3f775
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 16 13:47:49 2016 -0800
+
+    altos/lisp: Allow empty defun bodies
+    
+    This allows for (defun foo())
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit daa06c8dedc6dc1cf21936ee2769d9d25f0567bd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 16 13:19:20 2016 -0800
+
+    altos/lisp: Optimize chunk searching in collect
+    
+    Note range of existing chunks to exclude objects outside.
+    Only look at chunks which have been set to reduce loop cost.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c8f9db184cc929ebde845730a6d4b7864e423a84
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 16 12:34:14 2016 -0800
+
+    altos/lisp: Add incremental collection
+    
+    Realizing that long-lived objects will eventually float to the bottom
+    of the heap, I added a simple hack to the collector that 'remembers'
+    the top of the heap the last time a full collect was run and then runs
+    incremental collects looking to shift only objects above that
+    boundary. That doesn't perfectly capture the bounds of transient
+    objects, but does manage to reduce the amount of time spent not moving
+    persistent objects each time through the collector.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8406ddf8f0bd5453d6213973daed35991f80972a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 20:37:59 2016 -0800
+
+    altos/lisp: Make hanoi example output a bit prettier
+    
+    Make the towers symmetrical instead of lopsided. Much nicer looking.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 472ecec64213e6c37b588d69ca2e8efd5e9abe36
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 20:25:03 2016 -0800
+
+    altos/lisp: remove nth from hanoi.lisp
+    
+    It's now in ROM.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5161f6d78647591cc7ab8774a04edbc68a09f689
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 20:24:33 2016 -0800
+
+    altos/lambdakey: Strip out unused code
+    
+    Make space for more lisp bits!
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ac0f7768659e288338bf452b4248ae3572ea2f7d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 20:22:54 2016 -0800
+
+    altos/lisp: Take advantage of multi-arg macros. Add more ROM funcs
+    
+    Added nth, or and and.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1a00bf4ac12a6505d4b23d94e99b4b46bf679020
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 20:21:47 2016 -0800
+
+    altos/lisp: Allow macro/nlambda/lexpr to have multiple args
+    
+    Entries from the params are bound to the formals with whatever
+    remaining formals there are bound to the last argument as a list.
+    This makes writing functions a bit easier.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5c1fa73f159de9d9839e8619494c26931521d2d4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 20:20:14 2016 -0800
+
+    altos/lisp: Do better checking for un-evaluated macros in ROM
+    
+    Need to look at immediate lambdas as well, and also deal with
+    recursive functions by checking for recursion at each atom
+    dereference.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 881161fe1c5fb0e2b1220c30572eb2c45bedbafe
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 20:18:59 2016 -0800
+
+    altos/lisp: re-use small frames
+    
+    This saves a pile more use of the allocator by noting when frames have
+    not been referenced from another frame and freeing them when they go
+    out of scope. Frames with references are left to the allocator to deal
+    with.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 994adc7a47cbf3cbf6041eca7430273f8018de08
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 10:32:36 2016 -0800
+
+    altos/lisp: remove duplicate 'length' lambda from hanoi example
+    
+    This function is now a builtin.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 41175ff82bc0e35c99c60b49aa62944a12917157
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 10:18:12 2016 -0800
+
+    altos/lisp: Get lambdakey and nucleo-32 building again
+    
+    Remove exti from the build list to make things fit.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 974717eb9dad105c9897ee24f953d98d57eaec77
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 15 09:55:22 2016 -0800
+
+    altos/lisp: Evaluate macros once, then smash them into place
+    
+    This assumes that macros are all pure functions, which should be true
+    for syntactic macros.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b3b5bd2c14cfcde6c551a87ee6da08a53f1e4bc6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 14 23:04:05 2016 -0800
+
+    altos/lisp: Add license to hanoi demo
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 13a4d451b903d08e52005bcf531efa8de351bf2b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 14 21:27:41 2016 -0800
+
+    altos/lisp: Improve hanoi demo
+    
+    Repaint in place, without first clearing. This makes the updates a lot
+    clealyer looking.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 74ff0c6fd6c41cdaa054dcdb3d05c7d333bc24ff
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 14 21:27:03 2016 -0800
+
+    altos/lisp: Show number of collect calls in ao_lisp_test
+    
+    This helps tune the allocator
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5557f6b87a9b8bc9716de8191f2062a772a6ae6c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 14 21:25:38 2016 -0800
+
+    altos/lisp: Cache freed cons and stack items
+    
+    Track freed cons cells and stack items from the eval process where
+    possible so that they can be re-used without needing to collect.
+    
+    This dramatically reduces the number of collect calls.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ce549b2c11e6b2571590021e1c0503d8a6e7a702
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 14 19:55:36 2016 -0800
+
+    altos/lisp: Simplify GC a bit by only marking the head of each object
+    
+    We don't need to mark the whole object now as we're getting
+    information about where objects are by walking the tree each time
+    around the loop; ao_lisp_busy is only useful for terminating the walk
+    now.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ddb4b8d90478ae324aa207a7541352c1ac9451ee
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 14 18:45:12 2016 -0800
+
+    altos/lisp: Change GC to do moves in batches of 32
+    
+    This should make it quite a bit faster than doing one at a time.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit affcf6ffc08313151541993ee543bfe390165e81
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 23:38:03 2016 -0800
+
+    altos/stmf0: Add a comment about the requirements for using ao_flash_stm
+    
+    Need HSI clock and the flashing functions loaded in ram.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 30db58ade19ec69272a8c39c2f13d7919ca491a9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 23:36:22 2016 -0800
+
+    altos/lambdakey: Get save/restore working
+    
+    Need the HSI clock running for the flash hardware to work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 33aeffc123af1f9063969acf585f1caac885ced4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 23:34:54 2016 -0800
+
+    altos/lisp: Append a CRC to the saved image to validate on restore
+    
+    The CRC is actually of the ROM bits, so we can tell if the restored
+    image relates to the currently running code.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8f2d60b4c029bffaa559bd1f31f5b15230dfa674
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 21:18:50 2016 -0800
+
+    altos/lisp: Add save/restore to ao_lisp_test
+    
+    Allow testing of the save/restore code under Linux.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dba374516ed396633659dec571b6a44b03da8ad1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 21:16:09 2016 -0800
+
+    altos/lisp: Add save/restore infrastructure. Needs OS support to work.
+    
+    This sticks a few globals past the end of the heap and then asks the
+    OS to save the heap. On restore, the heap is re-populated by the OS
+    and then various global variables reset.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 29c890b4599b3bbdbd09a5915ea68a63f4e0a9ac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 21:11:13 2016 -0800
+
+    altos/lisp: Make sure memmove only happens once per object. Other GC fixes
+    
+    The memmove may be overlapping, so make sure it happens only once by
+    just checking whether move_size has been set, rather than looking at
+    ao_lisp_moving; that doesn't get set when moving a noted cons as that
+    still needs to be walked at a later time.
+    
+    Fix up the various looping move functions to all use the same
+    pattern. Atom was busted.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d46ca67f93e9ecbc4d8c051c3fbdead85490b690
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 21:07:09 2016 -0800
+
+    altos/lisp: Make ao_lisp_ref and ao_lisp_poly non-inline
+    
+    These functions are pretty large and end up consuming quite a bit of
+    space if inlined everywhere they are used.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 00827a0ffe30938c26be216369fd2d8f8946d2c4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 00:28:57 2016 -0800
+
+    altos/lisp: Share mark function for mark and move
+    
+    These two operations both wanted to walk the referenced objects;
+    sharing is caring.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7f7e2431f5d1f7c1782ed6e774ccfc70fb4c87cf
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 11 00:28:31 2016 -0800
+
+    altos/lisp: add length, pack, unpack and flush
+    
+    lots more builtins
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f5a36c15f894803f8804bbc3daf105eed53d5ff6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 10 23:31:10 2016 -0800
+
+    altos/lisp: Add towers of hanoi example
+    
+    Uses vt100 escape sequences to animate the display even.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7da6bfc195fad97e3afc576c609897c131fd4d8c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 10 23:29:21 2016 -0800
+
+    altos/lisp: Deal with memory compation in the middle of operations
+    
+    Handle memory compaction in places where we've got pointers into the
+    heap across an allocation operation. Either re-compute the values from
+    managed global references or add new roots across the allocation.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 137898e3431d887e75b09d8c1ce57297a1558e43
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 10 23:28:26 2016 -0800
+
+    altos/lisp: Improve lisp test program UI
+    
+    Add a prompt for stdin, read from other files on command line before
+    stdin.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92cdc0cf0e80c1ff3f31cce20fc2b9bda86e3638
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 10 23:25:56 2016 -0800
+
+    altos/lisp: Make read() return eof atom on end of file
+    
+    Also make it an exception to hit eof in the middle of an sexpr.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fb710f7f4f24f74ac3d45fcc423803384d986bb2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 10 23:24:11 2016 -0800
+
+    altos/lisp: use regular read-eval-print loop for make const
+    
+    No need to open code this sequence of operations.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c7d7cdc2318a97534c4c1f9c6fd2b51644be729d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 10 11:30:55 2016 -0800
+
+    altos/lisp: add progn, while, read and eval
+    
+    Progn as a builtin will help with tail-recursion.
+    while provides for loops until tail-recursion works :-)
+    read and eval are kinda useful.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 417161dbb36323b5a6572859dedad02ca92fc65c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 9 16:22:43 2016 -0800
+
+    altos/lisp: Clean up OS integration bits, add defun
+    
+    Provide an abstraction for the OS interface so that it
+    can build more cleanly on Linux and AltOS. Add defun macro.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0ee44c8e4bf5dabe6a97bf76b366c8b767c387f8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 9 11:13:58 2016 -0800
+
+    altos/lisp: macros appear to work now
+    
+    Needed an extra stack frame to stash the pre-macro state. This
+    simplified macro processing quite a bit; a macro now just evaluates
+    the function and then sends that result to be evaluated again.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 794718abc62f4610495fe2bd535a2b67bc46573c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 9 09:14:50 2016 -0800
+
+    altos/lisp: working on lexical scoping
+    
+    Not working yet
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cb4cdb115ad83ae0d75eb58e68f561d20279f027
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 6 21:47:31 2016 -0800
+
+    altos/lambdakey-v1.0: Tweak memory allocations
+    
+    With non-recursive GC, more memory is available for the heap
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6e5c1308ce33a864095eae02e7db18b0e043ab6e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 6 10:53:46 2016 -0800
+
+    altos/lisp: convert GC to non-recursive
+    
+    Use a boolean array to note cons cells which would otherwise recurse,
+    then loop until that array is empty.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d8cf97fe22acefab40d7bb321138e46d4483fef7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 5 17:53:15 2016 -0700
+
+    altos/lisp: more GC issues. add patom
+    
+    Use global ao_lisp_stack instead of local stack so that gc
+    moves of that item work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 286d07d83bd7ff361e5a904c151a75e5a9c8b071
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 5 15:12:05 2016 -0700
+
+    altos/lisp: make sure stack->formals_last gets moved during GC
+    
+    Failing this leads to broken formals chains
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3366efb139653939f053c1fe4aba352ba3b66c94
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Nov 5 14:51:58 2016 -0700
+
+    altos/lisp: Change GC move API
+    
+    Pass reference to move API so it can change the values in-place, then
+    let it return '1' when the underlying object has already been moved to
+    shorten GC times.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6fc1ee0f7adc6fcb3e850bcbaabc1db705314234
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 4 16:51:12 2016 -0700
+
+    altos/lisp: get builtin macros working again
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c9456362c8bad8cd9be717f591f2d0841f88eb50
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Nov 4 16:31:34 2016 -0700
+
+    altos/lisp: Start rewriting eval as state machine
+    
+    Ad-hoc code was incomprehensible and I couldn't make 'cond' work, so
+    I'm starting over.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c48bda3625fc507134da7b4af87a634e8eb3715b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 3 21:51:26 2016 -0700
+
+    altos: Add lambdakey
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77db0e8162cd01c2b42737b3d71b38cea942484f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 3 21:49:50 2016 -0700
+
+    altos: Add lambda support to lisp
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 11cb03b1d336ee90c422be27588f57be573a9546
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 2 22:56:01 2016 -0700
+
+    altos/lisp: Separate out values from atoms
+    
+    This enables changing values of atoms declared as constants, should
+    enable lets, and with some work, even lexical scoping.
+    
+    this required changing the constant computation to run
+    ao_lisp_collect() before dumping the block of constant data, and that
+    uncovered some minor memory manager bugs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9e1a787f8828fb7b750ad3310c89a89536ea5286
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 2 14:18:54 2016 -0700
+
+    altos/lisp: add set/setq and ' in reader
+    
+    Along with other small fixes
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8362393a621ea78a96e7f65f602f4bfc7bbd1158
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 2 14:18:31 2016 -0700
+
+    altos/stmf0: Add lisp to include directories
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit caba623cb013b73e1f0ca369edf98e0376bec41a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 2 14:14:23 2016 -0700
+
+    altos/kernel: Make ao_cmd_readline public. Return char from ao_cmd_lex.
+    
+    With these two changes, the readline function can be used by other
+    code.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d2408e72d1e0d3459918601712b09860ab17e200
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 1 21:14:45 2016 -0700
+
+    altos/lisp: Change lisp objects to use ao_poly everywhere. Add const
+    
+    This makes all lisp objects use 16-bit ints for references so we can
+    hold more stuff in small amounts of memory. Also adds a separate
+    constant pool of lisp objects for builtins, initial atoms and constant
+    lisp code.
+    
+    Now builds (and runs!) on the nucleo-32 boards.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e2f4d25cd6f6f3787d4ee99264732d5b2ce23d4c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 31 18:53:09 2016 -0700
+
+    altos: Add lisp reader
+
+commit 56d46ceaa1413415f25e47e81036426132f99924
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 31 16:43:44 2016 -0700
+
+    Add first lisp bits
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2cfcc622c94d87cdbee099f457b7d63cb2fcbc71
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Jan 25 12:21:29 2017 -0700
+
+    use elf, not ihx
+
+commit 4ae8eeb426ef60105ec8e53e289739e5a8ae5dae
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Jan 25 12:00:20 2017 -0700
+
+    stop using /usr/share for binaries in remaining turnon scripts
+
+commit f2c7bb5879ba22df05fd1e39f01ea692313306fd
+Author: Richard Hughes <richard@hughsie.com>
+Date:   Tue Jan 10 17:15:24 2017 +0000
+
+    altos/chaoskey: Add a metainfo for the ChaosKey
+    
+    This provides the information necessary to reflash chaoskey using
+    standard Linux device firmware tooling.
+
+commit 89ecc32b90565ace078c4a84d4406a4d1f86821a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 17 20:58:36 2016 -0800
+
+    altos/arm: Align data so that gcc 5.4 doesn't do byte-accesses. Add -Wcast-align
+    
+    Gcc 5.4.1 tracks alignment of data through assignments, so that a
+    uint32_t pointer which comes from byte-aligned uint8_t data:
+    
+    extern uint8_t foo[];
+    
+            uint32_t        *q = (void *) foo;
+    
+    Fetches and stores through this pointer are done bytewise. This is
+    slow (meh), but if q references a device register, things to bad very
+    quickly.
+    
+    This patch works around this bug in the compiler by adding
+    __attribute__((aligned(4))) tags to some variables, or changing them
+    from uint8_t to uint32_t. Places doing this will now be caught as I've
+    added -Wcast-align to the compiler flags. That required adding (void
+    *) casts, after the relevant code was checked to make sure the
+    compiler could tell that the addresses were aligned.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f650211f9e99e1d3d0ae13ae559dd1c082f71545
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 12 16:44:47 2016 -0800
+
+    altos/stm: Make ao_usb_set_address static. Saves a bunch of text space
+    
+    I'm sure this makes the function end up in-lined, which saves enough
+    text space to fit the flash loader in ROM again.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d46698a01ed4903d36635b34867bfc4bb8fbafc6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 17 22:17:20 2016 -0800
+
+    ao-bringup: Improve EasyMini turnon and test scripts
+    
+    Wait less time before trying the test script.
+    Have the test script wait for the device to appear. And then use
+    colors to help make the results clear.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5e24d637a8af09bf64beb7fcf7be4c13eee76a43
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 9 19:42:42 2016 -0700
+
+    altos/test: Fix tests
+    
+    A couple of fixups for ao_flight_test to dump pyro info only when
+    running in debug mode, and to change the aprs testing
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e3d8ad6de7d2dfabe45a285b27f465ba68844f05
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 30 19:08:14 2016 -0700
+
+    altos/nucleo-32: Add basic support for STM32F042 Nucleo-32 board
+    
+    This hooks up the LED, USB and the USART.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 148f6e0a107d9e88509958700351794f2f971312
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 30 19:06:20 2016 -0700
+
+    altos/stmf0: Add USART support
+    
+    The STM32F0 usart can be operated much like the STM32L usart, but the
+    registers are all moved around.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 26f2727eac0cca8930dde9d757bc094f73801859
 Author: Bdale Garbee <bdale@gag.com>
-Date:   Mon Sep 5 20:59:11 2016 -0600
+Date:   Sun Oct 2 17:19:14 2016 -0600
+
+    augment TeleDongle turn on script to support serial number on command line
+
+commit 66d4b5ea4031193e3c79ebdabeb381aae46fe93b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 22 03:23:34 2016 +0300
+
+    Update pdclib to version using arm-specific 'ar' program
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2c1ab416728c942ddf176f881f025840ada6bf93
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Sep 5 22:25:07 2016 -0600
 
-    Merge branch 'master' into branch-1.6
+    Fix release note html to remove xml bits
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 4fdf8ca9ca1cd5a84b03bd7a03c5806af64b413d
 Author: Keith Packard <keithp@keithp.com>
@@ -485,13 +2618,6 @@ Date:   Tue Jul 5 18:03:49 2016 +0200
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 148b013dd29c26920ddfb53449ed4d8cc5a4b5ee
-Merge: ea1ff22 cd97128
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Tue Jul 5 10:23:18 2016 +0200
-
-    Merge branch 'master' into branch-1.6
-
 commit cd97128e30c47edfcc71f7d872cbdad14867934c
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Jul 5 10:21:29 2016 +0200
@@ -504,19 +2630,6 @@ Date:   Tue Jul 5 00:48:07 2016 +0200
 
     updates made during 1.6.5 release process
 
-commit ea1ff225f1f450ee3fc377807d1bb7b982bf792d
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Mon Jul 4 23:47:56 2016 +0200
-
-    updating ChangeLog for 1.6.5 release
-
-commit 2e26d1ab42163988dc26b06b016c3b05efe17659
-Merge: 639e461 65ed2f5
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Mon Jul 4 23:47:24 2016 +0200
-
-    Merge branch 'master' into branch-1.6
-
 commit 65ed2f588ca596fe9aa559bebd590a2a11b9859b
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Jul 3 12:00:10 2016 +0200
@@ -842,19 +2955,6 @@ Date:   Fri Jun 17 10:18:20 2016 -0700
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 639e461ded29a48c155afea12171cbfc191ccfd7
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Fri Jun 17 10:01:17 2016 -0600
-
-    releasing 1.6.4
-
-commit 31cf047113ec72a78f4b500223a2c6be23bc86fd
-Merge: 2f0c977 afe74c0
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Fri Jun 17 10:00:10 2016 -0600
-
-    Merge branch 'master' into branch-1.6
-
 commit afe74c067a31ce420d0d4cdac2069c1d258a5114
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Jun 17 08:58:06 2016 -0700
@@ -1495,7 +3595,7 @@ Date:   Mon May 9 17:56:28 2016 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit f078235803a80403014b3e54039fd2d0e0704367
-Merge: 04759dd c457c82
+Merge: 04759ddd c457c827
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon May 9 15:52:38 2016 -0600
 
@@ -1527,19 +3627,6 @@ Date:   Mon May 9 11:33:48 2016 -0700
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 2f0c977c747824d0798550ac64eceb1d66c50efd
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Fri May 6 18:12:20 2016 -0600
-
-    releasing 1.6.3
-
-commit 15ae97fbdb4e75a74ea2e716194661d19dec46ff
-Merge: ac7be4a 1216c0c
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Fri May 6 18:11:01 2016 -0600
-
-    Merge branch 'master' into branch-1.6
-
 commit 1216c0ccece4ca1492967a341c5d01e9e5068ed8
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri May 6 17:10:14 2016 -0700
@@ -1548,15 +3635,8 @@ Date:   Fri May 6 17:10:14 2016 -0700
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit ac7be4a40df88ee3a0992e041635e4ac4cf5ac48
-Merge: b53c78e ce4c8a8
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Fri May 6 17:59:39 2016 -0600
-
-    Merge branch 'master' into branch-1.6
-
 commit ce4c8a8ad57515e851207b0a82f3af791bb30d3e
-Merge: aa9630c 320e312
+Merge: aa9630c3 320e312d
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Fri May 6 17:49:30 2016 -0600
 
@@ -2798,51 +4878,18 @@ Date:   Sun Jan 10 21:39:38 2016 -0800
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit b53c78e75879d647935a30acb88fdd69467617a7
-Merge: a2ea621 64adfbb
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Sun Jan 10 19:15:16 2016 -0700
-
-    Merge branch 'master' into branch-1.6
-
 commit 64adfbbb80c90dfe244179d81beaef8a84ed8bd6
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Jul 16 14:47:10 2015 -0600
 
     process updates from 1.6.1 release
 
-commit a2ea621eac3263348aff50885c79296f8ece26ed
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Sun Jan 10 19:08:12 2016 -0700
-
-    update Changelog from git log
-
-commit 1681776abc0873bcbbbc5b2b17e15d54a1031f51
-Merge: 8830926 aebdcaf
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Sun Jan 10 19:07:49 2016 -0700
-
-    Merge branch 'master' into branch-1.6
-
 commit aebdcaf37eafbc13cce695fe65a455e49c6108c3
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Jan 10 19:06:19 2016 -0700
 
     one more time, with feeling .. this time, I've updated pdclib
 
-commit 88309264656220bae6ee941211f7aa1b1dc19944
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Sun Jan 10 19:06:19 2016 -0700
-
-    one more time, with feeling .. this time, I've updated pdclib
-
-commit 70e9064ca962dfd345f8a342afa130f969606553
-Merge: 489d22f 73ce3f7
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Sun Jan 10 19:04:49 2016 -0700
-
-    Merge branch 'master' into branch-1.6
-
 commit 73ce3f73526edfabccd3b98e6e67de6d82a84b63
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Jan 10 18:58:31 2016 -0700
@@ -2850,7 +4897,7 @@ Date:   Sun Jan 10 18:58:31 2016 -0700
     submodule madness
 
 commit cbec66452ecd01bbd5aebf6f98443d5e0540f5d2
-Merge: 4043e07 81b8f4d
+Merge: 4043e070 81b8f4da
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Jan 10 18:29:07 2016 -0700
 
@@ -2903,7 +4950,7 @@ Date:   Sun Jan 10 17:45:45 2016 -0700
     modify release procedure to reflect Keith setting version in confgure.ac
 
 commit 2f35e0ba52f538ea1061bfff5bbd772b8a241386
-Merge: 86ccbac 3fdaf74
+Merge: 86ccbac1 3fdaf745
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Jan 10 17:44:03 2016 -0700
 
@@ -3475,7 +5522,7 @@ Date:   Sat Sep 12 19:20:49 2015 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 7064bc685aebeef07711e525dea4d5fbe33d235b
-Merge: ea1d241 dda3f45
+Merge: ea1d2415 dda3f459
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Sep 29 00:46:42 2015 -0600
 
@@ -3585,13 +5632,6 @@ Date:   Thu Aug 20 10:50:30 2015 -0700
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 489d22f448d9927533e90da4d16c5a332a234a8d
-Merge: 570daac eaab49a
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Sun Aug 16 17:53:40 2015 +0200
-
-    Merge branch 'master' into branch-1.6
-
 commit eaab49ab1859ebe236a201f93b5352e67aa7ed2b
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Aug 16 17:43:32 2015 +0200
@@ -3616,21 +5656,8 @@ Date:   Tue Jul 28 01:34:25 2015 -0600
 
     move turnon_teledongle to new cal-freq code
 
-commit 570daace9caf7647a09c53d5c75593cc4c98b93b
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Thu Jul 16 13:36:13 2015 -0600
-
-    changelog for 1.6.1 release
-
-commit 6e9bb9178356620bd47d9f2e31abf42b7f1a8f11
-Merge: e2cefd8 87c8bb3
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Thu Jul 16 13:31:42 2015 -0600
-
-    Merge branch 'master' into branch-1.6
-
 commit 87c8bb3956897830da1f7aaca2990a9571767b73
-Merge: 643c2fb d6445b3
+Merge: 643c2fb0 d6445b37
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Jul 16 07:54:35 2015 -0600
 
@@ -3647,7 +5674,7 @@ Date:   Wed Jul 15 18:31:05 2015 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 643c2fb03833d658320f476ef731bbb06fe3cc31
-Merge: e41786f 271f56a
+Merge: e41786fb 271f56a4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Jul 15 16:43:50 2015 -0600
 
@@ -4008,19 +6035,19 @@ Date:   Tue Jun 23 21:39:09 2015 -0700
     
     Pad
     
-       Reports igniter and GPS status changes
+            Reports igniter and GPS status changes
     
     Flight
     
-       Report flight state changes and max height after apogee
-       Report current speed, height and bearing/elevation/range once
-       every 10 seconds while the rocket is in motion.
+            Report flight state changes and max height after apogee
+            Report current speed, height and bearing/elevation/range once
+            every 10 seconds while the rocket is in motion.
     
     Recovery
     
-       Report distance and bearing when the location of either the
-       tracker or the receiver changes by more than 10m, but not more
-       than once every 10 seconds.
+            Report distance and bearing when the location of either the
+            tracker or the receiver changes by more than 10m, but not more
+            than once every 10 seconds.
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
@@ -4367,7 +6394,7 @@ Date:   Tue Jun 16 23:38:07 2015 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit c46c2c5767c6e909fa58587e6c864a4fbaa9fa20
-Merge: 39f4361 6cb7d76
+Merge: 39f43616 6cb7d76c
 Author: Robert Garbee <robert@gag.com>
 Date:   Sat Jun 13 17:40:59 2015 -0600
 
@@ -5321,7 +7348,7 @@ Date:   Sat Feb 28 15:07:16 2015 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 4af4e36cda96d053458eeb040e35886890917385
-Merge: 91b1a80 106b16b
+Merge: 91b1a806 106b16b4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Feb 22 14:55:40 2015 -0700
 
@@ -5525,12 +7552,6 @@ Date:   Mon Feb 9 08:35:24 2015 -0600
 
     Minor typo in man page
 
-commit e2cefd8593d269ce603aaf33f4a53a5c2dcb3350
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Sat Feb 7 22:36:22 2015 -0700
-
-    update ChangeLog for release
-
 commit 26f61380ce6b4df80fa0b5a8a242cef79d5ae339
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Feb 7 22:23:38 2015 -0700
@@ -5914,7 +7935,7 @@ Date:   Fri Jan 16 22:09:26 2015 +1300
     Signed-off-by: Keith Packard <keithp@keithp.com>
     
     Conflicts:
-       src/lpc/ao_usb_lpc.c
+            src/lpc/ao_usb_lpc.c
 
 commit 0671b3c8c24c9f33be77a10315c4669f33c516d7
 Author: Keith Packard <keithp@keithp.com>
@@ -6379,7 +8400,7 @@ Date:   Sat Dec 6 15:08:29 2014 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 7339d2379713b5b7e4c4fe6bad89ed93f9d39e82
-Merge: d1f9121 b6462ca
+Merge: d1f91215 b6462ca3
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Dec 6 15:39:53 2014 -0700
 
@@ -6907,11 +8928,11 @@ Date:   Sat Oct 4 00:11:13 2014 -0700
     This change also renames all of the imu values to make them easier to
     understand:
     
-       accel   gyro    axis
+            accel   gyro    axis
     
-       along   roll    length of the board
-       across  pitch   across the board
-       through yaw     through the board.
+            along   roll    length of the board
+            across  pitch   across the board
+            through yaw     through the board.
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
@@ -7227,7 +9248,7 @@ Date:   Wed Sep 10 00:26:10 2014 -0600
     another build dep
 
 commit 615b69b19557a9683eeb0475b30a053a35ca51ac
-Merge: a72b768 0365493
+Merge: a72b7683 03654934
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Sep 10 01:30:37 2014 -0600
 
@@ -7337,7 +9358,7 @@ Date:   Sat Sep 6 22:56:25 2014 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit f0d2d34f84980ab45ecedae17546f4d71e020c5e
-Merge: 8c212cd 6c812f1
+Merge: 8c212cd5 6c812f10
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Sep 6 23:42:47 2014 -0600
 
@@ -7404,14 +9425,14 @@ Date:   Sat Sep 6 20:39:37 2014 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 8c212cd5bfa03f71a31d84bd0051314e77d88461
-Merge: e9714e3 dd26ec2
+Merge: e9714e34 dd26ec2e
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Sep 6 13:41:36 2014 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
     
     Conflicts:
-       ao-bringup/turnon_telemega
+            ao-bringup/turnon_telemega
 
 commit e9714e34091abe657aa1b30aeda9466331aa39c1
 Author: Bdale Garbee <bdale@gag.com>
@@ -7851,7 +9872,7 @@ Date:   Thu Aug 14 18:16:14 2014 -0600
     change easymega from v0.1 to v1.0, tweak to build on master, add to Makefile
 
 commit 4828be0ca5252ac9cd6061209385dcd6c4c57965
-Merge: 17e894d 165b7dc
+Merge: 17e894d1 165b7dcf
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Aug 14 17:08:36 2014 -0600
 
@@ -8534,7 +10555,7 @@ Date:   Tue Jun 24 21:22:26 2014 -0600
     need the api key in Bdale's root too
 
 commit bd440afc2a6e37b74fffcf1b977e149485095316
-Merge: 5d4f912 a0ccab8
+Merge: 5d4f912b a0ccab8e
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Jun 24 21:17:53 2014 -0600
 
@@ -8916,7 +10937,7 @@ Date:   Sun Jun 15 17:40:27 2014 -0600
     tweaks
 
 commit a6c61fb993d3fd15183f8755d9058f05c606c9c0
-Merge: 0634119 4384899
+Merge: 0634119d 43848991
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Jun 15 16:31:01 2014 -0700
 
@@ -11154,7 +13175,7 @@ Date:   Tue May 13 17:30:47 2014 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 8124af8c27b2b9e446aa3a4f1da83d4db7c1ea87
-Merge: 6dd7eae 3bcf4bd
+Merge: 6dd7eae5 3bcf4bdd
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon May 12 23:21:55 2014 -0700
 
@@ -11894,7 +13915,7 @@ Date:   Sun Feb 23 17:42:08 2014 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 104b8bfc9b37fda175f2cb2a1e33601fbf6f48f6
-Merge: 403b95e 1edf7ef
+Merge: 403b95ee 1edf7ef8
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Feb 20 13:23:52 2014 -0700
 
@@ -12035,7 +14056,7 @@ Date:   Sun Feb 16 14:57:38 2014 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 95f5a6ef52947088993d395874cf6aa502fd2503
-Merge: 135b6d4 de2a619
+Merge: 135b6d40 de2a6199
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Feb 16 15:53:35 2014 -0700
 
@@ -12547,7 +14568,7 @@ Date:   Tue Jan 21 21:34:58 2014 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 13cf4000bd53ac4af66231d56e24c9eb11178a5f
-Merge: 7a8551f 99fedbf
+Merge: 7a8551fe 99fedbf0
 Author: Keith Packard <keithp@keithp.com>
 Date:   Tue Jan 21 20:59:06 2014 -0800
 
@@ -13049,7 +15070,7 @@ Date:   Thu Dec 19 03:22:21 2013 -0700
     updated notes from 1.3 release
 
 commit 27528961457865acc3a38b822268df6d7cb86cfd
-Merge: 4006eff a31629d
+Merge: 4006effc a31629df
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Dec 19 02:00:10 2013 -0700
 
@@ -13152,7 +15173,7 @@ Date:   Wed Dec 18 21:02:15 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 39cb8c2896317b7538353be979ac99baffc14489
-Merge: 2a6016c ee42796
+Merge: 2a6016cf ee427961
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Dec 18 21:53:52 2013 -0700
 
@@ -13204,7 +15225,7 @@ Date:   Wed Dec 18 18:30:54 2013 -0700
     update release docs to include option for submodules
 
 commit d9982c257463f23be940eea66bd4dc3aadff0043
-Merge: 1b97ed2 b63fc05
+Merge: 1b97ed2b b63fc054
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Dec 18 18:25:35 2013 -0700
 
@@ -13331,7 +15352,7 @@ Date:   Wed Dec 18 11:25:05 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 6df58bb0115a8da13d35ab38861f6231bea7f2a7
-Merge: 4383baf 02195f2
+Merge: 4383bafc 02195f29
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Dec 18 12:19:31 2013 -0700
 
@@ -13538,14 +15559,14 @@ Date:   Tue Dec 17 14:53:59 2013 -0700
     further documentation tweaks
 
 commit 90c88bab305c43eb62f964fd3ff350b8b0b5320d
-Merge: d5d6d10 dffbdd9
+Merge: d5d6d10c dffbdd93
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Dec 17 14:09:30 2013 -0700
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
     
     Conflicts:
-       doc/altusmetrum.xsl
+            doc/altusmetrum.xsl
 
 commit d5d6d10ceb724081c7cf89a3885d7e6c3da14604
 Author: Bdale Garbee <bdale@gag.com>
@@ -14831,7 +16852,7 @@ Date:   Tue Oct 8 09:39:29 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 488a527267decece48e6682e0e0c7fc29cbed329
-Merge: 6a1e398 f6661cc
+Merge: 6a1e398e f6661cc0
 Author: Keith Packard <keithp@keithp.com>
 Date:   Tue Oct 8 09:26:41 2013 -0700
 
@@ -14840,7 +16861,7 @@ Date:   Tue Oct 8 09:26:41 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
     
     Conflicts:
-       configure.ac
+            configure.ac
 
 commit 6a1e398e590121458176758858bb4210f3eb5a55
 Author: Keith Packard <keithp@keithp.com>
@@ -15223,7 +17244,7 @@ Date:   Thu Sep 5 03:11:42 2013 +1200
     Signed-off-by: Mike Beattie <mike@ethernal.org>
     
     Conflicts:
-       altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
+            altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
 
 commit ee14ad16c242e8bd7a9d33ebf569211d1490b8e1
 Author: Mike Beattie <mike@ethernal.org>
@@ -15234,9 +17255,9 @@ Date:   Tue Sep 3 15:10:23 2013 +1200
     Signed-off-by: Mike Beattie <mike@ethernal.org>
     
     Conflicts:
-       altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
-       altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
-       altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
+            altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
+            altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
+            altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
 
 commit 5b976a6651f4eb05d30afc08b9e1f27c7e52ae00
 Author: Keith Packard <keithp@keithp.com>
@@ -15397,7 +17418,7 @@ Date:   Sat Aug 31 23:10:56 2013 -0500
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 7ec1b97d278c7aec3199fb7270f0dcf9484c879f
-Merge: 017ed54 4188153
+Merge: 017ed54f 41881535
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Aug 31 08:22:09 2013 -0500
 
@@ -15466,7 +17487,7 @@ Date:   Tue Aug 27 21:28:07 2013 -0600
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit dcc51bb18985c24fa35bce0dd42ea3d847b960bf
-Merge: 7c82acc a73b025
+Merge: 7c82acc1 a73b0251
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Aug 28 22:52:58 2013 -0600
 
@@ -15475,8 +17496,8 @@ Date:   Wed Aug 28 22:52:58 2013 -0600
     Signed-off-by: Keith Packard <keithp@keithp.com>
     
     Conflicts:
-       src/core/ao_telemetry.c
-       src/core/ao_telemetry.h
+            src/core/ao_telemetry.c
+            src/core/ao_telemetry.h
     
     Added both Mini and Metrum telemetry defines
 
@@ -15853,7 +17874,7 @@ Date:   Sun Aug 25 22:22:55 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 203951f6e049ec7e95489849a2bfaa01aa19c0c9
-Merge: 4babe73 b363a62
+Merge: 4babe731 b363a628
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Aug 25 22:00:27 2013 -0700
 
@@ -16009,7 +18030,7 @@ Date:   Sat Aug 17 17:35:08 2013 +0200
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit f0e126251360f050b7121f167771c057bda8747e
-Merge: d95a2c5 4fe47ad
+Merge: d95a2c5d 4fe47adc
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Aug 17 17:33:31 2013 +0200
 
@@ -16026,7 +18047,7 @@ Date:   Sat Aug 17 17:30:52 2013 +0200
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 4ff54bb96f6c00c0c2c7dd32f81403bac331621a
-Merge: fa0859a 01f8df0
+Merge: fa0859a5 01f8df08
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Aug 17 16:03:26 2013 +0200
 
@@ -16044,7 +18065,7 @@ Date:   Sat Aug 17 16:01:44 2013 +0200
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 01f8df088759ee7e6bc3900a013e0ea4fafaf984
-Merge: e2ebe60 15063cb
+Merge: e2ebe60a 15063cbb
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Jul 30 00:15:06 2013 -0600
 
@@ -16514,7 +18535,7 @@ Date:   Tue May 21 11:30:44 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit fd5567882b732f8947b44b217552077c82a3d28e
-Merge: fd55c1f 57b4d82
+Merge: fd55c1fe 57b4d82d
 Author: Keith Packard <keithp@keithp.com>
 Date:   Tue May 21 11:16:54 2013 -0700
 
@@ -16558,7 +18579,7 @@ Date:   Sun May 19 23:07:54 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 27e9b93f3d35890a49575b2ead1983ce3c2fc213
-Merge: a4df257 d9cbef8
+Merge: a4df2575 d9cbef8c
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun May 19 20:40:42 2013 -0700
 
@@ -17392,7 +19413,7 @@ Date:   Fri May 10 19:21:18 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 106d212ff5920c39d95751ef6249dc141970412c
-Merge: ecb1285 09d5d6f
+Merge: ecb12857 09d5d6f5
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu May 9 21:06:52 2013 -0700
 
@@ -18247,7 +20268,7 @@ Date:   Thu May 2 23:14:02 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 7cce6c205e4595894e033ab8f0acc8064bf9f561
-Merge: 75f8229 5591509
+Merge: 75f8229d 55915098
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Apr 29 17:24:43 2013 -0600
 
@@ -18292,7 +20313,7 @@ Date:   Sat Apr 27 00:36:11 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit cef4e3ee95037050ae859fb2fdc0a57373764bd8
-Merge: fefc021 f3ee7de
+Merge: fefc0210 f3ee7deb
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Apr 25 22:22:50 2013 -0700
 
@@ -18465,7 +20486,7 @@ Date:   Sun Apr 21 14:52:56 2013 +1200
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 49caac78786014d443d9c05f47b5eb3070ec9bd3
-Merge: 5b7bbf1 cbf38c5
+Merge: 5b7bbf18 cbf38c55
 Author: Mike Beattie <mike@ethernal.org>
 Date:   Sun Apr 21 14:51:07 2013 +1200
 
@@ -18542,7 +20563,7 @@ Date:   Sat Apr 20 12:22:38 2013 -0600
     improve text in telebt turn-on script
 
 commit ff332e640b27c6be37dabef58ebac350ac2347b2
-Merge: b300060 87d6ed2
+Merge: b3000609 87d6ed24
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Apr 17 10:41:05 2013 -0700
 
@@ -18595,7 +20616,7 @@ Date:   Tue Apr 16 14:22:23 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit d5a557004c00d1ae25da04dc63c78b816562a236
-Merge: 6592a5b 5b04176
+Merge: 6592a5be 5b041769
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon Apr 15 23:26:33 2013 -0700
 
@@ -18610,7 +20631,7 @@ Date:   Mon Apr 15 23:25:55 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 6592a5be127a9c95d3b2e7d5aa6ffba71c6748b9
-Merge: c6f85cb eba3aa9
+Merge: c6f85cb1 eba3aa94
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon Apr 15 23:19:44 2013 -0700
 
@@ -18630,7 +20651,7 @@ Date:   Mon Apr 15 23:14:22 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit c6f85cb149dff8732104521cb62b355e8a0d7148
-Merge: 3cd8ff1 58dd4b8
+Merge: 3cd8ff18 58dd4b88
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Apr 14 20:02:10 2013 -0700
 
@@ -18681,7 +20702,7 @@ Date:   Sat Apr 13 11:39:14 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 2f7015afcca7c6042365d2124d3a5b7219e8e588
-Merge: 5077f3a 778daf0
+Merge: 5077f3ad 778daf0c
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Apr 13 10:51:04 2013 -0700
 
@@ -18884,7 +20905,7 @@ Date:   Mon Apr 8 17:42:18 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 6ba0df9b440b69bf5bc5f4e435b431adf303fee2
-Merge: 1d3ab47 28adf55
+Merge: 1d3ab47d 28adf554
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Apr 8 18:02:37 2013 -0600
 
@@ -19577,7 +21598,7 @@ Date:   Mon Mar 11 18:16:55 2013 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 90ee11542b111befa0e96e27292dc548e5c37396
-Merge: 97efce5 d7973de
+Merge: 97efce5f d7973de3
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Mar 10 11:43:06 2013 -0700
 
@@ -19622,7 +21643,7 @@ Date:   Sun Mar 10 20:40:13 2013 +1300
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 8adadf6bd2ba623642675e4beafac4ac98b1916d
-Merge: d029aca 0c0c6d6
+Merge: d029acad 0c0c6d60
 Author: Mike Beattie <mike@ethernal.org>
 Date:   Sun Mar 10 20:24:56 2013 +1300
 
@@ -19653,7 +21674,7 @@ Date:   Sun Mar 10 20:22:09 2013 +1300
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit d029acad6a992be9b7b4498e70605f8a1e1a4ef6
-Merge: eba7b2e 72c5b14
+Merge: eba7b2ef 72c5b142
 Author: Mike Beattie <mike@ethernal.org>
 Date:   Sun Mar 10 19:07:01 2013 +1300
 
@@ -19698,7 +21719,7 @@ Date:   Fri Mar 8 19:41:32 2013 +1300
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 84d35e4cbd7ea2f681c43496b9b9db84f9dd923f
-Merge: 760b1f0 e0d9128
+Merge: 760b1f02 e0d9128b
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Mar 7 13:00:44 2013 -0800
 
@@ -19848,7 +21869,7 @@ Date:   Thu Mar 7 18:54:45 2013 +1300
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 760b1f02c178c600226f39b5e66d8cbadbf4a29b
-Merge: afd2674 cbad587
+Merge: afd26742 cbad587b
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Mar 6 21:53:22 2013 -0800
 
@@ -19972,7 +21993,7 @@ Date:   Sun Feb 24 01:20:16 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 2120d362cefceba69e75996b6391d9558978c01d
-Merge: 5246acb a04c4f7
+Merge: 5246acb7 a04c4f7b
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Feb 24 00:20:54 2013 -0800
 
@@ -20155,7 +22176,7 @@ Date:   Sun Feb 10 11:58:36 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit bf88c5f829ea5d32043431945e862a9f6c96740a
-Merge: 3227029 d05a779
+Merge: 32270296 d05a7799
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Feb 10 01:21:52 2013 -0800
 
@@ -20493,7 +22514,7 @@ Date:   Wed Jan 16 22:05:32 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit a04c4f7b07e97d568f8f6f56dd363329817fb52c
-Merge: 0c2fa96 bd84dfd
+Merge: 0c2fa961 bd84dfd8
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Jan 16 15:22:46 2013 -0800
 
@@ -20545,8 +22566,8 @@ Date:   Wed Jan 16 15:01:12 2013 -0800
     The correct matrix is seen in this paper:
     
     On Reduced-Order Kalman Filters For GPS Position Filtering
-       J. Shima
-       6/2/2001
+            J. Shima
+            6/2/2001
     
     This references an older paper which is supposed to describe the
     derivation of the matrix:
@@ -20561,14 +22582,14 @@ Date:   Wed Jan 16 15:01:12 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 0c2fa9614ffe22901ba0fd089e1e02c362f9fbe0
-Merge: 456120d f2b59cf
+Merge: 456120d2 f2b59cf3
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Jan 16 10:40:28 2013 -0800
 
     Merge remote-tracking branch 'origin/telescience-v0.2' into telescience-v0.2
 
 commit 456120d201d72c89576a0c8d69b2fcba44169507
-Merge: f24c421 994ff76
+Merge: f24c4219 994ff76a
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Jan 16 10:39:40 2013 -0800
 
@@ -20660,7 +22681,7 @@ Date:   Sat Jan 12 20:11:38 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 670034eef48d63cdaec8d271fa93da984ffe2ea9
-Merge: 8c5ebaf d374d6b
+Merge: 8c5ebaf8 d374d6be
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Jan 12 10:57:22 2013 -0700
 
@@ -20765,7 +22786,7 @@ Date:   Thu Jan 10 21:26:20 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 1ed6b13e87c1cc2d6618b6ba3a293ea6e3b5752e
-Merge: acff2f4 d409417
+Merge: acff2f46 d409417f
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Jan 10 21:48:12 2013 -0800
 
@@ -20810,7 +22831,7 @@ Date:   Wed Jan 9 15:23:46 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 8c5ebaf88b459b09924753a8077393a7b0639133
-Merge: 59f355f d7d259c
+Merge: 59f355f5 d7d259c7
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Jan 8 22:12:17 2013 -0700
 
@@ -21147,7 +23168,7 @@ Date:   Tue Jan 1 15:30:11 2013 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 65b512c890a3ccf487655b79305ab1cfcf49259c
-Merge: 434e946 d7d259c
+Merge: 434e946a d7d259c7
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon Dec 31 14:24:59 2012 -0800
 
@@ -21217,14 +23238,14 @@ Date:   Fri Dec 28 23:05:31 2012 -0700
     Signed-off-by: Keith Packard <keithp@gag.com>
 
 commit f7a56152808c7838c1886884bb77de2705ab076c
-Merge: daf8776 b70ca5e
+Merge: daf8776f b70ca5ea
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Dec 28 21:50:13 2012 -0800
 
     Merge remote-tracking branch 'origin/master' into micropeak-logging
 
 commit 59f355f5288b42b2e47743d06e41e55819a55f64
-Merge: 099d2b0 b70ca5e
+Merge: 099d2b0e b70ca5ea
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Fri Dec 28 22:30:26 2012 -0700
 
@@ -21286,7 +23307,7 @@ Date:   Tue Dec 25 14:23:29 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 868ef0c9c4b208c02a87180b0eede329369bdc77
-Merge: 669cde8 57487e7
+Merge: 669cde8a 57487e78
 Author: Keith Packard <keithp@keithp.com>
 Date:   Tue Dec 25 14:20:42 2012 -0800
 
@@ -21380,7 +23401,7 @@ Date:   Sun Dec 16 16:08:33 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit dfff41c2bec16fe4c7b198a4720eb40d8e740ac4
-Merge: 22a58b0 00bc1a0
+Merge: 22a58b0f 00bc1a09
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Dec 16 16:06:41 2012 -0800
 
@@ -21468,7 +23489,7 @@ Date:   Sat Dec 15 14:47:22 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 6fa1ec0dbf2a4eda8d061c67b3779b83b88f29f0
-Merge: f140931 73422bf
+Merge: f1409311 73422bf7
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Dec 14 19:29:50 2012 -0800
 
@@ -21522,7 +23543,7 @@ Date:   Wed Dec 12 22:53:36 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 688a9458bb03a81e71554c14295d1baacbbbd530
-Merge: 816c6b5 c8866fb
+Merge: 816c6b5d c8866fba
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Dec 12 22:36:59 2012 -0800
 
@@ -21537,7 +23558,7 @@ Date:   Wed Dec 12 22:35:05 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 816c6b5d087694a9db9c34cc5ec7671a1487d9b9
-Merge: a4a8418 a4678cd
+Merge: a4a84182 a4678cd8
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Dec 12 11:10:14 2012 -0800
 
@@ -21577,7 +23598,7 @@ Date:   Tue Dec 11 23:43:30 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit a4a841828924ee37f5201d4ff0aec38459f2d802
-Merge: b26e837 d309fcf
+Merge: b26e837a d309fcff
 Author: Keith Packard <keithp@keithp.com>
 Date:   Tue Dec 11 14:42:43 2012 -0800
 
@@ -21595,7 +23616,7 @@ Date:   Tue Dec 11 14:41:53 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit b26e837a6f18641aae9372aab22168849ff10812
-Merge: 1489c7f c233ef6
+Merge: 1489c7f7 c233ef67
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Dec 9 18:33:31 2012 -0800
 
@@ -21662,7 +23683,7 @@ Date:   Fri Dec 7 17:35:15 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit bd05421991b596fe9cf73ee25c9046b0fb4e32f7
-Merge: 1f79706 1489c7f
+Merge: 1f797066 1489c7f7
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Dec 7 17:34:10 2012 -0800
 
@@ -21714,7 +23735,7 @@ Date:   Fri Dec 7 10:15:25 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 748e42ebf1dfb1efd5dec6ddd93f5c7aeedeb01d
-Merge: 75912f8 c10f9a4
+Merge: 75912f8a c10f9a43
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Dec 7 10:14:11 2012 -0800
 
@@ -21969,7 +23990,7 @@ Date:   Wed Dec 5 09:59:16 2012 -0800
     reporting. We're going to appropriate the code for use in Mega Metrum
     to (optionally) broadcast APRS packets.
     
-       http://ad7zj.net/kd7lmo/aprsbeacon_code.html
+            http://ad7zj.net/kd7lmo/aprsbeacon_code.html
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
     (
@@ -22166,7 +24187,7 @@ Date:   Thu Nov 29 20:36:51 2012 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit ceea0e75ac42acac4a20bf88f34bb93fd2768f4c
-Merge: 7738ddc 285fccf
+Merge: 7738ddc5 285fccfa
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Nov 20 12:37:38 2012 -0700
 
@@ -22442,7 +24463,7 @@ Date:   Mon Oct 29 11:43:02 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit a46c9398a5f02ff4b52b7a4309a51498560cadb5
-Merge: e57ab2a 56023cf
+Merge: e57ab2a7 56023cf5
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Oct 26 14:08:32 2012 -0700
 
@@ -22537,7 +24558,7 @@ Date:   Thu Oct 25 00:12:57 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 282f0451dd141db3304ab73e4020a849e59721eb
-Merge: 0680d62 78e1de4
+Merge: 0680d62d 78e1de48
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Oct 25 00:09:01 2012 -0700
 
@@ -22665,7 +24686,7 @@ Date:   Wed Oct 24 20:52:09 2012 +1300
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 055f3232decc07e064d596469b81cf9869411c2d
-Merge: 8ca58e2 9e60fa2
+Merge: 8ca58e20 9e60fa21
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Oct 23 09:38:36 2012 -0600
 
@@ -22693,7 +24714,7 @@ Date:   Tue Oct 23 19:22:52 2012 +1300
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 9e60fa214ad2c48fbe8f7e5c437681aa35d249fa
-Merge: 27c3157 4b41561
+Merge: 27c31572 4b41561a
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon Oct 22 22:39:31 2012 -0700
 
@@ -22925,7 +24946,7 @@ Date:   Sun Oct 21 13:01:03 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 7f664da148ae15d46d179d8ecede6fc0bc710ffb
-Merge: 3aba5eb 23b0c2f
+Merge: 3aba5eb5 23b0c2fe
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Oct 18 16:49:28 2012 -0700
 
@@ -22963,7 +24984,7 @@ Date:   Thu Oct 18 15:34:41 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 5a55501660ebab3b858a48483c5df1cfb4e858e4
-Merge: 0361235 440365b
+Merge: 0361235c 440365bd
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Oct 18 15:18:52 2012 -0700
 
@@ -23530,7 +25551,7 @@ Date:   Sat Oct 6 17:05:59 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 82fdc42d61340e6b76580ff12a9e1bea59eb8079
-Merge: 6b8881a 2cac8c5
+Merge: 6b8881a7 2cac8c57
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Oct 3 10:44:28 2012 -0700
 
@@ -23589,21 +25610,21 @@ Date:   Thu Sep 20 11:33:24 2012 +0200
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 2f2734bb418f5c3a89fa3f1bf1b98ce4cfe432e1
-Merge: e69a433 3fe5c2f
+Merge: e69a433f 3fe5c2f9
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Sep 20 11:30:19 2012 +0200
 
     Merge remote-tracking branch 'mjb/altosdroid'
 
 commit e69a433fd93b9f6bd2297d8045eb075fee29e73b
-Merge: 19243ec 6e0d672
+Merge: 19243ecc 6e0d672b
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Sep 20 11:30:11 2012 +0200
 
     Merge remote-tracking branch 'mjb/prefs_interface'
 
 commit 19243ecc9b5bbdcc069ae24acf1ca807322c84d8
-Merge: 90c1b6d 0ef8b71
+Merge: 90c1b6db 0ef8b714
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Sep 20 11:29:55 2012 +0200
 
@@ -23691,7 +25712,7 @@ Date:   Mon Sep 17 01:29:33 2012 +1200
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 52d3cad4f744140e1aa06fdfc0d49a0cf8734fd4
-Merge: 31f5a02 6e0d672
+Merge: 31f5a026 6e0d672b
 Author: Mike Beattie <mike@ethernal.org>
 Date:   Sun Sep 16 22:27:04 2012 +1200
 
@@ -23946,7 +25967,7 @@ Date:   Thu Sep 13 15:12:33 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 320d90c376dccfe1599505e3b485df8d46e34bb3
-Merge: 9a7d643 2e6c6a6
+Merge: 9a7d6431 2e6c6a6c
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Sep 13 15:36:37 2012 -0600
 
@@ -23963,7 +25984,7 @@ Date:   Thu Sep 13 00:35:27 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 9a7d6431777ce3377b788ddac6cb9fadd53c039c
-Merge: 2439f53 9728b20
+Merge: 2439f53e 9728b20a
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Sep 13 00:58:30 2012 -0600
 
@@ -24020,7 +26041,7 @@ Date:   Wed Sep 12 19:50:07 2012 -0600
     update Releasing for non-native versioning and builds on debian branch
 
 commit fe009534ce6846b6db96cac8f6c2d53ba8010d91
-Merge: 69d42b2 8ee29fe
+Merge: 69d42b26 8ee29fe4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Sep 12 19:49:51 2012 -0600
 
@@ -24108,7 +26129,7 @@ Date:   Tue Sep 11 23:36:26 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 69d42b26223b45df4167aa3baafba100ad71baab
-Merge: 3e9078c 3fa5fbd
+Merge: 3e9078cb 3fa5fbdf
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Sep 12 00:26:21 2012 -0600
 
@@ -24145,7 +26166,7 @@ Date:   Tue Sep 11 22:17:22 2012 -0600
     releasing 1.1
 
 commit 4563624638884b7b2f16cd4d396c00690e045999
-Merge: 11fbcf5 e5a55db
+Merge: 11fbcf5e e5a55dbf
 Author: Tom Marble <tmarble@info9.net>
 Date:   Tue Sep 11 22:50:18 2012 -0500
 
@@ -24203,7 +26224,7 @@ Date:   Tue Sep 11 12:44:24 2012 -0500
     Add appropriate Java build deps as given from autoconf
 
 commit 8e506274a35eccacd2d4523faa08d279a201753f
-Merge: 0bc3ed5 1fc97dd
+Merge: 0bc3ed53 1fc97dd9
 Author: Tom Marble <tmarble@info9.net>
 Date:   Tue Sep 11 11:39:22 2012 -0500
 
@@ -24216,7 +26237,7 @@ Date:   Tue Sep 11 11:37:14 2012 -0500
     Use explicit build deps for altosui (avoids * wildcarding)
 
 commit 1fc97dd9875a7639533a34438c4c7c999412eb3a
-Merge: 8397d2b 4420d4a
+Merge: 8397d2b0 4420d4a9
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Sep 11 10:35:04 2012 -0600
 
@@ -24382,7 +26403,7 @@ Date:   Sun Sep 9 13:09:27 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit e2b458a448106ba1ab207f0ea6824b56927d8547
-Merge: 9682e9e 3fe9322
+Merge: 9682e9e6 3fe93220
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Sep 9 13:03:47 2012 -0700
 
@@ -24562,7 +26583,7 @@ Date:   Sat Sep 1 00:14:27 2012 -0500
     This reverts commit ada6f2dfc045e77cb9499f20cdec1b4a54ef0db1.
 
 commit ec9e1186dce079a2f2b7be8050216ddb1bc1af66
-Merge: 503eabd 6d31f8d
+Merge: 503eabd0 6d31f8d1
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Aug 31 22:24:16 2012 -0500
 
@@ -24669,7 +26690,7 @@ Date:   Thu Aug 30 16:28:53 2012 -0500
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit b635cb26ba54c8f5c6a958e0ab0bc4d34d33b635
-Merge: 354c1fe a8ecf3a
+Merge: 354c1fed a8ecf3aa
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Aug 30 16:24:38 2012 -0500
 
@@ -24773,7 +26794,7 @@ Date:   Thu Aug 30 13:13:20 2012 +1200
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 583458772746317b98fced907ec780edff465888
-Merge: aea10c1 17b6ffb
+Merge: aea10c10 17b6ffb6
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Aug 29 11:29:24 2012 -0700
 
@@ -24994,14 +27015,14 @@ Date:   Mon Aug 27 22:45:20 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 5ed88fb72c3e3ecf3333c700d838667db71cfbdc
-Merge: adbe64c 621d093
+Merge: adbe64c5 621d0930
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Aug 28 23:39:53 2012 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
     
     Conflicts:
-       debian/control
+            debian/control
 
 commit adbe64c5a9402b7c5075a444a12629131b663877
 Author: Bdale Garbee <bdale@gag.com>
@@ -25967,21 +27988,21 @@ Date:   Wed Aug 8 07:07:49 2012 +1200
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 9456332fc16269270a2e9b7ef0b54523800cfe27
-Merge: bd02349 4d4ad34
+Merge: bd023491 4d4ad34a
 Author: Mike Beattie <mike@ethernal.org>
 Date:   Wed Aug 8 06:49:15 2012 +1200
 
     Merge branch 'master' of git://git.gag.com/fw/altos
 
 commit 4d4ad34aec0c75c66162b992f1e52947e4685730
-Merge: c7f2285 8e4ebd1
+Merge: c7f22850 8e4ebd1f
 Author: Keith Packard <keithp@keithp.com>
 Date:   Tue Aug 7 11:48:20 2012 -0700
 
     Merge remote-tracking branch 'mjb/master'
 
 commit bd02349111ae0f39b320e6a10a330051ddc39fdf
-Merge: 8e4ebd1 c7f2285
+Merge: 8e4ebd1f c7f22850
 Author: Mike Beattie <mike@ethernal.org>
 Date:   Wed Aug 8 06:46:56 2012 +1200
 
@@ -26168,7 +28189,7 @@ Date:   Thu Aug 2 21:20:23 2012 +1200
     Signed-off-by: Mike Beattie <mike@ethernal.org>
 
 commit 7481d06bebc2dc1473f451971d8b744c9da4e726
-Merge: 599e28b c56dead
+Merge: 599e28b2 c56dead7
 Author: Mike Beattie <mike@ethernal.org>
 Date:   Thu Aug 2 21:18:15 2012 +1200
 
@@ -26325,7 +28346,7 @@ Date:   Wed Jul 18 18:41:00 2012 -0600
     telescience: correctly calculating rate values with higher resolution
 
 commit e2b472bbb2418fc13be42dbc7c52beb88479c46d
-Merge: 75d6aa6 b242f27
+Merge: 75d6aa6f b242f275
 Author: Robert Garbee <robert@gag.com>
 Date:   Wed Jul 18 14:25:27 2012 -0600
 
@@ -28631,7 +30652,7 @@ Date:   Mon May 7 23:14:14 2012 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 6a973f788563ccc66b01cc7557a004dabef18d09
-Merge: d387f24 da2c920
+Merge: d387f246 da2c920b
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed May 16 09:13:53 2012 -0600
 
@@ -30956,34 +32977,34 @@ Date:   Fri Oct 7 09:53:09 2011 -0600
     
     Conflicts:
     
-       src/Makefile.proto
-       src/cc1111/ao_adc.c
-       src/cc1111/ao_packet_master.c
-       src/core/ao.h
+            src/Makefile.proto
+            src/cc1111/ao_adc.c
+            src/cc1111/ao_packet_master.c
+            src/core/ao.h
     
     Fix up the new makefiles
 
 commit 128bbfa150f88c09f7adde2434b7bf0b5a9ed556
-Merge: f6f54d7 246864b
+Merge: f6f54d70 246864b0
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Oct 7 08:41:56 2011 -0600
 
     Merge remote-tracking branch 'origin/simple-quiet' into multiarch
     
     Conflicts:
-       configure.ac
+            configure.ac
     
     fix version number
 
 commit f6f54d70b768dca1715ddddea64a4df00d82b09e
-Merge: 1c344b7 0d10e25
+Merge: 1c344b76 0d10e257
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Oct 7 08:40:14 2011 -0600
 
     Merge remote-tracking branch 'uniarch/master' into multiarch
     
     Conflicts:
-       src/core/ao_cmd.c
+            src/core/ao_cmd.c
     
     Use ao_arch_reboot after waiting for a second
 
@@ -31017,14 +33038,14 @@ Date:   Mon Sep 26 11:50:28 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 1c344b760776cd5d8c0297d8db9bf02687381b4e
-Merge: 4ed53ef fc4173f
+Merge: 4ed53ef8 fc4173ff
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Oct 7 08:34:59 2011 -0600
 
     Merge remote-tracking branch 'origin/master' into multiarch
     
     Conflicts:
-       configure.ac
+            configure.ac
     
     Fix version number and location of ao.h header
 
@@ -31035,7 +33056,7 @@ Date:   Tue Sep 27 00:59:08 2011 -0600
     add run-time dependency on libjfreechart-java
 
 commit 989aae5b18856e3420ea5b7a26ddd8dccae9d6d3
-Merge: 0552fbe e44f1ff
+Merge: 0552fbed e44f1ffb
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Sep 24 15:34:59 2011 -0600
 
@@ -31601,7 +33622,7 @@ Date:   Fri Aug 26 09:41:46 2011 -0600
     get ready for a 1.0.1 release
 
 commit 674231773256bacd7acb4b5718c47412e47b813f
-Merge: 08e3d54 3bfe8df
+Merge: 08e3d54b 3bfe8df4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Fri Aug 26 09:37:01 2011 -0600
 
@@ -31663,11 +33684,11 @@ Date:   Thu Aug 25 20:43:44 2011 -0700
     
     Split out sources into separate directories:
     
-       core:           architecture and product independent bits
-       cc1111:         cc1111-specific code
-       drivers:        architecture independent drivers
-       product:        product-specific sources and Makefile fragments
-       util:           scripts for building stuff
+            core:           architecture and product independent bits
+            cc1111:         cc1111-specific code
+            drivers:        architecture independent drivers
+            product:        product-specific sources and Makefile fragments
+            util:           scripts for building stuff
     
     This should have no effect on the built products, but testing is encouraged
     
@@ -31761,14 +33782,14 @@ Date:   Thu Aug 25 01:11:47 2011 -0600
     prepare to release
 
 commit 73abe19acf709c00f5352ec12e8cd6edae1d1963
-Merge: 1bd781d 5158493
+Merge: 1bd781da 5158493c
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Aug 25 00:34:49 2011 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
     
     Conflicts:
-       doc/altusmetrum.xsl
+            doc/altusmetrum.xsl
 
 commit 1bd781da934c738e0c9294197c7eb622b0710a9a
 Author: Bdale Garbee <bdale@gag.com>
@@ -31788,7 +33809,7 @@ Date:   Wed Aug 24 23:21:02 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit e268798dc260311f5f0167909481b41c9d27fc1c
-Merge: 458f816 242344d
+Merge: 458f816a 242344d3
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Aug 24 23:06:44 2011 -0700
 
@@ -31805,14 +33826,14 @@ Date:   Wed Aug 24 23:06:01 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 242344d3e32e7c7cd9270d708555923fa888e4d8
-Merge: 5c1cf74 94a1b22
+Merge: 5c1cf749 94a1b220
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 24 23:51:38 2011 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
     
     Conflicts:
-       doc/altusmetrum.xsl
+            doc/altusmetrum.xsl
 
 commit 5c1cf7492b82e63a9db9d0238ecbcd2b59486893
 Author: Bdale Garbee <bdale@gag.com>
@@ -31829,7 +33850,7 @@ Date:   Wed Aug 24 22:29:56 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit edfb553bb4fa5b0c7c6c658505b2a99d05fb13bf
-Merge: c74ab82 ec96f11
+Merge: c74ab82a ec96f116
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 24 23:23:56 2011 -0600
 
@@ -31863,7 +33884,7 @@ Date:   Wed Aug 24 22:18:29 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 50769fbbeaaf61111d363411e0ef0b2868681cf4
-Merge: 425fa99 d92c173
+Merge: 425fa995 d92c1736
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 24 23:15:20 2011 -0600
 
@@ -31893,7 +33914,7 @@ Date:   Wed Aug 24 23:03:23 2011 -0600
     more tweaks
 
 commit 09981cd024297fd4ef093c7468de2b9d5f3c2691
-Merge: a476e76 03c8b27
+Merge: a476e766 03c8b270
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 24 22:42:39 2011 -0600
 
@@ -31960,7 +33981,7 @@ Date:   Wed Aug 24 21:39:21 2011 -0600
     doc tweaks through chap 3
 
 commit 3d88e0493ab446d7c7011786390d30618a72d045
-Merge: 02d6545 5a9972d
+Merge: 02d65453 5a9972d4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 24 21:26:26 2011 -0600
 
@@ -32035,7 +34056,7 @@ Date:   Wed Aug 24 01:41:53 2011 -0600
     another test round
 
 commit 4d94e8f9f807a0bbeab0cdead011e74eeca1d1b6
-Merge: 4b5369d 3b0a9a1
+Merge: 4b5369dc 3b0a9a1c
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 24 01:38:58 2011 -0600
 
@@ -32287,7 +34308,7 @@ Date:   Sun Aug 21 22:12:04 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit a08826292ebd802a1ff2effccac3b96fd061c47d
-Merge: 3366cfe 55be3db
+Merge: 3366cfe6 55be3db2
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Aug 22 16:08:55 2011 -0600
 
@@ -32805,7 +34826,7 @@ Date:   Wed Aug 10 15:00:44 2011 -0700
     
     The official URL is now:
     
-       http://www.altusmetrum.org/AltOS/launch-sites.txt
+            http://www.altusmetrum.org/AltOS/launch-sites.txt
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
@@ -33361,7 +35382,7 @@ Date:   Sun Jul 17 11:25:47 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit f7cd8317bf78ece334e1ceb0263b875ca43bbbd2
-Merge: 51796e2 a482d90
+Merge: 51796e2f a482d904
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Jul 17 08:17:44 2011 -0700
 
@@ -33419,7 +35440,7 @@ Date:   Sat Jul 16 22:34:44 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit abb8510b97ce9cbbff0275cc31f74780fe1ce138
-Merge: 0929ee3 00e6981
+Merge: 0929ee32 00e6981c
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Jul 16 21:06:37 2011 -0700
 
@@ -34285,7 +36306,7 @@ Date:   Tue Apr 19 15:29:39 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 44fb71ca3e5bccd5f601fc5a2d5da7292050b1d6
-Merge: 2ebdb88 c269e26
+Merge: 2ebdb888 c269e263
 Author: Keith Packard <keithp@keithp.com>
 Date:   Tue Apr 19 14:06:39 2011 -0700
 
@@ -34494,7 +36515,7 @@ Date:   Thu Apr 7 22:00:38 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit f28efe271f9670473249574f6bcf6e160fe58c7b
-Merge: 8db5c52 835ab3a
+Merge: 8db5c52f 835ab3a8
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Apr 1 19:35:22 2011 -0700
 
@@ -35286,7 +37307,7 @@ Date:   Fri Mar 18 20:26:12 2011 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 5db94e1e230bade966a997aa83165405a9ec9d83
-Merge: 1a8f45e cbb968f
+Merge: 1a8f45e7 cbb968f5
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Fri Mar 18 21:12:39 2011 -0600
 
@@ -35793,7 +37814,7 @@ Date:   Tue Jan 18 17:27:11 2011 -0700
     update changelogs for Debian build
 
 commit da42f406e88ccc821cd45d5a94d5afec65ec50e9
-Merge: ea4cdfb cf550f9
+Merge: ea4cdfb8 cf550f9b
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Jan 17 09:50:17 2011 -0700
 
@@ -36790,14 +38811,14 @@ Date:   Wed Nov 24 21:39:18 2010 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 51c7741040d95c5deece939dae5e4136cc04afc4
-Merge: d1dbe3b 4e47c44
+Merge: d1dbe3b6 4e47c44d
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Nov 24 21:00:52 2010 -0800
 
     Merge branch 'buttonbox'
     
     Conflicts:
-       doc/telemetrum-doc.xsl
+            doc/telemetrum-doc.xsl
     
     Pull the buttbox version of the docs in as it had been updated.
     
@@ -36822,7 +38843,7 @@ Date:   Wed Nov 24 20:53:36 2010 -0700
     fix missing section close in Site Map content
 
 commit db2b19b8f0d452d682d53c7ed0ff6e359b46efa0
-Merge: b372f3c 915f881
+Merge: b372f3c0 915f881d
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Nov 24 18:57:35 2010 -0800
 
@@ -36843,7 +38864,7 @@ Date:   Thu Nov 25 09:52:30 2010 +1000
     doc: Document altosui "Site Map" tab
 
 commit f01096c4b42f9a4720ed0414826c2a283a992545
-Merge: 357826a 3fbefb3
+Merge: 357826aa 3fbefb3e
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Thu Nov 25 09:10:50 2010 +1000
 
@@ -36864,7 +38885,7 @@ Date:   Thu Nov 25 09:07:34 2010 +1000
     docs: Document altosui "Graph Data" button
 
 commit 7811e6dfa6caf10251da7df7c24b98cdc3787892
-Merge: 71b1949 7a50837
+Merge: 71b1949e 7a50837e
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Thu Nov 25 08:47:36 2010 +1000
 
@@ -36966,7 +38987,7 @@ Date:   Tue Nov 23 18:56:46 2010 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 71b1949e50f4533bcf44537da65b19bc67863c8e
-Merge: a79225c f1892b1
+Merge: a79225c2 f1892b13
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Wed Nov 24 12:14:11 2010 +1000
 
@@ -36980,7 +39001,7 @@ Date:   Tue Nov 23 18:58:11 2010 -0700
     while before I tackle that, if ever.
 
 commit a79225c215f17fa5218ddd9db4fc3f5c563a9f74
-Merge: 84cd5d4 853b711
+Merge: 84cd5d42 853b7112
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Wed Nov 24 11:55:14 2010 +1000
 
@@ -37005,7 +39026,7 @@ Date:   Wed Nov 24 02:11:36 2010 +1000
     altosui: don't switch away from user selected tab
 
 commit ae55a107f12546dc65f04618c7abc17beb920d73
-Merge: d1005f6 737f2fd
+Merge: d1005f68 737f2fdd
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Wed Nov 24 01:53:46 2010 +1000
 
@@ -37026,14 +39047,14 @@ Date:   Mon Nov 22 21:07:10 2010 -0700
     add a rudimentary --help for command line use
 
 commit d1005f68376d695039c314b8d7a68bbf9acbca4f
-Merge: 9a83e0d 22c0978
+Merge: 9a83e0dc 22c09781
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Tue Nov 23 10:14:55 2010 +1000
 
     Merge branch 'buttonbox' of git://git.gag.com/fw/altos into buttonbox
 
 commit 22c09781af1df4b38562b577e9926c23e4a397f2
-Merge: b27327a a79606a
+Merge: b27327a0 a79606a6
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon Nov 22 16:02:22 2010 -0800
 
@@ -37063,7 +39084,7 @@ Date:   Mon Nov 22 15:53:27 2010 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 9a83e0dc79f7a7467c7814d58daa2a2b89e50972
-Merge: 902735f a79606a
+Merge: 902735ff a79606a6
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Tue Nov 23 08:07:04 2010 +1000
 
@@ -37104,7 +39125,7 @@ Date:   Sun Nov 21 17:39:50 2010 +1000
     AltosSiteMap: ensure buffer around active tile
 
 commit ec47bc93a487614714a752cb30ec9fe3d8f72929
-Merge: 0393830 e7954c8
+Merge: 0393830f e7954c82
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sun Nov 21 16:08:37 2010 +1000
 
@@ -37162,14 +39183,14 @@ Date:   Sun Nov 21 13:07:11 2010 +1000
     AltosSiteMap: extend map if rocket goes far away
 
 commit 835b903727a2eabda8d9659cc46e53301f92897c
-Merge: 440a0f3 8789135
+Merge: 440a0f3f 87891355
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sun Nov 21 11:15:02 2010 +1000
 
     Merge branch 'sitemap' into buttonbox
     
     Conflicts:
-       ao-tools/altosui/AltosSiteMap.java
+            ao-tools/altosui/AltosSiteMap.java
 
 commit 878913551a1e4e3c8f2b39fa4aeb234880735a1c
 Author: Anthony Towns <aj@erisian.com.au>
@@ -37188,24 +39209,24 @@ Date:   Sat Nov 20 16:55:12 2010 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 2a7dc3ba36bac81640a9498e0d0caf1470b57c19
-Merge: e5b1ada ece2c86
+Merge: e5b1adae ece2c86e
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sun Nov 21 10:45:15 2010 +1000
 
     Merge branch 'buttonbox' into sitemap
     
     Conflicts:
-       ao-tools/altosui/AltosFlightUI.java
+            ao-tools/altosui/AltosFlightUI.java
 
 commit 8df185cd95cfecbed8272dd1275d077c5b45535b
-Merge: ece2c86 1e71264
+Merge: ece2c86e 1e712647
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Nov 20 16:35:48 2010 -0800
 
     Merge remote branch 'aj/sitemap' into buttonbox
     
     Conflicts:
-       ao-tools/altosui/AltosFlightUI.java
+            ao-tools/altosui/AltosFlightUI.java
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
@@ -37237,7 +39258,7 @@ Date:   Sun Nov 21 08:58:44 2010 +1000
     altosui: reindent
 
 commit a59a204e188e40ec8848a0dc63d6de710cee3039
-Merge: 8263630 37f0201
+Merge: 82636305 37f0201d
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sun Nov 21 08:56:13 2010 +1000
 
@@ -37315,14 +39336,14 @@ Date:   Sat Nov 20 21:06:37 2010 +1000
     AltosSiteMap: add autoscroll and grabndrag scroll
 
 commit 74cab8503b51ba6fb05a4d12a031c749e870b0ef
-Merge: 0ecf033 9a99cab
+Merge: 0ecf0331 9a99cabc
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sat Nov 20 18:20:45 2010 +1000
 
     Merge branch 'buttonbox' of git://git.gag.com/fw/altos into buttonbox
 
 commit 0ecf033110084f1a8be98282d7029dc14f70dab5
-Merge: 081fbd5 71c41ea
+Merge: 081fbd57 71c41ead
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sat Nov 20 18:14:30 2010 +1000
 
@@ -37353,14 +39374,14 @@ Date:   Sat Nov 20 00:09:03 2010 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 081fbd5715f9d3d81d98e149fb95d40447c07a79
-Merge: 90b9bc4 7920ed5
+Merge: 90b9bc44 7920ed5c
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sat Nov 20 17:40:49 2010 +1000
 
     Merge branch 'buttonbox' of git://git.gag.com/fw/altos into buttonbox
     
     Conflicts:
-       ao-tools/altosui/AltosFlightUI.java
+            ao-tools/altosui/AltosFlightUI.java
 
 commit 7920ed5c34b088f45ce4213b061ddd1ffe22cee8
 Author: Keith Packard <keithp@keithp.com>
@@ -37504,14 +39525,14 @@ Date:   Fri Nov 19 12:09:46 2010 +1000
     altosui: tile site maps
 
 commit 939be6793238a275b7682ecc376fed14379cf044
-Merge: e68fe94 1a4b6e9
+Merge: e68fe945 1a4b6e96
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Thu Nov 18 05:54:06 2010 +1000
 
     Merge branch 'buttonbox' of git://git.gag.com/fw/altos into buttonbox
     
     Conflicts:
-       ao-tools/altosui/AltosFlightUI.java
+            ao-tools/altosui/AltosFlightUI.java
 
 commit 1a4b6e96f823035b113f01d1bdfd61afc1f33e25
 Author: Keith Packard <keithp@keithp.com>
@@ -37654,7 +39675,7 @@ Date:   Sun Nov 14 00:57:45 2010 +1000
     AltosTelemetryReader: actually open serial port
 
 commit 9c32b93ef5fb43558fb0179ea1b047e35b7ed6e8
-Merge: 991541f a6f30fa
+Merge: 991541f5 a6f30fae
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sun Nov 14 00:29:11 2010 +1000
 
@@ -37671,7 +39692,7 @@ Date:   Fri Nov 12 17:02:22 2010 -0800
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 1bdc6166f3bc5ce3f8e55acb1484923781412e21
-Merge: f111871 5c6a533
+Merge: f1118717 5c6a5335
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Fri Nov 12 17:32:43 2010 -0700
 
@@ -37721,7 +39742,7 @@ Date:   Fri Nov 12 02:07:41 2010 +1000
     add site map tab, at least for QRS launches
 
 commit 5394548fa5c7bdbfcc01e8aa19e93e1cf6345e2a
-Merge: 891e629 75f7698
+Merge: 891e629f 75f7698b
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Nov 10 22:11:21 2010 -0800
 
@@ -37937,7 +39958,7 @@ Date:   Tue Sep 28 17:56:49 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 5a119fd92532d53e552efe1f7c61e87181fcace0
-Merge: 28da340 82744c3
+Merge: 28da3406 82744c34
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon Sep 27 22:28:07 2010 -0700
 
@@ -37966,7 +39987,7 @@ Date:   Tue Sep 28 14:45:01 2010 +1000
     Hax0r graphing to support telem/eeprom files
 
 commit e2b9f47a205348d38756c70e928a2a9183de6884
-Merge: 7ef3ad0 8032031
+Merge: 7ef3ad0c 80320319
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Tue Sep 28 12:55:47 2010 +1000
 
@@ -38014,7 +40035,7 @@ Date:   Mon Sep 27 17:11:48 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 7ef3ad0c9354c0484c25badc69334b59c7f355e2
-Merge: eb74866 e66919a
+Merge: eb74866e e66919aa
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Fri Sep 24 10:28:06 2010 +1000
 
@@ -38053,7 +40074,7 @@ Date:   Mon Aug 30 14:00:04 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit eb74866e919e8c661153847871f5a79e66d37296
-Merge: af404b4 1260589
+Merge: af404b42 12605899
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Mon Sep 20 22:05:26 2010 +1000
 
@@ -38096,7 +40117,7 @@ Date:   Wed Sep 15 06:51:05 2010 +1000
     Add graphing.
 
 commit 3d64f5a6511529ca53699190f4d54de1ba62a9bd
-Merge: ec6da08 b9623f8
+Merge: ec6da082 b9623f8e
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sat Sep 11 15:15:14 2010 +1000
 
@@ -38131,7 +40152,7 @@ Date:   Fri Sep 10 10:42:35 2010 -0600
     make the column headers comma separated, too, so they align with the data
 
 commit ec6da0824474e46de842845d7b53fe1a1dde33ed
-Merge: 7c2e411 1031067
+Merge: 7c2e4114 10310672
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Fri Sep 10 16:11:34 2010 +1000
 
@@ -38194,7 +40215,7 @@ Date:   Thu Sep 9 23:51:23 2010 -0600
     rewind packaging changelog
 
 commit 7c2e4114a3a43f919a7a6c967d3f16e5d630f90f
-Merge: ddc83b4 af200f5
+Merge: ddc83b4c af200f5b
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Fri Sep 10 15:50:01 2010 +1000
 
@@ -38299,7 +40320,7 @@ Date:   Thu Sep 9 20:06:09 2010 -0600
     update changelogs for Debian build
 
 commit 0ea75761416bff299233991e961ba25b6c7dcf89
-Merge: 35d70c9 8ee3464
+Merge: 35d70c92 8ee3464d
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Sep 9 20:05:27 2010 -0600
 
@@ -38412,7 +40433,7 @@ Date:   Thu Sep 9 15:43:47 2010 -0600
     update changelogs for Debian build
 
 commit ddc83b4c401be965a9947782becf20cc8c54e6a2
-Merge: afea6c2 3d49d5f
+Merge: afea6c26 3d49d5f6
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Sun Sep 5 20:49:34 2010 +1000
 
@@ -39224,14 +41245,14 @@ Date:   Fri Aug 27 12:41:26 2010 -0600
     update changelogs for Debian build
 
 commit cf65c6b8056c4af7c26b52ec6f9fbd3400cef638
-Merge: 5f2f6a8 ae5eff7
+Merge: 5f2f6a8f ae5eff7b
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Fri Aug 27 12:38:25 2010 -0600
 
     Merge branch 'bdale'
     
     Conflicts:
-       debian/control
+            debian/control
 
 commit ae5eff7bc0b63047737223423009707bedcb00f5
 Author: Bdale Garbee <bdale@gag.com>
@@ -39273,7 +41294,7 @@ Date:   Fri Aug 27 12:04:13 2010 -0600
     fix up the wrapper's path to the jar file
 
 commit 5f2f6a8f9ba56be867888758848bc7f152ccbd47
-Merge: 63bd34c 9d1b27f
+Merge: 63bd34cd 9d1b27fa
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Aug 27 11:00:31 2010 -0700
 
@@ -39312,7 +41333,7 @@ Date:   Fri Aug 27 11:17:54 2010 -0600
     add a dummy install target
 
 commit c443f43f8dee6e0fcbcecf9d09e948fd928b7af4
-Merge: 2950431 2923cf5
+Merge: 29504311 2923cf50
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Fri Aug 27 03:08:53 2010 -0600
 
@@ -39537,7 +41558,7 @@ Date:   Mon Aug 23 23:15:05 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit afea6c264c5ebf12f1d629bd4bc724da86d11b7a
-Merge: 0e17853 9d1b27f
+Merge: 0e17853c 9d1b27fa
 Author: Anthony Towns <aj@erisian.com.au>
 Date:   Tue Aug 24 00:02:31 2010 -0600
 
@@ -39555,7 +41576,7 @@ Date:   Mon Aug 23 23:01:36 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 295043112ccde35092945c286596f9045ee6fa05
-Merge: 2007288 ef8376c
+Merge: 2007288d ef8376c4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Aug 23 23:11:22 2010 -0600
 
@@ -39957,7 +41978,7 @@ Date:   Thu Jul 29 13:30:36 2010 -0600
     update changelogs for Debian build
 
 commit 7877496d47ce6d25210c0e1c6500666dbfc0876c
-Merge: c71061a 4cf39b1
+Merge: c71061a3 4cf39b13
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Jul 29 12:07:49 2010 -0700
 
@@ -40176,7 +42197,7 @@ Date:   Wed Jul 28 15:41:34 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 8a6040e143ecc7830cc1c0114de85f3b72c067eb
-Merge: 024d077 554a97e
+Merge: 024d0773 554a97ef
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Jul 28 13:29:51 2010 -0700
 
@@ -40220,7 +42241,7 @@ Date:   Wed Jul 28 12:24:53 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 172a2817dde6718724f2b5fad5a7761801446fa0
-Merge: f2a006f 81bf204
+Merge: f2a006fd 81bf2042
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Jul 28 11:20:22 2010 -0700
 
@@ -40245,21 +42266,21 @@ Date:   Wed Jul 28 09:31:09 2010 -0700
     
     Here's what happens with the ao_gps_tracking_report and ao_log threads:
     
-      ao_gps_tracking_report           ao_log
+      ao_gps_tracking_report                ao_log
     
        Writes a bunch of records
        *blocks* in the eeprom flush
-                                       sets ao_log_data 'log' to global 'log'
-                                       computes checksum for 'log' block
-                                       *blocks* on ao_log_mutex
+                                            sets ao_log_data 'log' to global 'log'
+                                            computes checksum for 'log' block
+                                            *blocks* on ao_log_mutex
        Wakes up
        sets ao_log_data 'log' to 'gps_log'
        writes remaining records
        'gps_log' is left with svid = 0
        *blocks* on ao_gps_tracking_data
-                                       writes data, reading from
-                                       the current ao_log_data 'log'
-                                       pointer which points at 'gps_log'
+                                            writes data, reading from
+                                            the current ao_log_data 'log'
+                                            pointer which points at 'gps_log'
     
     Making ao_log_data re-entrant fixes this by ensuring that the 'ao_log'
     thread has its own copy of the ao_log_data 'log' parameter.
@@ -40463,7 +42484,7 @@ Date:   Tue Jul 20 22:08:56 2010 -0600
     update changelogs for Debian build
 
 commit e747954b6a9e71705f619684df8a118a909b1039
-Merge: bd40a5b 695879d
+Merge: bd40a5b4 695879db
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Jul 20 22:07:22 2010 -0600
 
@@ -40534,14 +42555,14 @@ Date:   Mon Jun 21 11:44:32 2010 -0700
     ao-postflight: was walking off state.data array
 
 commit 11d155d558d0b121b66f089adee0a47d71f65a78
-Merge: 544003a 24393ea
+Merge: 544003a8 24393eab
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Jun 16 21:54:06 2010 -0700
 
     Merge remote branch 'mjb/master'
 
 commit 544003a8da0248fd6f3c62ded86af74ab7cdadf6
-Merge: 267923e 93c1e29
+Merge: 267923e5 93c1e29b
 Author: Keith Packard <keithp@keithp.com>
 Date:   Wed Jun 16 21:52:23 2010 -0700
 
@@ -40615,7 +42636,7 @@ Date:   Tue May 18 00:24:03 2010 -0600
     merge the altusmetrum-themes package
 
 commit 0c6cf621dfd8339b8bc3915750a3147235f1331b
-Merge: 32e430b 563a9dc
+Merge: 32e430b8 563a9dcd
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon May 17 23:59:43 2010 -0600
 
@@ -40640,7 +42661,7 @@ Date:   Mon May 17 21:30:57 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 69092ffd23ac1928d5c84413fd00c2423f313fc2
-Merge: 3c2211a cc002c0
+Merge: 3c2211ad cc002c0a
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon May 17 20:10:46 2010 -0600
 
@@ -40742,7 +42763,7 @@ Date:   Thu May 6 12:48:00 2010 -0600
     update changelogs for Debian build
 
 commit 314d27a73c903fef2968dabac3d5313573713460
-Merge: fa77db2 823fc0a
+Merge: fa77db2f 823fc0ac
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu May 6 12:47:30 2010 -0600
 
@@ -40850,7 +42871,7 @@ Date:   Tue Apr 27 00:18:43 2010 -0600
     update changelogs for Debian build
 
 commit 99094f02bf4849ba1f6b9842ded6c39d894320f7
-Merge: 641e76c 75d8ffd
+Merge: 641e76c5 75d8ffd4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Apr 27 00:17:37 2010 -0600
 
@@ -40892,7 +42913,7 @@ Date:   Thu Apr 22 14:53:44 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit f4383394b5d2b275b21e3ce8040d8cb9e48bb375
-Merge: 5f93cf8 c879b17
+Merge: 5f93cf8c c879b178
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Apr 18 08:36:07 2010 -0600
 
@@ -40997,7 +43018,7 @@ Date:   Thu Apr 8 17:28:17 2010 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit baaaac499cfbc1286ae55374cfdc796d32983b92
-Merge: a4356b9 dec9971
+Merge: a4356b9b dec9971d
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Apr 8 13:31:23 2010 -0700
 
@@ -41010,7 +43031,7 @@ Date:   Thu Apr 8 13:30:16 2010 -0700
     Use 16-bit flite voice (which appears to have changed symbols recently)
 
 commit 447c121fc1ceb878e45718ad1364a5349965a59a
-Merge: 10330d2 53ca3f9
+Merge: 10330d23 53ca3f98
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Apr 8 11:46:56 2010 -0700
 
@@ -41284,14 +43305,14 @@ Date:   Tue Mar 30 23:18:37 2010 -0600
     update changelogs for Debian build
 
 commit b41e617080fe825f7810ee5eee52ea37f7618ec6
-Merge: 28e40cc df7bda1
+Merge: 28e40ccf df7bda1f
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Mar 30 23:15:32 2010 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
     
     Conflicts:
-       ChangeLog
+            ChangeLog
 
 commit 28e40ccfcd80ab8764d4aa235257cea4d193a0c1
 Author: Bdale Garbee <bdale@gag.com>
@@ -41312,7 +43333,7 @@ Date:   Mon Mar 15 12:04:18 2010 -0600
     move gbp.conf into debian/
 
 commit df7bda1f32b0049c3878c325ea0b55999f3980e3
-Merge: 23da4f3 a7042fe
+Merge: 23da4f3b a7042fe7
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri Mar 12 10:38:26 2010 -0800
 
@@ -41374,7 +43395,7 @@ Date:   Sat Feb 27 17:36:13 2010 -0700
     update changelogs for Debian build
 
 commit a1478f65538fdaac7b58ffbd958a035b74956099
-Merge: 901fce5 bbf8c9f
+Merge: 901fce5f bbf8c9f1
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Feb 27 15:19:33 2010 -0800
 
@@ -42335,7 +44356,7 @@ Date:   Mon Nov 2 16:54:06 2009 -0700
     update changelogs for Debian build
 
 commit 7db9d86178ecfd58cc1c17ac9fcbdcfd2f13aaec
-Merge: b219801 f9de200
+Merge: b219801f f9de2000
 Author: Keith Packard <keithp@keithp.com>
 Date:   Mon Nov 2 15:47:40 2009 -0800
 
@@ -42384,7 +44405,7 @@ Date:   Mon Nov 2 15:56:42 2009 -0700
     de-version the libreadline-dev build dependency
 
 commit 0b483233118673cbc2cda1be6acd379df82bc95a
-Merge: ca5d323 550482d
+Merge: ca5d323a 550482d9
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Nov 1 20:59:02 2009 -0800
 
@@ -42573,14 +44594,14 @@ Date:   Mon Oct 12 15:57:19 2009 -0600
     update changelogs for Debian build
 
 commit c57bd7fd2f80e50b0b4c87fccb024ab07c93773d
-Merge: adf8764 2b76572
+Merge: adf8764b 2b765728
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Oct 12 15:57:08 2009 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
 
 commit 69b6f6bb465163cf767bb68e0e4a716d8ad2b39c
-Merge: bc77da6 2b76572
+Merge: bc77da68 2b765728
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Oct 10 17:16:21 2009 -0700
 
@@ -42598,7 +44619,7 @@ Date:   Sat Oct 10 17:15:38 2009 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit bc77da68c9cb7d4cca483eadbbb7e9ccf71c0060
-Merge: 46cccf6 8f7ea3d
+Merge: 46cccf62 8f7ea3de
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Oct 10 15:09:48 2009 -0700
 
@@ -42627,14 +44648,14 @@ Date:   Sat Oct 10 15:11:23 2009 -0600
     update changelogs for Debian build
 
 commit 541da6f3bbf81be93dfe3c01f7c8cfd757b28a2b
-Merge: dfc73cb 5f26ad6
+Merge: dfc73cba 5f26ad66
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Oct 10 15:05:50 2009 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
 
 commit 46cccf62fb40514b5930fcb2ffdaf2735415c764
-Merge: fb8f3fe 5f26ad6
+Merge: fb8f3fee 5f26ad66
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Oct 10 14:00:03 2009 -0700
 
@@ -42655,7 +44676,7 @@ Date:   Sat Oct 10 13:58:16 2009 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit fb8f3fee6a1bab1e46d782e84405845cee2dadb4
-Merge: 22856cf b8fc397
+Merge: 22856cf8 b8fc3975
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Oct 10 13:41:00 2009 -0700
 
@@ -42675,7 +44696,7 @@ Date:   Sat Oct 10 13:39:01 2009 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 22856cf8bb0f5e1f37c9b774132d9ef6934526ed
-Merge: 2f76034 e29961f
+Merge: 2f760349 e29961fd
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sat Oct 10 11:44:20 2009 -0700
 
@@ -42744,7 +44765,7 @@ Date:   Mon Sep 21 11:00:32 2009 -0700
     update changelogs for Debian build
 
 commit 327c64305a59f48ababf19875874a550af6b9cef
-Merge: c8a81a4 74f0fb4
+Merge: c8a81a41 74f0fb4d
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Sep 21 11:00:22 2009 -0700
 
@@ -42775,7 +44796,7 @@ Date:   Sun Sep 20 09:21:00 2009 -0600
     update changelogs for Debian build
 
 commit df42ccaaf468cdc5d93cbd1c001f58df58419722
-Merge: 0b24e40 078e9cd
+Merge: 0b24e403 078e9cdb
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Sep 20 09:19:28 2009 -0600
 
@@ -42871,7 +44892,7 @@ Date:   Sun Sep 6 17:46:39 2009 -0600
     update changelogs for Debian build
 
 commit 37e6c9a492a1d51373bf9333fb3172e0c377720f
-Merge: d256f82 2e6686b
+Merge: d256f820 2e6686b1
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Sep 6 17:46:10 2009 -0600
 
@@ -42884,7 +44905,7 @@ Date:   Sun Sep 6 16:45:47 2009 -0700
     Use plplotd instead of plplotd-gnome2
 
 commit d256f8204e9fce53ae4309562bb4c0cde1fae43e
-Merge: 0fc344d 32d3536
+Merge: 0fc344df 32d35367
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Sep 6 17:34:08 2009 -0600
 
@@ -42907,7 +44928,7 @@ Date:   Sun Sep 6 14:15:57 2009 -0600
     update changelogs for Debian build
 
 commit 4b0de757874c0ecaf38e3dfd3beefc398150e3d5
-Merge: 773c4ff d0eac98
+Merge: 773c4ffb d0eac989
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Sep 6 14:15:53 2009 -0600
 
@@ -42940,7 +44961,7 @@ Date:   Sun Sep 6 14:05:55 2009 -0600
     update changelogs for Debian build
 
 commit 45ede4a4b203ef9da5bf05c49cb9c5a2e6382ec5
-Merge: 45e2938 e35e485
+Merge: 45e29381 e35e485f
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Sep 6 14:05:51 2009 -0600
 
@@ -42963,7 +44984,7 @@ Date:   Sun Sep 6 14:02:14 2009 -0600
     update changelogs for Debian build
 
 commit d42ebf0661ecf15455e5051de1e16ae66f8dd857
-Merge: 384dbe9 7a19aac
+Merge: 384dbe9f 7a19aac5
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Sep 6 14:02:09 2009 -0600
 
@@ -42988,7 +45009,7 @@ Date:   Sun Sep 6 10:40:06 2009 -0600
     update changelogs for Debian build
 
 commit 35c54b3a278fa9bc2bc7f4b5ee04866697c93ba0
-Merge: 4f8eff7 6d018ab
+Merge: 4f8eff74 6d018ab9
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sun Sep 6 10:39:23 2009 -0600
 
@@ -43138,7 +45159,7 @@ Date:   Wed Sep 2 23:18:15 2009 -0600
     update changelogs for Debian build
 
 commit cb4a73f3b65ba72f645fd37ab8712829c9537bf8
-Merge: 9ddd869 e2e449d
+Merge: 9ddd8696 e2e449d5
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Sep 2 23:17:37 2009 -0600
 
@@ -43214,7 +45235,7 @@ Date:   Mon Aug 31 16:26:00 2009 -0600
     update changelogs for Debian build
 
 commit b34474c1f3083e73b7184d519f54d4c8031836fd
-Merge: 8df1697 0d65bff
+Merge: 8df16979 0d65bff4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Mon Aug 31 16:25:32 2009 -0600
 
@@ -43282,7 +45303,7 @@ Date:   Wed Aug 19 00:52:57 2009 -0600
     update changelogs for Debian build
 
 commit 4486d9156e19e4280b42bcd422d81d04f2d04a92
-Merge: dd09f0b 33edd62
+Merge: dd09f0bc 33edd629
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 19 00:49:24 2009 -0600
 
@@ -43324,7 +45345,7 @@ Date:   Tue Aug 18 21:49:39 2009 -0600
     add support for building Debian package
 
 commit d996aa9b32fb0eb385bd3d158256c29788a42fe3
-Merge: b3b2d3c 7d4ceb7
+Merge: b3b2d3c4 7d4ceb75
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Aug 18 18:56:09 2009 -0600
 
@@ -43341,7 +45362,7 @@ Date:   Tue Aug 18 17:55:22 2009 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit b3b2d3c475a135084b5628c730fc6fca1ba0817b
-Merge: 4685fc5 da12b89
+Merge: 4685fc54 da12b89f
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Aug 18 18:36:03 2009 -0600
 
@@ -43360,18 +45381,18 @@ Date:   Tue Aug 18 17:29:29 2009 -0700
     Fix ao-bitbang examples to not have . in the first column
 
 commit 4685fc541466afbeefc151bcb64cd054739c048b
-Merge: 1c2a0b6 c29275b
+Merge: 1c2a0b66 c29275b7
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Tue Aug 18 18:09:38 2009 -0600
 
     Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
     
     Conflicts:
-       ao-tools/ao-bitbang/Makefile.am
-       ao-tools/ao-eeprom/Makefile.am
-       ao-tools/ao-load/Makefile.am
-       ao-tools/ao-load/ao-load.c
-       ao-tools/ao-rawload/Makefile.am
+            ao-tools/ao-bitbang/Makefile.am
+            ao-tools/ao-eeprom/Makefile.am
+            ao-tools/ao-load/Makefile.am
+            ao-tools/ao-load/ao-load.c
+            ao-tools/ao-rawload/Makefile.am
 
 commit c29275b72438637d46d7a50742882d2736eb176a
 Author: Keith Packard <keithp@keithp.com>
@@ -43860,7 +45881,7 @@ Date:   Thu Jun 4 11:20:10 2009 -0700
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
 commit 17d2432a8b9c15963cd3b821f025ad33972ef477
-Merge: 210dbaa 8a9a3f0
+Merge: 210dbaa2 8a9a3f02
 Author: Keith Packard <keithp@keithp.com>
 Date:   Thu Jun 4 11:13:15 2009 -0700
 
index 288f43ce47857a3af002f0298270be13d2a6c7e5..8617a12cea7a5def8d7062cde0f3aea11e4561d6 100644 (file)
@@ -219,7 +219,23 @@ public class AltosConvert {
                return AltosLib.MISSING;
        }
 
-       static double tele_mini_voltage(int sensor) {
+       static double tele_mini_3_adc(int raw) {
+               return raw / 4095.0;
+       }
+
+       static public double tele_mini_3_battery_voltage(int v_batt) {
+               if (v_batt != AltosLib.MISSING)
+                       return 3.3 * tele_mini_3_adc(v_batt) * (5.6 + 10.0) / 10.0;
+               return AltosLib.MISSING;
+       }
+
+       static double tele_mini_3_pyro_voltage(int raw) {
+               if (raw != AltosLib.MISSING)
+                       return 3.3 * tele_mini_3_adc(raw) * (100.0 + 27.0) / 27.0;
+               return AltosLib.MISSING;
+       }
+
+       static double tele_mini_2_voltage(int sensor) {
                double  supply = 3.3;
 
                return sensor / 32767.0 * supply * 127/27;
@@ -350,6 +366,10 @@ public class AltosConvert {
                return (c - 32) * 5/9;
        }
 
+       public static double psi_to_pa(double psi) {
+               return psi * 6894.76;
+       }
+
        public static boolean imperial_units = false;
 
        public static AltosDistance distance = new AltosDistance();
index c9598254e34dbe34e0ef98f3a4e0f449d446d4b3..32d9f8eab2efa5066b44213c7881607b003b5f04 100644 (file)
@@ -82,13 +82,17 @@ public class AltosEepromChunk {
                case AltosLib.AO_LOG_FORMAT_TELEMETRUM:
                        eeprom = new AltosEepromMetrum2(this, offset);
                        break;
-               case AltosLib.AO_LOG_FORMAT_TELEMINI:
+               case AltosLib.AO_LOG_FORMAT_TELEMINI2:
+               case AltosLib.AO_LOG_FORMAT_TELEMINI3:
                case AltosLib.AO_LOG_FORMAT_EASYMINI:
                        eeprom = new AltosEepromMini(this, offset);
                        break;
                case AltosLib.AO_LOG_FORMAT_TELEGPS:
                        eeprom = new AltosEepromGPS(this, offset);
                        break;
+               case AltosLib.AO_LOG_FORMAT_TELEFIRETWO:
+                       eeprom = new AltosEepromFireTwo(this, offset);
+                       break;
                default:
                        throw new ParseException("unknown eeprom format " + log_format, 0);
                }
index 957c826a019098ec17bdce98be1ffb5b6cd1d052..5544ec37935a2a102d394ad362be01f167c03433 100644 (file)
@@ -101,13 +101,17 @@ public class AltosEepromFile extends AltosStateIterable {
                case AltosLib.AO_LOG_FORMAT_TELEMETRUM:
                        body = new AltosEepromIterable(AltosEepromMetrum2.read(input));
                        break;
-               case AltosLib.AO_LOG_FORMAT_TELEMINI:
+               case AltosLib.AO_LOG_FORMAT_TELEMINI2:
+               case AltosLib.AO_LOG_FORMAT_TELEMINI3:
                case AltosLib.AO_LOG_FORMAT_EASYMINI:
                        body = new AltosEepromIterable(AltosEepromMini.read(input));
                        break;
                case AltosLib.AO_LOG_FORMAT_TELEGPS:
                        body = new AltosEepromIterable(AltosEepromGPS.read(input));
                        break;
+               case AltosLib.AO_LOG_FORMAT_TELEFIRETWO:
+                       body = new AltosEepromIterable(AltosEepromFireTwo.read(input));
+                       break;
                default:
                        body = new AltosEepromIterable(new LinkedList<AltosEeprom>());
                        break;
diff --git a/altoslib/AltosEepromFireTwo.java b/altoslib/AltosEepromFireTwo.java
new file mode 100644 (file)
index 0000000..dd51028
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_11;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromFireTwo extends AltosEeprom {
+       public static final int record_length = 32;
+
+       public int record_length() { return record_length; }
+
+       /* AO_LOG_FLIGHT elements */
+       public int flight() { return data16(0); }
+       public int idle_pres() { return data16(2); }
+       public int idle_thrust() { return data16(4); }
+
+       /* AO_LOG_STATE elements */
+       public int state() { return data16(0); }
+       public int reason() { return data16(2); }
+
+       /* AO_LOG_SENSOR elements */
+       public int pres() { return data16(0); }
+       public int thrust() { return data16(2); }
+       public int temp(int i) { return data16(4+i*2); }
+
+       public AltosEepromFireTwo (AltosEepromChunk chunk, int start) throws ParseException {
+               parse_chunk(chunk, start);
+       }
+
+       private static final double r_above = 5600.0;
+       private static final double r_below = 10000.0;
+       private static final double v_adc = 3.3;
+
+       private static double
+       firetwo_adc(int raw) {
+               return raw / 4095.0;
+       }
+
+       private static double
+       adc_to_pa(int adc) {
+
+               /* raw adc to processor voltage, then back through the
+                * voltage divider to the sensor voltage
+                */
+
+               double  v = firetwo_adc(adc) * v_adc * (r_above + r_below) / r_below;
+
+               /* Bound to ranges provided in sensor */
+               if (v < 0.5) v = 0.5;
+               if (v > 4.5) v = 4.5;
+
+               double  psi = (v - 0.5) / 4.0 * 1600.0;
+               return AltosConvert.psi_to_pa(psi);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               switch (cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       state.set_flight(flight());
+                       state.set_ground_pressure(adc_to_pa(idle_pres()));
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.set_state(state());
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       state.set_pressure(adc_to_pa(pres()));
+                       break;
+               }
+       }
+
+       public AltosEepromFireTwo (String line) {
+               parse_string(line);
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> firetwos = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               try {
+                                       AltosEepromFireTwo firetwo = new AltosEepromFireTwo(line);
+
+                                       if (firetwo.cmd != AltosLib.AO_LOG_INVALID)
+                                               firetwos.add(firetwo);
+                               } catch (Exception e) {
+                                       System.out.printf ("exception\n");
+                               }
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return firetwos;
+       }
+}
index dc51e591de71c626ea371422769742d76e370f6d..04155071fbd0767f143788cf91a5ef94754e8167 100644 (file)
@@ -42,11 +42,24 @@ public class AltosEepromMini extends AltosEeprom {
        public int sense_m() { return data16(8); }
        public int v_batt() { return data16(10); }
 
-       double voltage(AltosState state, int sensor) {
+       private double battery_voltage(AltosState state, int sensor) {
                if (state.log_format == AltosLib.AO_LOG_FORMAT_EASYMINI)
                        return AltosConvert.easy_mini_voltage(sensor, state.serial);
-               else
-                       return AltosConvert.tele_mini_voltage(sensor);
+               if (state.log_format == AltosLib.AO_LOG_FORMAT_TELEMINI2)
+                       return AltosConvert.tele_mini_2_voltage(sensor);
+               if (state.log_format == AltosLib.AO_LOG_FORMAT_TELEMINI3)
+                       return AltosConvert.tele_mini_3_battery_voltage(sensor);
+               return -1;
+       }
+
+       private double pyro_voltage(AltosState state, int sensor) {
+               if (state.log_format == AltosLib.AO_LOG_FORMAT_EASYMINI)
+                       return AltosConvert.easy_mini_voltage(sensor, state.serial);
+               if (state.log_format == AltosLib.AO_LOG_FORMAT_TELEMINI2)
+                       return AltosConvert.tele_mini_2_voltage(sensor);
+               if (state.log_format == AltosLib.AO_LOG_FORMAT_TELEMINI3)
+                       return AltosConvert.tele_mini_3_pyro_voltage(sensor);
+               return -1;
        }
 
        public void update_state(AltosState state) {
@@ -62,9 +75,9 @@ public class AltosEepromMini extends AltosEeprom {
                        break;
                case AltosLib.AO_LOG_SENSOR:
                        state.set_ms5607(pres(), temp());
-                       state.set_apogee_voltage(voltage(state, sense_a()));
-                       state.set_main_voltage(voltage(state, sense_m()));
-                       state.set_battery_voltage(voltage(state, v_batt()));
+                       state.set_apogee_voltage(pyro_voltage(state, sense_a()));
+                       state.set_main_voltage(pyro_voltage(state, sense_m()));
+                       state.set_battery_voltage(battery_voltage(state, v_batt()));
                        break;
                }
        }
index 8871e9cc1089d6c3aab624052962efa302a3f852..73717e178c38569fbe2e426cae50f04ce809fccf 100644 (file)
@@ -38,8 +38,9 @@ class AltosIdler {
        static final int        idle_sensor_metrum = 11;
        static final int        idle_sensor_mega = 12;
        static final int        idle_sensor_emini = 13;
-       static final int        idle_sensor_tmini = 14;
+       static final int        idle_sensor_tmini2 = 14;
        static final int        idle_sensor_tgps = 15;
+       static final int        idle_sensor_tmini3 = 16;
 
        public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException, AltosUnknownProduct {
                for (int idler : idlers) {
@@ -72,12 +73,15 @@ class AltosIdler {
                        case idle_sensor_emini:
                                AltosSensorEMini.update_state(state, link, config_data);
                                break;
-                       case idle_sensor_tmini:
-                               AltosSensorTMini.update_state(state, link, config_data);
+                       case idle_sensor_tmini2:
+                               AltosSensorTMini2.update_state(state, link, config_data);
                                break;
                        case idle_sensor_tgps:
                                AltosSensorTGPS.update_state(state, link, config_data);
                                break;
+                       case idle_sensor_tmini3:
+                               AltosSensorTMini3.update_state(state, link, config_data);
+                               break;
                        }
                        if (idle != null)
                                idle.update_state(state);
@@ -108,7 +112,11 @@ public class AltosIdleFetch implements AltosStateUpdate {
 
                new AltosIdler("TeleMini-v2",
                               AltosIdler.idle_ms5607,
-                              AltosIdler.idle_sensor_tmini),
+                              AltosIdler.idle_sensor_tmini2),
+
+               new AltosIdler("TeleMini-v3",
+                              AltosIdler.idle_ms5607,
+                              AltosIdler.idle_sensor_tmini3),
 
                new AltosIdler("TeleMetrum-v1",
                               AltosIdler.idle_gps,
index cfa1fa2746da84690ba3df658f6e19b04eafebfa..a3f164d48827ecee6d5278c86863d063582edf07 100644 (file)
@@ -332,9 +332,12 @@ public class AltosLib {
        public static final int AO_LOG_FORMAT_TELEMEGA_OLD = 5;
        public static final int AO_LOG_FORMAT_EASYMINI = 6;
        public static final int AO_LOG_FORMAT_TELEMETRUM = 7;
-       public static final int AO_LOG_FORMAT_TELEMINI = 8;
+       public static final int AO_LOG_FORMAT_TELEMINI2 = 8;
        public static final int AO_LOG_FORMAT_TELEGPS = 9;
        public static final int AO_LOG_FORMAT_TELEMEGA = 10;
+       public static final int AO_LOG_FORMAT_DETHERM = 11;
+       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_NONE = 127;
 
        public static boolean isspace(int c) {
diff --git a/altoslib/AltosSensorTMini.java b/altoslib/AltosSensorTMini.java
deleted file mode 100644 (file)
index 073144d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.
- */
-
-package org.altusmetrum.altoslib_11;
-
-import java.util.concurrent.TimeoutException;
-
-public class AltosSensorTMini {
-       public int      tick;
-       public int      apogee;
-       public int      main;
-       public int      batt;
-
-       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
-               try {
-                       AltosSensorTMini        sensor_tmini = new AltosSensorTMini(link);
-
-                       if (sensor_tmini == null)
-                               return;
-                       state.set_battery_voltage(AltosConvert.tele_mini_voltage(sensor_tmini.batt));
-                       state.set_apogee_voltage(AltosConvert.tele_mini_voltage(sensor_tmini.apogee));
-                       state.set_main_voltage(AltosConvert.tele_mini_voltage(sensor_tmini.main));
-
-               } catch (TimeoutException te) {
-               }
-       }
-
-       public AltosSensorTMini(AltosLink link) throws InterruptedException, TimeoutException {
-               String[] items = link.adc();
-               for (int i = 0; i < items.length;) {
-                       if (items[i].equals("tick:")) {
-                               tick = Integer.parseInt(items[i+1]);
-                               i += 2;
-                               continue;
-                       }
-                       if (items[i].equals("apogee:")) {
-                               apogee = Integer.parseInt(items[i+1]);
-                               i += 2;
-                               continue;
-                       }
-                       if (items[i].equals("main:")) {
-                               main = Integer.parseInt(items[i+1]);
-                               i += 2;
-                               continue;
-                       }
-                       if (items[i].equals("batt:")) {
-                               batt = Integer.parseInt(items[i+1]);
-                               i += 2;
-                               continue;
-                       }
-                       i++;
-               }
-       }
-}
-
diff --git a/altoslib/AltosSensorTMini2.java b/altoslib/AltosSensorTMini2.java
new file mode 100644 (file)
index 0000000..7e00abd
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_11;
+
+import java.util.concurrent.TimeoutException;
+
+public class AltosSensorTMini2 {
+       public int      tick;
+       public int      apogee;
+       public int      main;
+       public int      batt;
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosSensorTMini2       sensor_tmini = new AltosSensorTMini2(link);
+
+                       if (sensor_tmini == null)
+                               return;
+                       state.set_battery_voltage(AltosConvert.tele_mini_2_voltage(sensor_tmini.batt));
+                       state.set_apogee_voltage(AltosConvert.tele_mini_2_voltage(sensor_tmini.apogee));
+                       state.set_main_voltage(AltosConvert.tele_mini_2_voltage(sensor_tmini.main));
+
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosSensorTMini2(AltosLink link) throws InterruptedException, TimeoutException {
+               String[] items = link.adc();
+               for (int i = 0; i < items.length;) {
+                       if (items[i].equals("tick:")) {
+                               tick = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("apogee:")) {
+                               apogee = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("main:")) {
+                               main = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("batt:")) {
+                               batt = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       i++;
+               }
+       }
+}
+
diff --git a/altoslib/AltosSensorTMini3.java b/altoslib/AltosSensorTMini3.java
new file mode 100644 (file)
index 0000000..19d514d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_11;
+
+import java.util.concurrent.TimeoutException;
+
+public class AltosSensorTMini3 {
+       public int      tick;
+       public int      apogee;
+       public int      main;
+       public int      batt;
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosSensorTMini3       sensor_tmini = new AltosSensorTMini3(link);
+
+                       if (sensor_tmini == null)
+                               return;
+                       state.set_battery_voltage(AltosConvert.tele_mini_3_battery_voltage(sensor_tmini.batt));
+                       state.set_apogee_voltage(AltosConvert.tele_mini_3_pyro_voltage(sensor_tmini.apogee));
+                       state.set_main_voltage(AltosConvert.tele_mini_3_pyro_voltage(sensor_tmini.main));
+
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosSensorTMini3(AltosLink link) throws InterruptedException, TimeoutException {
+               String[] items = link.adc();
+               for (int i = 0; i < items.length;) {
+                       if (items[i].equals("tick:")) {
+                               tick = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("apogee:")) {
+                               apogee = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("main:")) {
+                               main = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("batt:")) {
+                               batt = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       i++;
+               }
+       }
+}
+
index 0caefcd678a165e714b7e9cb3f53ce8f80578389..f830bf3582a0a452f24facbda8671e45019d642b 100644 (file)
@@ -67,7 +67,8 @@ public abstract class AltosTelemetry implements AltosStateUpdate {
        final static int packet_type_mega_data = 0x09;
        final static int packet_type_metrum_sensor = 0x0a;
        final static int packet_type_metrum_data = 0x0b;
-       final static int packet_type_mini = 0x10;
+       final static int packet_type_mini2 = 0x10;
+       final static int packet_type_mini3 = 0x11;
 
        static AltosTelemetry parse_hex(String hex)  throws ParseException, AltosCRCException {
                AltosTelemetry  telem = null;
diff --git a/altoslib/AltosTelemetryMini.java b/altoslib/AltosTelemetryMini.java
deleted file mode 100644 (file)
index 74adb05..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.
- */
-
-package org.altusmetrum.altoslib_11;
-
-
-public class AltosTelemetryMini extends AltosTelemetryStandard {
-       int     state;
-
-       int     v_batt;
-       int     sense_a;
-       int     sense_m;
-
-       int     pres;
-       int     temp;
-
-       int     acceleration;
-       int     speed;
-       int     height;
-
-       int     ground_pres;
-
-       public AltosTelemetryMini(int[] bytes) {
-               super(bytes);
-
-               state         = int8(5);
-
-               v_batt        = int16(6);
-               sense_a       = int16(8);
-               sense_m       = int16(10);
-
-               pres          = int32(12);
-               temp          = int16(16);
-
-               acceleration  = int16(18);
-               speed         = int16(20);
-               height        = int16(22);
-
-               ground_pres   = int32(24);
-       }
-
-       public void update_state(AltosState state) {
-               super.update_state(state);
-
-               state.set_state(this.state);
-
-               state.set_battery_voltage(AltosConvert.tele_mini_voltage(v_batt));
-               state.set_apogee_voltage(AltosConvert.tele_mini_voltage(sense_a));
-               state.set_main_voltage(AltosConvert.tele_mini_voltage(sense_m));
-
-               state.set_ground_pressure(ground_pres);
-
-               state.set_pressure(pres);
-               state.set_temperature(temp/100.0);
-
-               state.set_kalman(height, speed/16.0, acceleration/16.0);
-       }
-}
diff --git a/altoslib/AltosTelemetryMini2.java b/altoslib/AltosTelemetryMini2.java
new file mode 100644 (file)
index 0000000..50ec504
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_11;
+
+
+public class AltosTelemetryMini2 extends AltosTelemetryStandard {
+       int     state;
+
+       int     v_batt;
+       int     sense_a;
+       int     sense_m;
+
+       int     pres;
+       int     temp;
+
+       int     acceleration;
+       int     speed;
+       int     height;
+
+       int     ground_pres;
+
+       public AltosTelemetryMini2(int[] bytes) {
+               super(bytes);
+
+               state         = int8(5);
+
+               v_batt        = int16(6);
+               sense_a       = int16(8);
+               sense_m       = int16(10);
+
+               pres          = int32(12);
+               temp          = int16(16);
+
+               acceleration  = int16(18);
+               speed         = int16(20);
+               height        = int16(22);
+
+               ground_pres   = int32(24);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               state.set_state(this.state);
+
+               state.set_battery_voltage(AltosConvert.tele_mini_2_voltage(v_batt));
+               state.set_apogee_voltage(AltosConvert.tele_mini_2_voltage(sense_a));
+               state.set_main_voltage(AltosConvert.tele_mini_2_voltage(sense_m));
+
+               state.set_ground_pressure(ground_pres);
+
+               state.set_pressure(pres);
+               state.set_temperature(temp/100.0);
+
+               state.set_kalman(height, speed/16.0, acceleration/16.0);
+       }
+}
diff --git a/altoslib/AltosTelemetryMini3.java b/altoslib/AltosTelemetryMini3.java
new file mode 100644 (file)
index 0000000..21f8c48
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_11;
+
+
+public class AltosTelemetryMini3 extends AltosTelemetryStandard {
+
+       int     state;
+
+       int     v_batt;
+       int     sense_a;
+       int     sense_m;
+
+       int     pres;
+       int     temp;
+
+       int     acceleration;
+       int     speed;
+       int     height_16;
+
+       int     ground_pres;
+
+       public AltosTelemetryMini3(int[] bytes) {
+               super(bytes);
+
+               state         = int8(5);
+
+               v_batt        = int16(6);
+               sense_a       = int16(8);
+               sense_m       = int16(10);
+
+               pres          = int32(12);
+               temp          = int16(16);
+
+               acceleration  = int16(18);
+               speed         = int16(20);
+               height_16     = int16(22);
+
+               ground_pres   = int32(24);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               state.set_state(this.state);
+
+               state.set_battery_voltage(AltosConvert.tele_mini_3_battery_voltage(v_batt));
+
+               state.set_apogee_voltage(AltosConvert.tele_mini_3_pyro_voltage(sense_a));
+               state.set_main_voltage(AltosConvert.tele_mini_3_pyro_voltage(sense_m));
+
+               state.set_pressure(pres);
+               state.set_temperature(temp/100.0);
+
+               state.set_kalman(extend_height(state, height_16),
+                                speed/16.0, acceleration/16.0);
+
+               state.set_ground_pressure(ground_pres);
+       }
+}
index 4f0d7130543d43e5d953fb130aca588a2fe008f9..35d315c7972963b4b3ea1b9bfa447704c70e5d2a 100644 (file)
@@ -84,8 +84,11 @@ public abstract class AltosTelemetryStandard extends AltosTelemetry {
                case packet_type_metrum_data:
                        telem = new AltosTelemetryMetrumData(bytes);
                        break;
-               case packet_type_mini:
-                       telem = new AltosTelemetryMini(bytes);
+               case packet_type_mini2:
+                       telem = new AltosTelemetryMini2(bytes);
+                       break;
+               case packet_type_mini3:
+                       telem = new AltosTelemetryMini3(bytes);
                        break;
                default:
                        telem = new AltosTelemetryRaw(bytes);
index 2a9eb9c99e6150d090bb82821048a7cca01eb24f..2615942157195ca2333dc73bb86d5fc888e48b6b 100644 (file)
@@ -49,6 +49,7 @@ altoslib_JAVA = \
        AltosEepromMini.java \
        AltosEepromGPS.java \
        AltosEepromMonitor.java \
+       AltosEepromFireTwo.java \
        AltosFile.java \
        AltosFlash.java \
        AltosFlashListener.java \
@@ -88,7 +89,8 @@ altoslib_JAVA = \
        AltosSensorMM.java \
        AltosSensorEMini.java \
        AltosSensorTM.java \
-       AltosSensorTMini.java \
+       AltosSensorTMini2.java \
+       AltosSensorTMini3.java \
        AltosSensorMega.java \
        AltosSensorMetrum.java \
        AltosSensorTGPS.java \
@@ -105,7 +107,8 @@ altoslib_JAVA = \
        AltosTelemetryMap.java \
        AltosTelemetryMegaSensor.java \
        AltosTelemetryMegaData.java \
-       AltosTelemetryMini.java \
+       AltosTelemetryMini2.java \
+       AltosTelemetryMini3.java \
        AltosTelemetryMetrumSensor.java \
        AltosTelemetryMetrumData.java \
        AltosTelemetryReader.java \
index b4c8164f584b716cc64123b4cb725d57b2115b2d..f64b1f846b1edb1a5a715799ef66ebde988a7c40 100755 (executable)
@@ -12,7 +12,9 @@ case "$#" in
        serial="--serial $1"
        ;;
     0)
-       snum=`dmesg | grep 'on chaoskey' | tail -1 | sed 's/.*chaoskey \([0-9a-f][0-9a-f]*\) on chaoskey.*/\1/'`
+       snum=`sudo dmesg | awk '/usb.*Product:/ { ck = index($0, "ChaosKey"); }
+                    /usb.*SerialNumber:/ { if (ck) print $5; }' | tail -1`
+
        case "$snum" in
            "")
                serial=""
index e11244d2372eced9700fe10b5be103d574617c4d..e9948da90d4607aa90c8710cac6269007b59dc47 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 VERSION=1.0
 PRODUCT=EasyMini
@@ -8,48 +8,55 @@ 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 -e "\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"
-           echo ""
-           
-           ./test-igniters "$dev" drogue main
-           echo ""
-
-           echo "Testing baro sensor"
-           ../ao-tools/ao-test-baro/ao-test-baro --tty="$dev"
-
-           case $? in
-               0)
-                   ;;
-               *)
-                   echo "failed"
-                   exit 1
-           esac
-           echo""
+found=0
+while [ $found -eq 0 ]; do
+    (ao-list; echo END END END END) | while read product serial dev; do
+       case "$product" in
+           "$PRODUCT-v$VERSION")
 
-           FLASHSIZE=1048576
+               found=1
+               echo -e '\e[34m'Testing $product $serial $dev'\e[39m'
+               echo ""
+               
+               ./test-igniters "$dev" drogue main
+               echo ""
 
-           echo "Testing flash"
-           ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE"
+               echo "Testing baro sensor"
+               ../ao-tools/ao-test-baro/ao-test-baro --tty="$dev"
 
-           case $? in
-               0)
-                   ;;
-               *)
-                   echo "failed"
+               if [ $? -ne 0 ]; then
+                   echo -e '\e[31m'"$PRODUCT-$VERSION serial $serial failed"'\e[39m'
                    exit 1
-           esac
-           echo""
+               fi
+               echo""
+
+               FLASHSIZE=1048576
 
-           echo "$PRODUCT-v$VERSION" serial "$serial" is ready to ship
-           ret=0
-           ;;
-    esac
+               echo "Testing flash"
+               ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE"
+
+               if [ $? -ne 0 ]; then
+                   echo -e '\e[31m'"$PRODUCT-$VERSION serial $serial failed"'\e[39m'
+                   exit 1
+               fi
+
+               echo ""
+
+               echo -e '\e[32m'"$PRODUCT-v$VERSION" serial "$serial" is ready to ship'\e[39m'
+               exit 0
+               ;;
+           END)
+               exit 2
+               ;;
+       esac
+    done
+    result=$?
+    if [ $result -ne 2 ]; then
+       exit $result
+    fi
+    echo 'No device, sleeping...'
+    sleep 1
 done
diff --git a/ao-bringup/test-telemini b/ao-bringup/test-telemini
new file mode 100755 (executable)
index 0000000..7df36a2
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+VERSION=3.0
+PRODUCT=TeleMini
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+
+echo "$PRODUCT-v$VERSION Test Program"
+echo "Copyright 2017 by Keith Packard.  Released under GPL v2 or later"
+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"
+           echo ""
+
+           ./test-igniters "$dev" drogue main
+           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=524288
+
+           echo "Testing flash"
+           ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE"
+
+           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 1e75e72fb0c9a04be36f87f07fabeaf94a681a22..b14ed2ab9895c835d20f3de84bdb2775753db31b 100755 (executable)
@@ -1,5 +1,7 @@
 #!/bin/sh
 
+PRODUCT=EasyMega
+
 if [ -x ../ao-tools/ao-flash/ao-flash-stm ]; then
        STMLOAD=../ao-tools/ao-flash/ao-flash-stm
 else
@@ -17,16 +19,29 @@ fi
 VERSION=1.0
 REPO=~/altusmetrumllc/Binaries
 
-echo "EasyMega v$VERSION Turn-On and Calibration Program"
+echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
 echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2"
 echo
 echo "Expectations:"
-echo "\tEasyMega v$VERSION"
+echo "\t$PRODUCT v$VERSION"
 echo "\t\twith USB cable attached"
 echo "\t\twith ST-Link-V2 cabled to debug header"
 echo
-echo -n "EasyMega-$VERSION serial number: "
-read SERIAL
+
+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 $STMLOAD
 
@@ -38,14 +53,14 @@ $USBLOAD --serial=$SERIAL $REPO/easymega-v$VERSION*.elf || exit 1
 
 sleep 2
 
-dev=`../ao-tools/ao-list/ao-list | awk '/EasyMega-v'"$VERSION"'/ { print $3; exit(0); }'`
+dev=`../ao-tools/ao-list/ao-list | awk '/'"$PRODUCT"'-v'"$VERSION"'/ { print $3; exit(0); }'`
 
 case "$dev" in
 /dev/tty*)
-       echo "EasyMega found on $dev"
+       echo "$PRODUCT found on $dev"
        ;;
 *)
-       echo 'No EasyMega-v'"$VERSION"' found'
+       echo 'No '"$PRODUCT"'-v'"$VERSION"' found'
        exit 1
        ;;
 esac
index 0b915c5ee46152a5e5653c3fde19b121bbe9da8a..4580790a80eb919b4a799147ed86b78e96ae12ad 100755 (executable)
@@ -65,7 +65,7 @@ echo $USBLOAD $ALTOS_FILE
 
 $USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1
 
-sleep 2
+sleep 1
 
 ./test-easymini
 
index d17e2b96caae76fef6281e3e35cee58af506a4e5..0cdbde7a5973e37830e775ed677da6a0a66b503b 100755 (executable)
@@ -28,8 +28,21 @@ echo "\t$PRODUCT_NAME 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
-echo -n "$PRODUCT_NAME-$VERSION serial number: "
-read SERIAL
+
+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
 
 BINARIES=$HOME/altusmetrumllc/Binaries
 
index 058e72cec590936c7073bae6755cf17c5fb27e5f..20c8798a1e7639cdc38d441b51ac3396f340b72b 100755 (executable)
@@ -51,7 +51,7 @@ read FREQ
 CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
 
 echo "Programming flash with cal value " $CAL_VALUE
-$AOLOAD -D $programmer --cal $CAL_VALUE /usr/share/altos/teledongle-v0.2*.ihx $SERIAL
+$AOLOAD -D $programmer --cal $CAL_VALUE ~/altusmetrumllc/Binaries/teledongle-v0.2*.ihx $SERIAL
 
 echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
 echo $SERIAL","$CAL_VALUE >> cal_values
index ba97d503c09d476c1e52068320c286977dbf1f0c..b6da2898bbaece3545bce832e5f32bda8f4e1017 100755 (executable)
@@ -1,10 +1,12 @@
 #!/bin/sh
 
-if [ -x /usr/bin/ao-flash-lpc ]; then
-       FLASH_LPC=/usr/bin/ao-flash-lpc
+if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then
+        FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc
+elif [ -x /usr/bin/ao-flash-lpc ]; then
+        FLASH_LPC=/usr/bin/ao-flash-lpc
 else
-       echo "Can't find ao-flash-lpc!  Aborting."
-       exit 1
+        echo "Can't find ao-flash-lpc!  Aborting."
+        exit 1
 fi
 
 if [ -x /usr/bin/ao-usbload ]; then
@@ -14,8 +16,8 @@ else
        exit 1
 fi
 
-VERSION=1.0
 PRODUCT=TeleGPS
+VERSION=1.0
 BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
 echo $FILE
 
index 5c62c49d623b1871616c940fabc98658545ddc90..d40be953c4cb012bfe30eec44cb4846ff6e7ee12 100755 (executable)
@@ -48,7 +48,7 @@ $FLASH_STM ~/altusmetrumllc/Binaries/loaders/telemetrum-v$VERSION-*.elf || exit
 
 sleep 2
 
-$USBLOAD --serial=$SERIAL /usr/share/altos/telemetrum-v$VERSION*.ihx || exit 1
+$USBLOAD --serial=$SERIAL ~/altusmetrumllc/Binaries/telemetrum-v$VERSION-*.elf || exit 1
 
 sleep 5
 
diff --git a/ao-bringup/turnon_telemetrum_v1.1 b/ao-bringup/turnon_telemetrum_v1.1
new file mode 100755 (executable)
index 0000000..830d7ed
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+if [ -x ../ao-tools/ao-load/ao-load ]; then
+       AOLOAD=../ao-tools/ao-load/ao-load
+elif [ -x /usr/bin/ao-load ]; then
+       AOLOAD=/usr/bin/ao-load
+else
+       echo "Can't find ao-load!  Aborting."
+       exit 1
+fi
+
+if [ -x ../ao-tools/ao-rawload/ao-rawload ]; then
+       RAWLOAD=../ao-tools/ao-rawload/ao-rawload
+elif [ -x /usr/bin/ao-rawload ]; then
+       RAWLOAD=/usr/bin/ao-rawload
+else
+       echo "Can't find ao-rawload!  Aborting."
+       exit 1
+fi
+
+echo "TeleMetrum v1.1 Turn-On and Calibration Program"
+echo "Copyright 2010 by Bdale Garbee.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\tTeleMetrum v1.1 powered from USB"
+echo "\t\twith TeleDongle (on /dev/ttyACM0) cabled to debug header"
+echo "\t\twith coax from UHF to frequency counter"
+echo
+echo -n "TeleMetrum serial number: "
+read SERIAL
+
+echo $RAWLOAD
+
+$RAWLOAD --device 100 -r ao_led_blink.ihx
+echo "the red LED should be blinking"
+sleep 5
+
+$RAWLOAD --device 100 -r ao_radio_xmit.ihx
+echo -n "Generating RF carrier.  Please enter measured frequency: "
+read FREQ
+
+CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
+
+echo "Programming flash with cal value " $CAL_VALUE
+$AOLOAD --device 100 --cal $CAL_VALUE \
+       ~/altusmetrumllc/Binaries/telemetrum-v1.1*.ihx $SERIAL
+
+echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
+echo "Unplug and replug USB, cu to the board, confirm freq and record power"
index 6aef7f51b3635d741a269fa164c20e3024ea1509..1958de2a709f44fa6aac76d8be5eede0d4828a33 100755 (executable)
@@ -1,59 +1,76 @@
 #!/bin/sh
 
-if [ -x ../ao-tools/ao-load/ao-load ]; then
-       AOLOAD=../ao-tools/ao-load/ao-load
-elif [ -x /usr/bin/ao-load ]; then
-       AOLOAD=/usr/bin/ao-load
+if [ -x /usr/bin/dfu-util ]; then
+    DFU_UTIL=/usr/bin/dfu-util
 else
-       echo "Can't find ao-load!  Aborting."
-       exit 1
+    echo "Can't find dfu-util! Aborting."
+    exit 1
 fi
 
-if [ -x ../ao-tools/ao-rawload/ao-rawload ]; then
-       RAWLOAD=../ao-tools/ao-rawload/ao-rawload
-elif [ -x /usr/bin/ao-rawload ]; then
-       RAWLOAD=/usr/bin/ao-rawload
+if [ -x /usr/bin/ao-usbload ]; then
+       USBLOAD=/usr/bin/ao-usbload
 else
-       echo "Can't find ao-rawload!  Aborting."
+       echo "Can't find ao-usbload!  Aborting."
        exit 1
 fi
 
-VERSION=1.0
+VERSION=3.0
+PRODUCT=TeleMini
 
-echo "TeleMini v$VERSION Turn-On and Calibration Program"
-echo "Copyright 2011 by Bdale Garbee.  Released under GPL v2"
+echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2017 by Keith Packard.  Released under GPL v2 or later"
 echo
 echo "Expectations:"
-echo "\tTeleMini v$VERSION powered from LiPo"
-echo "\t\twith TeleDongle (on /dev/ttyACM0) cabled to debug header"
-echo "\t\twith frequency counter able to sample RF output"
+echo "\t$PRODUCT v$VERSION powered from USB"
 echo
-echo -n "TeleMini serial number: "
-read SERIAL
+echo -n "$PRODUCT-$VERSION serial number: "
+
+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 $RAWLOAD
+FLASH_FILE=~/altusmetrumllc/Binaries/loaders/telemini-v$VERSION-altos-flash-*.bin
+ALTOS_FILE=~/altusmetrumllc/Binaries/telemini-v$VERSION-*.elf
+#FLASH_FILE=../src/telemini-v3.0/flash-loader/telemini-v$VERSION-altos-flash-*.bin
+#ALTOS_FILE=../src/telemini-v3.0/telemini-v$VERSION-*.elf
 
-case $USER in
-    bdale)
-       programmer=100
+$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || exit 1
+
+sleep 2
+
+$USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1
+
+sleep 3
+
+dev=`ao-list | awk '/'"$PRODUCT"'-v'"$VERSION"'/ { print $3; exit(0); }'`
+
+case "$dev" in
+/dev/tty*)
+       echo "$PRODUCT found on $dev"
        ;;
-    keithp)
-       programmer=186
+*)
+       echo 'No '"$PRODUCT"'-v'"$VERSION"' found'
+       exit 1
        ;;
 esac
 
-$RAWLOAD -D $programmer -r ao_led_blink.ihx
-echo "LEDs should be blinking"
-sleep 5
+echo 'E 0' > $dev
 
-$RAWLOAD -D $programmer -r ao_radio_xmit.ihx
-echo -n "Generating RF carrier.  Please enter measured frequency: "
-read FREQ
+SERIAL=$SERIAL ./cal-freq $dev
 
-CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
+echo 'E 1' > $dev
 
-echo "Programming flash with cal value " $CAL_VALUE
-$AOLOAD -D $programmer --cal $CAL_VALUE ~/altusmetrumllc/Binaries/telemini-v$VERSION-*.ihx $SERIAL
+./test-telemini
 
-echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
-echo "Unplug and replug USB, cu to the board, confirm freq and record power"
+exit $?
index 9eebf5d2e55eb0dde1312d95cf53c8c95a669db5..a20428f29240484dfa55f9ddd47946e5479f9e27 100755 (executable)
@@ -5,29 +5,12 @@ case "$#" in
        exit 1
        ;;
 esac
-
-ST_FLASH=st-flash
-
-if which $ST_FLASH > /dev/null; then
-    :
-else
-    echo "$0: $ST_FLASH not found. Check to see if the stlink package is installed"
-    exit 1
-fi
-
-file=$1
-
-bin=/tmp/flash$$.bin
-trap "rm $bin" 0 1 15
-
-base=`arm-none-eabi-nm $file | awk '/interrupt_vector/ { print $1 }'`
-case x"$base" in
-x)
-    echo "$file: No interrupt vector address found"
-    exit 1
-    ;;
-esac
-
-arm-none-eabi-objcopy -O binary $file $bin
-
-$ST_FLASH --reset write $bin $base
+cmds=/tmp/flash$$
+trap "rm $cmds" 0 1 15
+file="$1"
+echo "program $file reset" > $cmds
+openocd \
+       -f interface/stlink-v2.cfg \
+       -f target/stm32l1.cfg \
+       -f $cmds \
+       -c shutdown
index d2b81e4f98fd0d8178e1803ad737194f905cc8e9..36c805c201bdb34181bd719b7c85b828eeccce00 100644 (file)
@@ -164,7 +164,7 @@ do_baro(struct cc_usb *usb) {
        double temperature = strtod(temp[2], NULL) / 100.0;
        double altitude = strtod(alt[1], NULL);
 
-       if (altitude < -50 || 3000 < altitude) {
+       if (altitude < -100 || 3000 < altitude) {
                printf ("weird altitude %f\n", altitude);
                free_baro(b);
                return 0;
index 0a23dfda0ae9eccc1be55b24a90dd8b0ecef7aa7..754cd78413037eb445b08395fc6fd819c4686eb0 100644 (file)
@@ -110,6 +110,7 @@ ao_self_write(struct cc_usb *cc, struct ao_hex_image *image)
                        start = image->address;
                if (stop > image->address + image->length)
                        stop = image->address + image->length;
+               memset(block, 0xff, 0x100);
                memcpy(block + start - address, image->data + start - image->address, stop - start);
                ao_self_block_write(cc, address, block);
                ao_self_block_read(cc, address, check);
index 0fc946f21831ee0ba525b9ea7de810a6b39b28f6..3e6658e9d45cd96bba45123b273c5be2740cc21d 100644 (file)
@@ -18,12 +18,15 @@ dnl
 dnl Process this file with autoconf to create configure.
 
 AC_PREREQ(2.57)
-AC_INIT([altos], 1.6.8)
-ANDROID_VERSION=13
+AC_INIT([altos], 1.7)
+ANDROID_VERSION=14
 AC_CONFIG_SRCDIR([src/kernel/ao.h])
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
 AM_MAINTAINER_MODE
 
+RELEASE_DATE=2017-04-24
+AC_SUBST(RELEASE_DATE)
+
 VERSION_DASH=`echo $VERSION | sed 's/\./-/g'`
 AC_SUBST(VERSION_DASH)
 AC_SUBST(ANDROID_VERSION)
@@ -515,6 +518,7 @@ AM_CONDITIONAL([INSTALL_SHARED_MIME_INFO], [test x$INSTALL_SHARED_MIME_INFO = xy
 AC_OUTPUT([
 Makefile
 src/Makedefs
+src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml
 altoslib/Makefile
 altoslib/AltosVersion.java
 icon/Makefile
index e6fb95abc5c8deed5459df5916c8f5a05fc8eaa8..0d01279fbe819d4d533fd38c38c2314396fb0bfd 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 RELNOTES_INC=\
+       release-notes-1.7.inc \
        release-notes-1.6.8.inc \
        release-notes-1.6.5.inc \
        release-notes-1.6.4.inc \
@@ -86,8 +87,11 @@ IMAGES=\
        telemetrum.svg \
        telemetrum-v1.1-thside.jpg \
        telemetrum-v2.0-th.jpg \
-       telemini.svg \
+       telemini-v1.svg \
        telemini-v1-top.jpg \
+       telemini-v3.svg \
+       telemini-v3.0-top.jpg \
+       telemini-v3.0-bottom.jpg \
        altusmetrum-oneline.svg \
        telegps-oneline.svg \
        micropeak-oneline.svg
@@ -107,7 +111,7 @@ INC_FILES=\
        getting-started.inc \
        usage.inc \
        telemetrum.inc \
-       telemini-v1.0.inc \
+       telemini.inc \
        easymini-device.inc \
        telemega.inc \
        easymega.inc \
@@ -162,7 +166,8 @@ OUTLINE_TXT_FILES=\
        easymini-outline.txt \
        telemega-outline.txt \
        telemetrum-outline.txt \
-       telemini-outline.txt
+       telemini-v1-outline.txt \
+       telemini-v3-outline.txt
 
 OUTLINE_RAW_FILES=$(OUTLINE_TXT_FILES:.txt=.raw)
 
@@ -172,7 +177,8 @@ SVG=\
        easymini.svg \
        telemega.svg \
        telemetrum.svg \
-       telemini.svg \
+       telemini-v1.svg \
+       telemini-v3.svg \
        easymega.svg
 
 RELNOTES_PDF=$(RELNOTES_INC:.inc=.pdf)
@@ -237,6 +243,7 @@ DOC=$(HTML) $(HTML_REVHISTORY) $(PDF) $(IMAGES) $(STYLESHEET)
 .raw.pdf:
        a2x --verbose -a docinfo -f pdf --xsltproc-opts "--stringparam toc.section.depth 2" --xsl-file $(FOP_STYLE) --fop --fop-opts="-c $(FOP_XCONF)" $*.raw
        a2x --verbose -a docinfo -f xhtml --xsltproc-opts "--stringparam toc.section.depth 2" --xsl-file $(HTML_STYLE) --stylesheet=$(STYLESHEET) $*.raw
+       case $* in release-notes*) ./fix-html $*.html ;; esac
 
 .pdf.html:
        @touch $@
@@ -260,6 +267,10 @@ micropeak.pdf micropeak.html: micropeak-docinfo.xml $(MICROPEAK_RAW_FILES) $(IMA
 
 easymini.pdf easymini.html: easymini-docinfo.xml $(EASYMINI_RAW_FILES) $(IMAGES)
 
+telemini-v1-outline.pdf: telemini-v1-outline.txt telemini-v1.svg
+
+telemini-v3-outline.pdf: telemini-v3-outline.txt telemini-v3.svg
+
 install:       all
 
 publish:       $(DOC) $(FONTS)
index faaa13f9720eb3f2308e5054af4e8dbb1058a3e9..dce81c3bbe65b206b2f9656f35a68f696709f766 100644 (file)
                flights, there may not be any space left. TeleMetrum
                and TeleMega can store multiple flights, depending on
                the configured maximum flight log size. TeleGPS logs
-               data continuously. TeleMini stores only a single
+               data continuously. TeleMini v1.0 stores only a single
                flight, so it will need to be downloaded and erased
                after each flight to capture data. This only affects
                on-board flight logging; the altimeter will still
index 76a24d918960872663d42bfb2d9a869bc762210a..88e7a03558dd75ad03a57ad0735f16c22f2279ff 100644 (file)
                This reprograms Altus Metrum devices with new
                firmware.
                ifdef::telemetrum,telemini[]
-                       TeleMetrum v1.x, TeleDongle v0.2, TeleMini
-                       and TeleBT are all reprogrammed by using another
+                       TeleMetrum v1.x, TeleDongle v0.2, TeleMini v1.0
+                       and TeleBT v1.0 are all reprogrammed by using another
                        similar unit as a programming dongle (pair
                        programming).
                endif::telemetrum,telemini[]
index e1f4eb62b86148d59c4fc7b3ce24c9e7715e95af..2475b5f1ea045c6baa28cb88f2132265b9f26217 100644 (file)
@@ -18,7 +18,7 @@
   <surname>Towns</surname>
 </author>
 <copyright>
-  <year>2016</year>
+  <year>2017</year>
   <holder>Bdale Garbee and Keith Packard</holder>
 </copyright>
 <mediaobject>
 </legalnotice>
 <revhistory>
   <?dbhtml filename="altusmetrum-revhistory.html"?>
+  <revision>
+    <revnumber>1.7</revnumber>
+    <date>21 Apr 2017</date>
+    <revremark>
+      Add support for TeleMini v3.0 in firmware, AltosUI and AltosDroid
+    </revremark>
+  </revision>
   <revision>
     <revnumber>1.6.8</revnumber>
     <date>4 Sep 2016</date>
index 15fc28fc6bba760f54d1beb46f4200322cd7c5a9..48211eb81b0aa5d6c5bad08532fa99969a61d4b1 100644 (file)
@@ -22,7 +22,7 @@
 
        include::telemetrum.raw[]
 
-       include::telemini-v1.0.raw[]
+       include::telemini.raw[]
 
        include::easymini-device.raw[]
 
diff --git a/doc/fix-html b/doc/fix-html
new file mode 100755 (executable)
index 0000000..d8751e4
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+sed -i \
+-e 's/<[?]xml [^>]*>//' \
+-e 's/<!DOCTYPE [^>]*>//' "$@"
index 32e44840fc86bbd9a7ad2e3292e6670c794f0910..392289083e1323d39070793ee3e19085199fd547 100644 (file)
@@ -25,6 +25,7 @@
        endif::telemetrum[]
        ifdef::telemini[]
        |TeleMini v1.0          |2      |5kB    |4
+       |TeleMini v3.0          |16     |512kB  |5
        endif::telemini[]
        ifdef::easymini[]
        |EasyMini               |16     |1MB    |10
@@ -44,7 +45,7 @@
             
        Configuration data is also stored in the flash memory on
        ifdef::telemetrum[TeleMetrum v1.x,]
-       ifdef::telemini[TeleMini and]
+       ifdef::telemini[TeleMini v3.0 and]
        ifdef::easymini[EasyMini.]
        This consumes 64kB
        of flash space.  This configuration space is not available
index d390551efe319733aaf74641c8783040c668c56f..273b435bda80c5c63dd51c2a1b53833e467b16a6 100644 (file)
@@ -6,7 +6,6 @@
        apogee and main ejection charges.  All Altus Metrum products are
        designed for use with single-cell batteries with 3.7 volts
        nominal.
-       ifdef::telemini[TeleMini v2.0 and]
        EasyMini may also be used with other
        batteries as long as they supply between 4 and 12 volts.
 
index 28daa41a12d0fe3026b1d3098b348c35786d55e7..6b0cd31872f08b7704d41a8fea0f358c6d01ef36 100644 (file)
@@ -17,9 +17,9 @@
        Our second device was TeleMini, a dual deploy altimeter with
        radio telemetry and radio direction finding. The first version
        of this device was only 13mm by 38mm (½ inch by 1½ inches) and
-       could fit easily in an 18mm air-frame. The latest version, v2.0,
-       includes a beeper, USB data download and extended on-board
-       flight logging, along with an improved barometric sensor.
+       could fit easily in an 18mm air-frame. The latest version, v3.0,
+       includes a beeper, higher power radio, extended on-board
+       flight logging and an improved barometric sensor.
 
        TeleMega is our most sophisticated device, including six pyro
        channels (four of which are fully programmable), integrated GPS,
diff --git a/doc/release-notes-1.7.inc b/doc/release-notes-1.7.inc
new file mode 100644 (file)
index 0000000..f2da71f
--- /dev/null
@@ -0,0 +1,25 @@
+= Release Notes for Version 1.7
+:toc!:
+:doctype: article
+
+       Version 1.7 includes support for our new TeleMini v3.0
+       flight computer and bug fixes in in the flight software for all our boards
+       and ground station interfaces.
+
+       == AltOS
+
+       AltOS New Features
+
+       * Add support for TeleMini v3.0 boards.
+
+       AltOS Fixes
+
+       * Fix interrupt priorities on STM32L processors. Run timer
+          interrupt at lowest priority so that device interrupts get
+          serviced first.
+
+       == AltosUI and TeleGPS Applications
+
+       AltosUI New Features
+
+       * Add support for TeleMini v3.0 hardware
index 7cd075f624a2e629988825175c28a16db90893c3..86ce95d3b69172a5786f3bf57ac8749ace3ef199 100644 (file)
@@ -1,6 +1,10 @@
 [appendix]
 == Release Notes
 
+       :leveloffset: 2
+       include::release-notes-1.7.raw[]
+
+       <<<<
        :leveloffset: 2
        include::release-notes-1.6.8.raw[]
 
index c335b081e0a42c6e1f063d029417a652dfa620da..f09d6fc9e7290587fce1099c17235ba76147291a 100644 (file)
        |10mW
        |3.7V
 
+       |TeleMini v3.0
+       |MS5607 30km (100k')
+       |-
+       |-
+       |-
+       |512kB
+       |40mW
+       |3.7V
        endif::telemini[]
 
        ifdef::easymini[]
index e68b2acbc5dca491c7c2bd3858a5334402149628..17dfdf89106f43d33edb1391b05fdf8951c9d4d1 100644 (file)
@@ -25,8 +25,9 @@
                is selected if the board is connected via USB to a computer,
                otherwise the board enters “flight” mode.
                ifdef::telemini[]
-               TeleMini v1.0
-               selects “idle” mode if it receives a command packet within the
+               TeleMini
+               selects “idle” mode if it receives a command packet
+               within the
                first five seconds of operation.
                endif::telemini[]
 
@@ -60,7 +61,7 @@
                mode for requests sent via TeleDongle.  Commands can be issued
                in idle mode over either USB or the radio link
                equivalently.
-               ifdef::telemini[TeleMini v1.0 only has the radio link.]
+               ifdef::telemini[TeleMini only has the radio link.]
                endif::radio[]
                Idle mode is useful for configuring the altimeter, for
                extracting data from the on-board storage chip after
                endif::telemetrum,telemega,easymega[]
 
                ifdef::telemini[]
-               TeleMini v1.0 is configured solely via the radio link. Of course, that
+               TeleMini is configured solely via the radio link. Of course, that
                means you need to know the TeleMini radio configuration values
                or you won't be able to communicate with it. For situations
-               when you don't have the radio configuration values, TeleMini v1.0
-               offers an 'emergency recovery' mode. In this mode, TeleMini is
+               when you don't have the radio configuration values,
+               TeleMini v1.0
+               offers an 'emergency recovery' mode. In this mode,
+               TeleMini v1.0 is
                configured as follows:
 
 
                Any operation which can be performed with a flight computer can
                either be done with the device directly connected to the
                computer via the USB cable, or through the radio
-               link. TeleMini v1.0 doesn't provide a USB connector and so it is
+               link. TeleMini doesn't provide a USB connector and so it is
                always communicated with over radio.  Select the appropriate
                TeleDongle device when the list of devices is presented and
                AltosUI will interact with an altimeter over the radio link.
index 36d2edba775088e9a340eb41e936bd594d759d9a..d7399b6a5fbd99a8e8b8bd5bb6ae8418846fac63 100644 (file)
                which device has transmitted the packet, when it was transmitted
                and what the rest of the packet contains.
 
-       === TeleMetrum v1.x, TeleMini and TeleNano Sensor Data
+       === TeleMetrum v1.x, TeleMini v1.0 and TeleNano Sensor Data
 
                .Sensor Packet Type
                [options="border",cols="1,3"]
                |====
                |Type   |Description
                |0x01   |TeleMetrum v1.x Sensor Data
-               |0x02   |TeleMini Sensor Data
+               |0x02   |TeleMini v1.0 Sensor Data
                |0x03   |TeleNano Sensor Data
                |====
 
-               TeleMetrum v1.x, TeleMini and TeleNano share this same
+               TeleMetrum v1.x, TeleMini v1.0 and TeleNano share this same
                packet format for sensor data. Each uses a distinct
                packet type so that the receiver knows which data
                values are valid and which are undefined.
                |32
                |====
 
+       === TeleMini v3.0 Sensor Data
+       
+               .Sensor Packet Type
+               [options="border",cols="1,3"]
+               |====
+               |Type   |Description
+               |0x11   |TeleMini v3.0 Sensor Data
+               |====
+
+               TeleMini v3.0 uses this
+               packet format for sensor data.
+
+               Sensor Data packets are transmitted once per second on
+               the ground, 10 times per second during ascent and once
+               per second during descent and landing
+
+               .Sensor Packet Contents
+               [options="border",cols="2,3,3,9"]
+               |====
+               |Offset |Data Type      |Name           |Description
+               |5      |uint8_t        |state          |Flight state
+               |6      |int16_t        |v_batt         |battery voltage
+               |8      |int16_t        |sense_a        |apogee continuity sense
+               |10     |int16_t        |sense_m        |main continuity sense
+               |12     |int32_t        |pres           |pressure sensor (Pa * 10)
+               |16     |int16_t        |temp           |temperature sensor (°C * 100)
+               |18     |int16_t        |acceleration   |m/s² * 16
+               |20     |int16_t        |speed          |m/s * 16
+               |22     |int16_t        |height         |m
+               |24     |int16_t        |ground_pres    |Average barometer reading on ground
+               |28     |pad[4]         |pad bytes      |
+               |32
+               |====
+
+
        === Configuration Data
 
                .Configuration Packet Type
diff --git a/doc/telemini-outline.txt b/doc/telemini-outline.txt
deleted file mode 100644 (file)
index 1992adf..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-= TeleMini Outline and Hole Pattern
-:doctype: article
-
-       This image, when printed, provides a precise template for the
-       mounting holes in TeleMini. TeleMini has overall dimensions of
-       0.500 x 1.500 inches, and the mounting holes are sized for use
-       with 2-56 or M2 screws.
-
-       image::telemini.svg[align="center"]
diff --git a/doc/telemini-v1-outline.txt b/doc/telemini-v1-outline.txt
new file mode 100644 (file)
index 0000000..bce3f65
--- /dev/null
@@ -0,0 +1,10 @@
+= TeleMini v1 Outline and Hole Pattern
+:doctype: article
+
+       This image, when printed, provides a precise template for the
+       mounting holes in TeleMini. TeleMini v1 has overall dimensions of
+       0.500 x 1.500 inches, and the mounting holes are sized for use
+       with 2-56 or M2 screws. The holes are located 0.100 inches
+       from the edge of the board in both directions.
+
+       image::telemini-v1.svg[align="center"]
diff --git a/doc/telemini-v1.0.inc b/doc/telemini-v1.0.inc
deleted file mode 100644 (file)
index e0d674f..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-== TeleMini v1.0
-
-       .TeleMini v1.0 Board
-       image::telemini-v1-top.jpg[width="5.5in"]
-
-       TeleMini v1.0 is ½ inches by 1½ inches.  It was
-       designed to fit inside an 18mm air-frame tube, but using it in
-       a tube that small in diameter may require some creativity in
-       mounting and wiring to succeed!  Since there is no
-       accelerometer, TeleMini can be mounted in any convenient
-       orientation.  The default ¼ wave UHF wire antenna attached to
-       the center of one end of the board is about 7 inches long. Two
-       wires for the power switch are connected to holes in the
-       middle of the board. Screw terminals for the e-matches for
-       apogee and main ejection charges depart from the other end of
-       the board, meaning an ideal “simple” avionics bay for TeleMini
-       should have at least 9 inches of interior length.
-
-       === TeleMini v1.0 Screw Terminals
-
-               TeleMini v1.0 has four screw terminals on the end of the
-               board opposite the telemetry antenna. Two are for the apogee
-               and two are for main igniter circuits. There are also wires
-               soldered to the board for the power switch.  Using the
-               picture above and starting from the top for the terminals
-               and from the left for the power switch wires, the
-               connections are as follows:
-
-               .TeleMini v1.0 Screw Terminals
-               [options="header",grid="all",cols="2,3,10"]
-               |====
-               |Terminal #|Terminal Name|Description
-
-               |1
-               |Apogee -
-               |Apogee pyro channel connection to pyro circuit
-
-               |2
-               |Apogee +
-               |Apogee pyro channel common connection to battery +
-
-               |3
-               |Main -
-               |Main pyro channel connection to pyro circuit
-
-               |4
-               |Main +
-               |Main pyro channel common connection to battery +
-
-               |Left
-               |Switch Output
-               |Switch connection to flight computer
-
-               |Right
-               |Switch Input
-               |Switch connection to positive battery terminal
-               |====
-
-       === Using a Separate Pyro Battery with TeleMini v1.0
-
-               As described above, using an external pyro battery involves
-               connecting the negative battery terminal to the flight
-               computer ground, connecting the positive battery terminal to
-               one of the igniter leads and connecting the other igniter
-               lead to the per-channel pyro circuit connection. Because
-               there is no solid ground connection to use on TeleMini, this
-               is not recommended.
-
-               The only available ground connection on TeleMini v1.0 are
-               the two mounting holes next to the telemetry
-               antenna. Somehow connect a small piece of wire to one of
-               those holes and hook it to the negative pyro battery terminal.
-
-               Connecting the positive battery terminal to the pyro
-               charges must be done separate from TeleMini v1.0, by soldering
-               them together or using some other connector.
-
-               The other lead from each pyro charge is then inserted into
-               the appropriate per-pyro channel screw terminal (terminal 3 for the
-               Main charge, terminal 1 for the Apogee charge).
-
-       === Using an Active Switch with TeleMini v1.0
-
-               As explained above, an external active switch requires three
-               connections, one to the positive battery terminal, one to
-               the flight computer positive input and one to ground. Again,
-               because TeleMini doesn't have any good ground connection,
-               this is not recommended.
-
-               The positive battery terminal is available on the Right
-               power switch wire, the positive flight computer input is on
-               the left power switch wire. Hook a lead to either of the
-               mounting holes for a ground connection.
diff --git a/doc/telemini-v1.svg b/doc/telemini-v1.svg
new file mode 100644 (file)
index 0000000..b2e21e3
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<svg
+       xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   width="1.75in"
+   height=".75in"
+   viewBox="0 0 175 75"
+   preserveaspectratio="none"
+   id="svg2"
+   version="1.1">
+  <g transform="translate(12.5,12.5)"
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-size:20">
+    <!-- outline -->
+    <rect width="150" height="50" x="0" y="0"/>
+    <!-- holes -->
+    <path d="M140,10 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
+    <path d="M140,40 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
+    <!-- arrow -->
+    <path d="M25,25 l100,0"/>
+    <path style="fill:#000000;stroke:none" d="M125,20 l10,5 l-10,5 z"/>
+    <!-- label -->
+    <text x="75" y="20" style="fill:#000000;stroke:none" text-anchor="middle">TeleMini</text>
+    <g transform="rotate(90)" style="font-size:14">
+      <text x="25" y="-133" style="fill:#000000;stroke:none" text-anchor="middle">UP</text>
+    </g>
+  </g>
+</svg>
\ No newline at end of file
diff --git a/doc/telemini-v3-outline.txt b/doc/telemini-v3-outline.txt
new file mode 100644 (file)
index 0000000..bb26ed6
--- /dev/null
@@ -0,0 +1,10 @@
+= TeleMini v3 Outline and Hole Pattern
+:doctype: article
+
+       This image, when printed, provides a precise template for the
+       mounting holes in TeleMini v3. TeleMini v3 has overall dimensions of
+       0.500 x 1.670 inches, and the mounting holes are sized for use
+       with 2-56 or M2 screws. The holes are located 0.085 inches
+       from the edge of the board in both directions.
+
+       image::telemini-v3.svg[align="center"]
diff --git a/doc/telemini-v3.0-bottom.jpg b/doc/telemini-v3.0-bottom.jpg
new file mode 100644 (file)
index 0000000..e4e4744
Binary files /dev/null and b/doc/telemini-v3.0-bottom.jpg differ
diff --git a/doc/telemini-v3.0-top.jpg b/doc/telemini-v3.0-top.jpg
new file mode 100644 (file)
index 0000000..1539902
Binary files /dev/null and b/doc/telemini-v3.0-top.jpg differ
diff --git a/doc/telemini-v3.svg b/doc/telemini-v3.svg
new file mode 100644 (file)
index 0000000..8835a2b
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<svg
+       xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   width="1.92in"
+   height=".75in"
+   viewBox="0 0 192 75"
+   preserveaspectratio="none"
+   id="svg2"
+   version="1.1">
+  <g transform="translate(12.5,12.5)"
+     style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linejoin:miter;font-size:20">
+    <!-- outline -->
+    <rect width="167" height="50" x="0" y="0"/>
+    <!-- holes -->
+    <path d="M8.5,8.5 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
+    <path d="M8.5,41.5 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
+    <path d="M158.5,8.5 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
+    <path d="M158.5,41.5 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
+    <!-- arrow -->
+    <path d="M25,25 l100,0"/>
+    <path style="fill:#000000;stroke:none" d="M125,20 l10,5 l-10,5 z"/>
+    <!-- label -->
+    <text x="75" y="20" style="fill:#000000;stroke:none" text-anchor="middle">TeleMini v3</text>
+    <g transform="rotate(90)" style="font-size:14">
+      <text x="25" y="-143" style="fill:#000000;stroke:none" text-anchor="middle">UP</text>
+    </g>
+  </g>
+</svg>
diff --git a/doc/telemini.inc b/doc/telemini.inc
new file mode 100644 (file)
index 0000000..b40582a
--- /dev/null
@@ -0,0 +1,106 @@
+== TeleMini
+
+       .TeleMini v3 Board
+       image::telemini-v3.0-top.jpg[width="5.5in"]
+       image::telemini-v3.0-bottom.jpg[width="5.5in"]
+
+       TeleMini v3 is 0.5 inches by 1.67 inches.  It was
+       designed to fit inside an 18mm air-frame tube, but using it in
+       a tube that small in diameter may require some creativity in
+       mounting and wiring to succeed!  Since there is no
+       accelerometer, TeleMini can be mounted in any convenient
+       orientation.  The default ¼ wave UHF wire antenna attached to
+       the center of one end of the board is about 7 inches long. Screw
+       terminals for the power switch are located in the
+       middle of the board. Screw terminals for the e-matches for
+       apogee and main ejection charges depart from the other end of
+       the board, meaning an ideal “simple” avionics bay for TeleMini
+       should have at least 9 inches of interior length.
+
+       === TeleMini v3 Screw Terminals
+
+               TeleMini v3 has four screw terminals on the end of the
+               board opposite the telemetry antenna. Two are for the apogee
+               and two are for main igniter circuits. Another two
+               screw terminals are located in the middle of the board
+               for the power switch.  Using the
+               picture above and starting from the top for the pyro terminals
+               and from the left for the power switch terminals, the
+               connections are as follows:
+
+               .TeleMini v3 Screw Terminals
+               [options="header",grid="all",cols="2,3,10"]
+               |====
+               |Terminal #|Terminal Name|Description
+
+               |1
+               |Apogee -
+               |Apogee pyro channel connection to pyro circuit
+
+               |2
+               |Apogee +
+               |Apogee pyro channel common connection to battery +
+
+               |3
+               |Main -
+               |Main pyro channel connection to pyro circuit
+
+               |4
+               |Main +
+               |Main pyro channel common connection to battery +
+
+               |Left
+               |Switch Output
+               |Switch connection to flight computer
+
+               |Right
+               |Switch Input
+               |Switch connection to positive battery terminal
+               |====
+
+       === Using a Separate Pyro Battery with TeleMini v3
+
+               As described above, using an external pyro battery involves
+               connecting the negative battery terminal to the flight
+               computer ground, connecting the positive battery terminal to
+               one of the igniter leads and connecting the other igniter
+               lead to the per-channel pyro circuit connection. Because
+               there is no solid ground connection to use on TeleMini, this
+               is not recommended.
+
+               The only available ground connection on TeleMini v3 are
+               the two mounting holes next to the telemetry
+               antenna. Somehow connect a small piece of wire to one of
+               those holes and hook it to the negative pyro battery terminal.
+
+               Connecting the positive battery terminal to the pyro
+               charges must be done separate from TeleMini v3, by soldering
+               them together or using some other connector.
+
+               The other lead from each pyro charge is then inserted into
+               the appropriate per-pyro channel screw terminal (terminal 3 for the
+               Main charge, terminal 1 for the Apogee charge).
+
+       === Using an Active Switch with TeleMini v3
+
+               As explained above, an external active switch requires three
+               connections, one to the positive battery terminal, one to
+               the flight computer positive input and one to ground. Again,
+               because TeleMini doesn't have any good ground connection,
+               this is not recommended.
+
+               The positive battery terminal is available on the Right
+               power switch wire, the positive flight computer input is on
+               the left power switch wire. Hook a lead to either of the
+               mounting holes for a ground connection.
+
+       === TeleMini v1
+
+               TeleMini v1 is the earlier version of this product. It
+               has a lower-power radio, less storage, no beeper and
+               soldered-in wires instead of screw terminals for the
+               power switch.
+
+               .TeleMini v1 Board
+               image::telemini-v1-top.jpg[width="5.5in"]
+
diff --git a/doc/telemini.svg b/doc/telemini.svg
deleted file mode 100644 (file)
index b2e21e3..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-
-<svg
-       xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   width="1.75in"
-   height=".75in"
-   viewBox="0 0 175 75"
-   preserveaspectratio="none"
-   id="svg2"
-   version="1.1">
-  <g transform="translate(12.5,12.5)"
-     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-size:20">
-    <!-- outline -->
-    <rect width="150" height="50" x="0" y="0"/>
-    <!-- holes -->
-    <path d="M140,10 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
-    <path d="M140,40 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
-    <!-- arrow -->
-    <path d="M25,25 l100,0"/>
-    <path style="fill:#000000;stroke:none" d="M125,20 l10,5 l-10,5 z"/>
-    <!-- label -->
-    <text x="75" y="20" style="fill:#000000;stroke:none" text-anchor="middle">TeleMini</text>
-    <g transform="rotate(90)" style="font-size:14">
-      <text x="25" y="-133" style="fill:#000000;stroke:none" text-anchor="middle">UP</text>
-    </g>
-  </g>
-</svg>
\ No newline at end of file
index 11ea12838d06904f0b026839bb559b4f4e976e32..91aa58f2b3309c87cc00edc79da6362f61c211e3 100644 (file)
@@ -11,7 +11,7 @@
        programmed directly over their USB connectors (self
        programming).
        ifdef::telemega[]
-       TeleMetrum v1, TeleMini and TeleDongle v0.2 are
+       TeleMetrum v1, TeleMini v1.0 and TeleDongle v0.2 are
        all programmed by using another device as a programmer (pair
        programming). It's important to recognize which kind of devices
        you have before trying to reprogram them.
 
                        If something goes wrong, give it another try.
 
-               ==== Updating TeleMini Firmware
+               ==== Updating TeleMini v1.0 Firmware
 
                        You'll need a special 'programming cable' to
-                       reprogram the TeleMini.  You can make your own
+                       reprogram the TeleMini v1.0.  You can make your own
                        using an 8-pin MicroMaTch connector on one end
                        and a set of four pins on the other.
 
                        . Plug the 8-pin end of the programming cable
                          to the matching connector on the TeleDongle
                          v0.2 or TeleBT v1.0, and the 4-pins into the
-                         holes in the TeleMini circuit board.  Note
+                         holes in the TeleMini v1.0 circuit board.  Note
                          that the MicroMaTch connector has an
                          alignment pin that goes through a hole in
                          the PC board when you have the cable
                          oriented correctly, and that pin 1 on the
-                         TeleMini board is marked with a square pad
+                         TeleMini v1.0 board is marked with a square pad
                          while the other pins have round pads.
 
-                       . Attach a battery to the TeleMini board.
+                       . Attach a battery to the TeleMini v1.0 board.
 
                        . Plug the TeleDongle v0.2 or TeleBT v1.0 into
                          your computer's USB port, and power up the
-                         TeleMini
+                         TeleMini v1.0
 
                        . Run AltosUI, and select 'Flash Image' from
                          the File menu.
                          programming device.
 
                        . Select the image you want put on the
-                         TeleMini, which should have a name in the
+                         TeleMini v1.0, which should have a name in the
                          form telemini-v1.0-1.0.0.ihx.  It should be
                          visible in the default directory, if not you
                          may have to poke around your system to find
                          you'll need to change them.
 
                        . Hit the 'OK' button and the software should
-                         proceed to flash the TeleMini with new
+                         proceed to flash the TeleMini v1.0 with new
                          firmware, showing a progress bar.
 
-                       . Confirm that the TeleMini board seems to
+                       . Confirm that the TeleMini v1.0 board seems to
                          have updated OK, which you can do by
                          configuring it over the radio link through
                          the TeleDongle, or letting it come up in
                ==== Updating TeleDongle v0.2 Firmware
 
                Updating TeleDongle v0.2 firmware is just like
-               updating TeleMetrum v1.x or TeleMini firmware, but you
+               updating TeleMetrum v1.x or TeleMini v1.0 firmware, but you
                use either a TeleMetrum v1.x, TeleDongle v0.2 or
                TeleBT v1.0 as the programmer.
 
index cca2a9718313170b1b823a51c22a37216b5fd06c..fde3c42194470194faf3f7ed9edf5b2dd5101752 100644 (file)
@@ -21,6 +21,7 @@
 int
 stdio_put(char c, FILE *stream)
 {
+       (void) stream;
        putchar(c);
        return 0;
 }
@@ -28,6 +29,7 @@ stdio_put(char c, FILE *stream)
 int
 stdio_get(FILE *stream)
 {
+       (void) stream;
        return (int) getchar() & 0xff;
 }
 
index 4f0a0c1400252b48fbf7f980f11e96194e0cb234..76d6d13b3392daa667156de26184b95dd8c92cc7 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <ao.h>
+#include <ao_launch.h>
 #include <ao_radio_cmac.h>
 
 __xdata uint16_t ao_launch_ignite;
diff --git a/src/cc1111/ao_launch.h b/src/cc1111/ao_launch.h
new file mode 100644 (file)
index 0000000..966b5ce
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_LAUNCH_H_
+#define _AO_LAUNCH_H_
+/* ao_launch.c */
+
+struct ao_launch_command {
+       uint16_t        tick;
+       uint16_t        serial;
+       uint8_t         cmd;
+       uint8_t         channel;
+       uint16_t        unused;
+};
+
+#define AO_LAUNCH_QUERY                1
+
+struct ao_launch_query {
+       uint16_t        tick;
+       uint16_t        serial;
+       uint8_t         channel;
+       uint8_t         valid;
+       uint8_t         arm_status;
+       uint8_t         igniter_status;
+};
+
+#define AO_LAUNCH_ARM          2
+#define AO_LAUNCH_FIRE         3
+
+void
+ao_launch_init(void);
+
+#endif /* _AO_LAUNCH_H_ */
index 0acef562608f7760104ae230e837b7aa90856eb5..a3d454da252a75385bd0b5e30136dd3e92da5ffd 100644 (file)
@@ -62,7 +62,7 @@ ao_timer_init(void)
        /* NOTE:  This uses a timer only present on cc1111 architecture. */
 
        /* disable timer 1 */
-       T1CTL = 0;
+/*     T1CTL = 0; */
 
        /* set the sample rate */
        T1CC0H = T1_SAMPLE_TIME >> 8;
index b0adba26a8a0da1d6f3a92852b2aead63c3d72f7..9fd5915431515fbbd7ce375e02ca8bfe07441e11 100644 (file)
@@ -1,2 +1,3 @@
 ao_product.h
 chaoskey-*
+*.cab
index d9944a124ab7ee3e2f318c8567cf1e0df482cfde..f2c168baf3cf1a99f3fe7cc55b5c9b1aaf01e1aa 100644 (file)
@@ -14,6 +14,7 @@ INC = \
        ao_task.h \
        ao_adc_fast.h \
        ao_power.h \
+       ao_crc.h \
        stm32f0.h
 
 #
@@ -38,6 +39,8 @@ ALTOS_SRC = \
        ao_gpio.c \
        ao_product.c
 
+VENDOR=AltusMetrum
+PROJECT_NAME=ChaosKey
 PRODUCT=ChaosKey-hw-1.0-sw-$(VERSION)
 PRODUCT_DEF=-DCHAOSKEY_V_1_0
 IDVENDOR=0x1d50
@@ -48,6 +51,7 @@ CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
 PROGNAME=chaoskey-v1.0
 PROG=$(PROGNAME)-$(VERSION).elf
 HEX=$(PROGNAME)-$(VERSION).ihx
+METAINFO=org.altusmetrum.ChaosKey.metainfo.xml
 
 SRC=$(ALTOS_SRC) ao_chaoskey.c
 OBJ=$(SRC:.c=.o)
@@ -62,11 +66,20 @@ ao_product.h: ao-make-product.5c ../Version
 
 $(OBJ): $(INC)
 
+%.cab: $(PROG) $(HEX) $(METAINFO)
+       gcab --create --nopath $@ $(PROG) $(HEX) $(METAINFO)
+
+cab: $(VENDOR)-$(PROJECT_NAME)-$(VERSION).cab
+
+check: $(METAINFO)
+       appstream-util validate-relax $(METAINFO)
+
 distclean:     clean
 
 clean:
        rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
        rm -f ao_product.h
+       rm -f *.cab
 
 install:
 
diff --git a/src/chaoskey-v1.0/chaoskey-connector.svg b/src/chaoskey-v1.0/chaoskey-connector.svg
new file mode 100644 (file)
index 0000000..671a46b
--- /dev/null
@@ -0,0 +1,274 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg7384"
+   sodipodi:docname="chaoskey.svg"
+   version="1.1"
+   inkscape:version="0.92pre3 r"
+   height="225"
+   width="400"
+   viewBox="0 0 400 225">
+  <metadata
+     id="metadata90">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>Gnome Symbolic Icon Theme</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     inkscape:cy="43.99517"
+     pagecolor="#e5e6e4"
+     borderopacity="1"
+     showborder="true"
+     inkscape:bbox-paths="false"
+     guidetolerance="10"
+     inkscape:object-paths="false"
+     inkscape:window-width="2560"
+     showguides="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-bbox="true"
+     inkscape:pageshadow="2"
+     inkscape:guide-bbox="true"
+     inkscape:snap-nodes="false"
+     bordercolor="#666666"
+     objecttolerance="10"
+     id="namedview88"
+     showgrid="false"
+     inkscape:window-maximized="1"
+     inkscape:window-x="2560"
+     inkscape:snap-global="true"
+     inkscape:window-y="0"
+     gridtolerance="10"
+     inkscape:window-height="1403"
+     inkscape:snap-others="false"
+     inkscape:snap-to-guides="true"
+     inkscape:current-layer="g9377"
+     inkscape:snap-bbox-midpoints="false"
+     inkscape:zoom="5.6568542"
+     inkscape:cx="79.698472"
+     inkscape:snap-grids="true"
+     inkscape:pageopacity="1"
+     inkscape:showpageshadow="false">
+    <inkscape:grid
+       spacingx="1px"
+       spacingy="1px"
+       id="grid4866"
+       empspacing="2"
+       enabled="true"
+       type="xygrid"
+       snapvisiblegridlinesonly="true"
+       visible="true" />
+  </sodipodi:namedview>
+  <title
+     id="title9167">Gnome Symbolic Icon Theme</title>
+  <defs
+     id="defs7386" />
+  <g
+     inkscape:label="figures"
+     transform="translate(-569.10098,-638)"
+     inkscape:groupmode="layer"
+     id="layer12"
+     style="display:inline">
+    <g
+       id="g9377"
+       transform="translate(6,740)">
+      <path
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         d="m 643.97547,-41.91406 c -6.36396,0 -12.97215,4.683215 -12.97215,12.019445 v 70.902784 9.335743 c 0,7.247844 4.39329,11.492028 10.40889,11.492028 h 109.67315 v -0.043 H 898.3666 v -5.457 -86.88477 -5.45703 H 751.08536 v -1.3125 -4.5957 z m 143.71145,20.37304 c 6.09267,0 11.17907,4.22094 12.44336,9.85938 -1.26429,5.63804 -6.35069,9.85742 -12.44336,9.85742 -6.09267,0 -11.17752,-4.21938 -12.44141,-9.85742 1.26389,-5.63844 6.34874,-9.85938 12.44141,-9.85938 z m 0,50.5918 c 6.09267,-10e-6 11.17907,4.22094 12.44336,9.85938 -1.26429,5.63804 -6.35069,9.85742 -12.44336,9.85742 -6.09267,0 -11.17752,-4.21938 -12.44141,-9.85742 1.26389,-5.63844 6.34874,-9.85939 12.44141,-9.85938 z"
+         id="path9437"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="sccsscccccccccsscscsccscc" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path9406"
+         d="m 749.75794,-30.548211 v 92.340426 h 148.60837 v -92.340426 z m 37.92955,9.007314 c 7.04304,-10e-7 12.75289,5.635711 12.75289,12.5873068 0,6.9515972 -5.70985,12.586021 -12.75289,12.586021 -7.04304,0 -12.75289,-5.6344238 -12.75289,-12.586021 0,-6.9515958 5.70985,-12.5873078 12.75289,-12.5873068 z m 0,50.591426 c 7.04304,-7e-6 12.75289,5.635708 12.75289,12.587306 0,6.951598 -5.70985,12.58602 -12.75289,12.58602 -7.04304,0 -12.75289,-5.634422 -12.75289,-12.58602 0,-6.951598 5.70985,-12.587313 12.75289,-12.587306 z"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <path
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         d="m 749.75794,-36.005319 v 92.340426 h 148.60837 v -92.340426 z m 37.92955,9.007314 c 7.04304,-1e-6 12.75289,5.635711 12.75289,12.587308 0,6.9515972 -5.70985,12.5860213 -12.75289,12.5860213 -7.04304,0 -12.75289,-5.6344241 -12.75289,-12.5860213 0,-6.951597 5.70985,-12.587309 12.75289,-12.587308 z m 0,50.591426 c 7.04304,-7e-6 12.75289,5.635708 12.75289,12.587306 0,6.951598 -5.70985,12.58602 -12.75289,12.58602 -7.04304,0 -12.75289,-5.634422 -12.75289,-12.58602 0,-6.951598 5.70985,-12.587313 12.75289,-12.587306 z"
+         id="rect9282"
+         inkscape:connector-curvature="0" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9374"
+         width="12.092357"
+         height="12.060186"
+         x="829.53729"
+         y="-29.215614"
+         rx="0"
+         ry="0" />
+      <ellipse
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="path9300"
+         cx="835.67212"
+         cy="-23.143618"
+         rx="3.6488662"
+         ry="3.6276596" />
+      <ellipse
+         cy="-11.930851"
+         cx="835.67212"
+         id="circle9316"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         rx="3.6488662"
+         ry="3.6276596" />
+      <ellipse
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="circle9318"
+         cx="835.67212"
+         cy="-1.3776593"
+         rx="3.6488662"
+         ry="3.6276596" />
+      <ellipse
+         cy="9.1755333"
+         cx="835.67212"
+         id="circle9320"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         rx="3.6488662"
+         ry="3.6276596" />
+      <ellipse
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="circle9322"
+         cx="835.67212"
+         cy="19.728724"
+         rx="3.6488662"
+         ry="3.6276596" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9339"
+         width="9.288023"
+         height="16.489361"
+         x="791.55402"
+         y="4.888298" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9341"
+         width="18.576046"
+         height="11.87234"
+         x="805.48608"
+         y="-24.132978" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9343"
+         width="17.249186"
+         height="7.9148936"
+         x="750.42133"
+         y="-18.835106" />
+      <rect
+         y="-1.6861706"
+         x="750.42133"
+         height="7.9148936"
+         width="17.249186"
+         id="rect9345"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9347"
+         width="17.249186"
+         height="7.9148936"
+         x="750.42133"
+         y="15.462767" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path9404"
+         d="m 634.00914,-35.108991 -3.0052,84.392953 c 0,8.662058 3.50963,12.551145 11.82333,12.551145 l 108.25753,0 V -37.3187 Z"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         sodipodi:nodetypes="cccccc" />
+      <rect
+         y="32.611702"
+         x="750.42133"
+         height="7.9148936"
+         width="17.249186"
+         id="rect9349"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <rect
+         y="-24.132978"
+         x="853.25305"
+         height="38.255318"
+         width="37.815521"
+         id="rect9351"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <rect
+         y="34.569149"
+         x="869.83881"
+         height="11.87234"
+         width="18.576046"
+         id="rect9353"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9355"
+         width="13.268604"
+         height="19.787233"
+         x="849.93591"
+         y="26.654255" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9359"
+         width="18.576046"
+         height="15.829787"
+         x="808.80322"
+         y="30.611702" />
+      <path
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         d="m 631.00394,-29.80569 v 69.648156 c 0,6.815994 3.28909,11.242641 9.52371,11.242641 H 751.0848 V -41.914894 H 645.03698 c -7.86656,0 -14.03304,4.772971 -14.03304,12.109204 z m 35.80579,-0.962137 h 11.98062 c 1.47016,0 2.65372,1.176681 2.65372,2.638298 v 17.280335 c 0,1.4616169 -1.18356,2.6382978 -2.65372,2.6382978 h -11.98062 c -1.47016,0 -2.65372,-1.1766809 -2.65372,-2.6382978 v -17.280335 c 0,-1.461617 1.18356,-2.638298 2.65372,-2.638298 z m 0,46.829786 h 11.98062 c 1.47016,0 2.65372,1.176681 2.65372,2.638298 v 17.280337 c 0,1.461617 -1.18356,2.638298 -2.65372,2.638298 h -11.98062 c -1.47016,0 -2.65372,-1.176681 -2.65372,-2.638298 V 18.700257 c 0,-1.461617 1.18356,-2.638298 2.65372,-2.638298 z"
+         id="rect9362"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cccccccssssssssssssssssss" />
+      <ellipse
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="path9364"
+         cx="738.81134"
+         cy="5.2446804"
+         rx="4.3122964"
+         ry="4.2872338" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9408"
+         width="37.815521"
+         height="38.255318"
+         x="853.25305"
+         y="-28.132978" />
+      <rect
+         y="26.611702"
+         x="808.80322"
+         height="15.829787"
+         width="18.576046"
+         id="rect9410"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <rect
+         y="-28.132978"
+         x="805.48608"
+         height="11.87234"
+         width="18.576046"
+         id="rect9412"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <rect
+         y="22.654255"
+         x="849.93591"
+         height="19.787233"
+         width="13.268604"
+         id="rect9414"
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      <rect
+         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+         id="rect9416"
+         width="18.576046"
+         height="11.87234"
+         x="869.83881"
+         y="30.569149" />
+    </g>
+  </g>
+</svg>
diff --git a/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in b/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in
new file mode 100644 (file)
index 0000000..6e39187
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2017 Richard Hughes <richard@hughsie.com> -->
+<component type="firmware">
+  <id>org.altusmetrum.ChaosKey.firmware</id>
+  <name>ChaosKey</name>
+  <summary>Firmware for the Altus Metrum ChaosKey</summary>
+  <description>
+    <p>
+      Updating the firmware on your ChaosKey device improves performance and adds
+      new features.
+    </p>
+  </description>
+  <provides>
+    <!-- USB\VID_1D50&PID_60C6 -->
+    <firmware type="flashed">b62500d7-c981-595b-a798-eb6cf4d4942b</firmware>
+  </provides>
+  <url type="homepage">https://chaoskey.org/</url>
+  <metadata_license>CC-BY-4.0</metadata_license>
+  <project_license>GPL-2.0</project_license>
+  <developer_name>AltusMetrum</developer_name>
+  <releases>
+    <release urgency="medium" version="@VERSION@" date="@RELEASE_DATE@">
+      <checksum filename="chaoskey-v1.0-@VERSION@.ihx" target="content"/>
+      <description>
+        <p>
+          FIXME before release.
+        </p>
+      </description>
+    </release>
+    <release urgency="medium" version="1.6.7" date="2017-01-01">
+      <checksum filename="chaoskey-v1.0-1.6.7.ihx" target="content"/>
+      <description>
+        <p>
+          Change the ADC clock speed to eliminate sampling problems which
+          cleans up the chaoskey raw data.
+        </p>
+      </description>
+    </release>
+  </releases>
+  <screenshots>
+    <screenshot type="default">
+      <image type="source">https://chaoskey.org/chaoskey-connector.svg</image>
+      <caption>Remove the plastic cover, then connect pins 1 and 5 whilst inserting into a USB socket.</caption>
+    </screenshot>
+  </screenshots>
+</component>
diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile
new file mode 100644 (file)
index 0000000..8cc6ce3
--- /dev/null
@@ -0,0 +1,137 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+LDFLAGS=-L../stm -Wl,-Tcortexelf.ld
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_pins.h \
+       ao_kalman.h \
+       ao_product.h \
+       ao_profile.h \
+       ao_task.h \
+       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 \
+       ao_flip_bits.h \
+       Makefile
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+
+
+ALTOS_SRC = \
+       ao_boot_chain.c \
+       ao_interrupt.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_task.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_serial_stm.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       ao_i2c_stm.c \
+       ao_as1107.c \
+       ao_matrix.c \
+       ao_vga.c \
+       ao_blt.c \
+       ao_copy.c \
+       ao_rect.c \
+       ao_text.c \
+       ao_line.c \
+       ao_ps2.c \
+       ao_console.c \
+       ao_sdcard.c \
+       ao_bufio.c \
+       ao_fat.c \
+       ao_flash_stm.c \
+       ao_button.c \
+       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 \
+       $(PROFILE) \
+       $(SAMPLE_PROFILE) \
+       $(STACK_GUARD)
+
+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
+
+SRC=$(ALTOS_SRC) ao_cortexelf.c
+OBJ=$(SRC:.c=.o)
+
+all:: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) cortexelf.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 ao_flip_bits.h
+
+ao_flip_bits.h: ao_flip_bits.5c
+       nickle ao_flip_bits.5c > $@
+
+include ../lisp/Makefile-lisp
+
+install:
+
+uninstall:
diff --git a/src/cortexelf-v1/ao_1802.c b/src/cortexelf-v1/ao_1802.c
new file mode 100644 (file)
index 0000000..9fb3659
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * 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.h>
+#include <ao_flip_bits.h>
+#include <ao_1802.h>
+#include <ao_exti.h>
+
+/* Decoded address driven by TPA/TPB signals */
+uint16_t       ADDRESS;
+
+/* Decoded data, driven by TPB signal */
+uint8_t                DATA;
+
+/* Mux control */
+#define _MUX_1802              0
+#define _MUX_STM               1
+
+uint8_t                MUX_CONTROL;
+
+/* Signals muxed between 1802 and STM */
+uint8_t
+MRD(void) {
+       return ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN);
+}
+
+void
+MRD_set(uint8_t value) {
+       ao_gpio_set(MRD_PORT, MRD_BIT, MRD_PIN, value);
+}
+
+uint8_t
+MWR(void) {
+       return ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN);
+}
+
+void
+MWR_set(uint8_t value) {
+       ao_gpio_set(MWR_PORT, MWR_BIT, MWR_PIN, value);
+}
+
+static void
+TPA_rising(void)
+{
+       ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8);
+       ao_wakeup(&ADDRESS);
+}
+
+uint8_t
+TPA(void) {
+       return ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN);
+}
+
+void
+TPA_set(uint8_t tpa) {
+       ao_gpio_set(TPA_PORT, TPA_BIT, TPA_PIN, tpa);
+       if (tpa)
+               TPA_rising();
+}
+
+static void
+TPB_rising(void)
+{
+       ADDRESS = (ADDRESS & 0xff00) | MA();
+       if (MWR() == 0 || MRD() == 0)
+               DATA = BUS();
+       ao_wakeup(&ADDRESS);
+}
+
+static void
+TPB_falling(void)
+{
+}
+
+uint8_t
+TPB(void) {
+       return ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN);
+}
+
+void
+TPB_set(uint8_t tpb) {
+       ao_gpio_set(TPB_PORT, TPB_BIT, TPB_PIN, tpb);
+       if (tpb)
+               TPB_rising();
+       else
+               TPB_falling();
+}
+
+uint8_t
+MA(void) {
+       return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & MA_MASK;
+}
+
+void
+MA_set(uint8_t ma) {
+       ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, MA_MASK << MA_SHIFT);
+}
+
+/* Tri-state data bus */
+
+uint8_t
+BUS(void) {
+       return ao_flip_bits_8[(ao_gpio_get_all(BUS_PORT) >> BUS_SHIFT) & BUS_MASK];
+}
+
+void
+BUS_set(uint8_t bus) {
+       ao_gpio_set_mask(BUS_PORT, ao_flip_bits_8[bus] << BUS_SHIFT, BUS_MASK << BUS_SHIFT);
+}
+
+void
+BUS_stm(void)
+{
+       ao_set_output_mask(BUS_PORT, BUS_MASK << BUS_SHIFT);
+}
+
+void
+BUS_1802(void)
+{
+       ao_set_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT);
+}
+
+/* Pins controlled by 1802 */
+uint8_t
+SC(void) {
+       return ao_flip_bits_2[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & SC_MASK];
+}
+
+uint8_t
+Q(void) {
+       return ao_gpio_get(Q_PORT, Q_BIT, Q_PIN);
+}
+
+uint8_t
+N(void) {
+       return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & N_MASK;
+}
+
+/* Pins controlled by STM */
+uint8_t
+EF(void) {
+       return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & EF_MASK;
+}
+
+void
+EF_set(uint8_t ef) {
+       ao_gpio_set_mask(EF_PORT, ef << EF_SHIFT, EF_MASK << EF_SHIFT);
+}
+
+uint8_t
+DMA_IN(void) {
+       return ao_gpio_get(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN);
+}
+
+void
+DMA_IN_set(uint8_t dma_in) {
+       ao_gpio_set(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, dma_in);
+}
+
+uint8_t
+DMA_OUT(void) {
+       return ao_gpio_get(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN);
+}
+
+void
+DMA_OUT_set(uint8_t dma_out) {
+       ao_gpio_set(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, dma_out);
+}
+
+uint8_t
+INT(void) {
+       return ao_gpio_get(INT_PORT, INT_BIT, INT_PIN);
+}
+
+void
+INT_set(uint8_t dma_out) {
+       ao_gpio_set(INT_PORT, INT_BIT, INT_PIN, dma_out);
+}
+
+uint8_t
+CLEAR(void) {
+       return ao_gpio_get(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN);
+}
+
+void
+CLEAR_set(uint8_t dma_out) {
+       ao_gpio_set(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, dma_out);
+}
+
+uint8_t
+WAIT(void) {
+       return ao_gpio_get(WAIT_PORT, WAIT_BIT, WAIT_PIN);
+}
+
+void
+WAIT_set(uint8_t dma_out) {
+       ao_gpio_set(WAIT_PORT, WAIT_BIT, WAIT_PIN, dma_out);
+}
+
+void
+tpb_isr(void) {
+       /* Latch low address and data on rising edge of TPB */
+       if (TPB())
+               TPB_rising();
+       else
+               TPB_falling();
+}
+
+void
+tpa_isr(void) {
+       /* Latch high address on rising edge of TPA */
+       if (TPA())
+               TPA_rising();
+}
+
+#define ao_1802_in(port, bit, mode) do {               \
+               ao_gpio_set_mode(port, bit, mode);      \
+               ao_set_input(port, bit);                \
+       } while (0)
+
+#define ao_1802_in_isr(port, bit, mode) do {           \
+               ao_gpio_set_mode(port, bit, mode);      \
+               ao_set_input(port, bit);                \
+               ao_exti_enable(port, bit);              \
+       } while (0)
+
+#define ao_1802_out_isr(port, bit) do { \
+               ao_exti_disable(port, bit); \
+               ao_set_output(port, bit); \
+       } while (0)
+
+void
+MUX_1802(void)
+{
+       if (MUX_CONTROL != _MUX_1802) {
+               /* Set pins to input, but pulled to idle value */
+               ao_1802_in(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
+               ao_1802_in(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
+               ao_1802_in_isr(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN);
+               ao_1802_in_isr(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN);
+               ao_set_input_mask(MA_PORT, MA_MASK << MA_SHIFT);
+
+               ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0);
+
+               /* Now change the pins to eliminate the pull up/down */
+               ao_gpio_set_mode(MRD_PORT, MRD_BIT, 0);
+               ao_gpio_set_mode(MWR_PORT, MWR_BIT, 0);
+               ao_gpio_set_mode(TPB_PORT, TPB_BIT, 0);
+               ao_gpio_set_mode(TPA_PORT, TPA_BIT, 0);
+
+               MUX_CONTROL = _MUX_1802;
+       }
+}
+
+void
+MUX_stm(void)
+{
+       if (MUX_CONTROL != _MUX_STM) {
+               /* Set the pins back to pull to the idle value */
+               ao_gpio_set_mode(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
+               ao_gpio_set_mode(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
+               ao_gpio_set_mode(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN);
+               ao_gpio_set_mode(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN);
+
+               ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1);
+
+               /* Now set the pins as output, driven to the idle value */
+               ao_set_output(MRD_PORT, MRD_BIT, MRD_PIN, 1);
+               ao_set_output(MWR_PORT, MWR_BIT, MWR_PIN, 1);
+               ao_set_output(TPB_PORT, TPB_BIT, TPB_PIN, 0);
+               ao_set_output(TPA_PORT, TPA_BIT, TPA_PIN, 0);
+               ao_set_output_mask(MA_PORT, MA_MASK << MA_SHIFT);
+               MUX_CONTROL = _MUX_STM;
+       }
+}
+
+void
+ao_1802_init(void)
+{
+       /* Multiplexed signals*/
+
+       /* active low signals */
+       ao_enable_input(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
+       ao_enable_input(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
+
+       /* active high signals with interrupts */
+       ao_exti_setup(TPA_PORT, TPA_BIT,
+                     AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING,
+                     tpa_isr);
+       ao_exti_setup(TPB_PORT, TPB_BIT,
+                     AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING,
+                     tpb_isr);
+
+       /* multiplexed address bus */
+       ao_enable_input_mask(MA_PORT, MA_MASK << MA_SHIFT, 0);
+
+       /* Data bus */
+
+       ao_enable_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT, 0);
+
+       /* Pins controlled by 1802 */
+       ao_enable_input_mask(SC_PORT, SC_MASK << SC_SHIFT, 0);
+       ao_enable_input(Q_PORT, Q_BIT, 0);
+       ao_enable_input_mask(N_PORT, N_MASK << N_SHIFT, 0);
+
+       /* Pins controlled by STM */
+       ao_enable_output_mask(EF_PORT, 0, EF_MASK << EF_SHIFT);
+       ao_enable_output(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, 1);
+       ao_enable_output(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, 1);
+       ao_enable_output(INT_PORT, INT_BIT, INT_PIN, 1);
+       ao_enable_output(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, 1);
+       ao_enable_output(WAIT_PORT, WAIT_BIT, WAIT_PIN, 1);
+
+       /* Force configuration to STM so that MUX_1802 will do something */
+       MUX_CONTROL = _MUX_STM;
+       MUX_1802();
+}
diff --git a/src/cortexelf-v1/ao_1802.h b/src/cortexelf-v1/ao_1802.h
new file mode 100644 (file)
index 0000000..5ea89fe
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_1802_H_
+#define _AO_1802_H_
+
+/* Decoded address driven by TPA/TPB signals */
+extern uint16_t                ADDRESS;
+
+/* Decoded data, driven by TPB signal */
+extern uint8_t         DATA;
+
+uint8_t
+MRD(void);
+
+void
+MRD_set(uint8_t value);
+
+uint8_t
+MWR(void);
+
+void
+MWR_set(uint8_t value);
+
+uint8_t
+TPA(void);
+
+void
+TPA_set(uint8_t tpa);
+
+uint8_t
+TPB(void);
+
+void
+TPB_set(uint8_t tpb);
+
+uint8_t
+MA(void);
+
+void
+MA_set(uint8_t ma);
+
+/* Tri-state data bus */
+
+uint8_t
+BUS(void);
+
+void
+BUS_set(uint8_t bus);
+
+void
+BUS_stm(void);
+
+void
+BUS_1802(void);
+
+/* Pins controlled by 1802 */
+uint8_t
+SC(void);
+
+uint8_t
+Q(void);
+
+uint8_t
+N(void);
+
+/* Pins controlled by STM */
+uint8_t
+EF(void);
+
+void
+EF_set(uint8_t ef);
+
+uint8_t
+DMA_IN(void);
+
+void
+DMA_IN_set(uint8_t dma_in);
+
+uint8_t
+DMA_OUT(void);
+
+void
+DMA_OUT_set(uint8_t dma_out);
+
+uint8_t
+INT(void);
+
+void
+INT_set(uint8_t dma_out);
+
+uint8_t
+CLEAR(void);
+
+void
+CLEAR_set(uint8_t dma_out);
+
+uint8_t
+WAIT(void);
+
+void
+WAIT_set(uint8_t dma_out);
+
+#define SC_FETCH       0
+#define SC_EXECUTE     1
+#define SC_DMA         2
+#define SC_INTERRUPT   3
+
+void
+MUX_1802(void);
+
+void
+MUX_stm(void);
+
+void
+ao_1802_init(void);
+
+#endif /* _AO_1802_H_ */
diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c
new file mode 100644 (file)
index 0000000..61a9d21
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * 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_profile.h>
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+#include <ao_ps2.h>
+#include <ao_vga.h>
+#include <ao_console.h>
+#include <ao_sdcard.h>
+#include <ao_fat.h>
+#include <ao_lisp.h>
+#include <ao_button.h>
+#include <ao_event.h>
+#include <ao_as1107.h>
+#include <ao_hex.h>
+#include <ao_1802.h>
+
+struct ao_task ball_task;
+
+#define BALL_WIDTH     5
+#define BALL_HEIGHT    5
+
+static int     ball_x;
+static int     ball_y;
+static int     ball_dx, ball_dy;
+
+uint8_t                ball_enable;
+
+void
+ao_ball(void)
+{
+       ball_dx = 1;
+       ball_dy = 1;
+       ball_x = 0;
+       ball_y = 0;
+       for (;;) {
+               while (!ball_enable)
+                       ao_sleep(&ball_enable);
+               for (;;) {
+                       ao_line(&ao_vga_bitmap,
+                               -100, -100, ball_x*2, ball_y*2,
+                               1, AO_XOR);
+                       ao_text(&ao_vga_bitmap,
+                               ball_x, ball_y - 10,
+                               "Hello, Bdale!",
+                               1, AO_XOR);
+                       ao_rect(&ao_vga_bitmap,
+                               ball_x, ball_y,
+                               BALL_WIDTH,
+                               BALL_HEIGHT,
+                               1,
+                               AO_XOR);
+                       ao_delay(AO_MS_TO_TICKS(10));
+                       ao_rect(&ao_vga_bitmap,
+                               ball_x, ball_y,
+                               BALL_WIDTH,
+                               BALL_HEIGHT,
+                               1,
+                               AO_XOR);
+                       ao_text(&ao_vga_bitmap,
+                               ball_x, ball_y - 10,
+                               "Hello, Bdale!",
+                               1, AO_XOR);
+                       ao_line(&ao_vga_bitmap,
+                               -100, -100, ball_x*2, ball_y*2,
+                               1, AO_XOR);
+                       if (!ball_enable)
+                               break;
+                       ball_x += ball_dx;
+                       ball_y += ball_dy;
+                       if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) {
+                               ball_x = AO_VGA_WIDTH - BALL_WIDTH;
+                               ball_dx = -ball_dx;
+                       }
+                       if (ball_x < 0) {
+                               ball_x = -ball_x;
+                               ball_dx = -ball_dx;
+                       }
+                       if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) {
+                               ball_y = AO_VGA_HEIGHT - BALL_HEIGHT;
+                               ball_dy = -ball_dy;
+                       }
+                       if (ball_y < 0) {
+                               ball_y = -ball_y;
+                               ball_dy = -ball_dy;
+                       }
+               }
+       }
+}
+
+static void
+ao_fb_init(void)
+{
+       ao_rect(&ao_vga_bitmap,
+               0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT,
+               1, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               10, 10, 10, 10,
+               0, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               AO_VGA_WIDTH - 20, 10, 10, 10,
+               0, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               10, AO_VGA_HEIGHT - 20, 10, 10,
+               0, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               AO_VGA_WIDTH - 20, AO_VGA_HEIGHT - 20, 10, 10,
+               0, AO_COPY);
+
+       ao_text(&ao_vga_bitmap,
+               20, 100,
+               "Hello, Bdale!",
+               0, AO_COPY);
+
+       ao_text(&ao_vga_bitmap,
+               1, ao_font.ascent,
+               "UL",
+               0, AO_COPY);
+
+       ao_text(&ao_vga_bitmap,
+               1, AO_VGA_HEIGHT - ao_font.descent,
+               "BL",
+               0, AO_COPY);
+}
+
+static void
+ao_video_toggle(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_lex_i)
+               ao_fb_init();
+       ao_vga_enable(ao_cmd_lex_i);
+}
+
+static void
+ao_ball_toggle(void)
+{
+       ao_cmd_decimal();
+       ball_enable = ao_cmd_lex_i;
+       ao_wakeup(&ball_enable);
+}
+
+static void
+ao_ps2_read_keys(void)
+{
+       char    c;
+
+       for (;;) {
+               c = ao_ps2_getchar();
+               printf("%02x %c\n", c, ' ' <= c && c < 0x7f ? c : '.');
+               flush();
+               if (c == ' ')
+                       break;
+       }
+}
+
+static void
+ao_console_send(void)
+{
+       char    c;
+
+       while ((c = getchar()) != '~') {
+               ao_console_putchar(c);
+               flush();
+       }
+}
+
+static void lisp_cmd() {
+       ao_lisp_read_eval_print();
+}
+
+static void
+ao_serial_blather(void)
+{
+       char c;
+
+       while ((c = getchar()) != '~') {
+               ao_serial1_putchar(c);
+               ao_serial2_putchar(c);
+       }
+}
+
+static void
+led_cmd(void)
+{
+       uint8_t start;
+       uint8_t value;
+       ao_cmd_decimal();
+
+       start = ao_cmd_lex_i;
+       ao_cmd_hex();
+       value = ao_cmd_lex_i;
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       ao_as1107_write_8(start, value);
+}
+
+__code struct ao_cmds ao_demo_cmds[] = {
+       { ao_video_toggle, "V\0Toggle video" },
+       { ao_ball_toggle, "B\0Toggle ball" },
+       { 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" },
+       { led_cmd, "L start value\0Show value (byte) at digit start" },
+       { 0, NULL }
+};
+
+static struct ao_task event_task;
+
+static void
+ao_event_loop(void)
+{
+       for (;;) {
+               struct ao_event ev;
+
+               ao_event_get(&ev);
+               printf("type %d uint %d tick %d value %d\n",
+                      ev.type, ev.unit, ev.tick, ev.value);
+               flush();
+       }
+}
+
+int
+main(void)
+{
+       ao_clock_init();
+
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+
+       ao_task_init();
+       ao_serial_init();
+       ao_timer_init();
+
+       ao_spi_init();
+       ao_dma_init();
+       ao_exti_init();
+
+       ao_sdcard_init();
+       ao_fat_init();
+
+       ao_ps2_init();
+       ao_vga_init();
+       ao_console_init();
+
+       ao_cmd_init();
+
+       ao_usb_init();
+
+       ao_button_init();
+
+       ao_as1107_init();
+       ao_matrix_init();
+       ao_1802_init();
+
+       ao_hex_init();
+
+       ao_config_init();
+
+       ao_add_task(&ball_task, ao_ball, "ball");
+       ao_add_task(&event_task, ao_event_loop, "events");
+       ao_cmd_register(&ao_demo_cmds[0]);
+
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/cortexelf-v1/ao_flip_bits.5c b/src/cortexelf-v1/ao_flip_bits.5c
new file mode 100644 (file)
index 0000000..cd5507c
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/nickle
+
+int flip_bits(int a, int n)
+{
+       int result = 0;
+       for (int pos = 0; pos < n; pos++)
+               if ((a & (1 << pos)) != 0)
+                       result |= (1 << (n - 1 - pos));
+       return result;
+}
+
+void print_flip_bits(string name, int n) {
+       printf ("static const uint8_t %s_%d[%d] = {\n", name, n, 1 << n);
+
+       for (int i = 0; i < 1 << n; i++) {
+               printf (" 0x%02x,", flip_bits(i, n));
+               if ((i & 0xf) == 0xf)
+                       printf("\n");
+       }
+       printf("};\n");
+}
+
+print_flip_bits("ao_flip_bits", 8);
+print_flip_bits("ao_flip_bits", 2);
diff --git a/src/cortexelf-v1/ao_hex.c b/src/cortexelf-v1/ao_hex.c
new file mode 100644 (file)
index 0000000..1507407
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.h>
+#include "ao_hex.h"
+#include "ao_as1107.h"
+#include "ao_1802.h"
+
+static struct ao_task  ao_hex_task;
+
+static void
+ao_hex(void)
+{
+       for (;;) {
+               ao_as1107_write_16(0, ADDRESS);
+               ao_as1107_write_8(6, DATA);
+               ao_sleep(&ADDRESS);
+       }
+}
+
+void
+ao_hex_init(void)
+{
+       ao_add_task(&ao_hex_task, ao_hex, "hex");
+}
diff --git a/src/cortexelf-v1/ao_hex.h b/src/cortexelf-v1/ao_hex.h
new file mode 100644 (file)
index 0000000..674c1ee
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_HEX_H_
+#define _AO_HEX_H_
+
+void
+ao_hex_init(void);
+
+#endif /* _AO_HEX_H_ */
diff --git a/src/cortexelf-v1/ao_lisp_os.h b/src/cortexelf-v1/ao_lisp_os.h
new file mode 100644 (file)
index 0000000..d0c1f7b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..7c85399
--- /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_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;
+}
diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h
new file mode 100644 (file)
index 0000000..258ffe3
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE         1
+
+/* 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 = 24MHz */
+#define AO_PLLDIV              4
+#define AO_RCC_CFGR_PLLDIV     (STM_RCC_CFGR_PLLDIV_4)
+
+/* HCLK = 24MHz (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_PPRE1_DIV_1
+
+/* Run APB2 at HCLK/1 */
+#define AO_APB2_PRESCALER      1
+#define AO_RCC_CFGR_PPRE2_DIV  STM_RCC_CFGR_PPRE2_DIV_1
+
+/* Allow for non-maskable interrupts at priority 0 */
+#define AO_NONMASK_INTERRUPT   1
+
+/* PS/2 keyboard connection */
+#define AO_PS2_CLOCK_PORT      (&stm_gpiod)
+#define AO_PS2_CLOCK_BIT       9
+#define AO_PS2_DATA_PORT       (&stm_gpiod)
+#define AO_PS2_DATA_BIT                8
+
+#define HAS_SERIAL_1           1
+#define USE_SERIAL_1_STDIN     1
+#define SERIAL_1_PB6_PB7       1
+#define SERIAL_1_PA9_PA10      0
+
+#define HAS_SERIAL_2           1
+#define USE_SERIAL_2_STDIN     1
+#define SERIAL_2_PA2_PA3       0
+#define SERIAL_2_PD5_PD6       1
+
+#define HAS_SERIAL_3           0
+#define USE_SERIAL_3_STDIN     0
+#define SERIAL_3_PB10_PB11     0
+#define SERIAL_3_PC10_PC11     0
+#define SERIAL_3_PD8_PD9       0
+
+#define HAS_EEPROM             0
+#define USE_INTERNAL_FLASH     0
+#define USE_EEPROM_CONFIG      0
+#define USE_STORAGE_CONFIG     0
+#define HAS_USB                        1
+#define HAS_BEEP               0
+#define HAS_BATTERY_REPORT     0
+#define HAS_RADIO              0
+#define HAS_TELEMETRY          0
+#define HAS_APRS               0
+#define HAS_COMPANION          0
+
+#define HAS_SPI_1              0
+#define SPI_1_PA5_PA6_PA7      0
+#define SPI_1_PB3_PB4_PB5      0
+#define SPI_1_PE13_PE14_PE15   0
+#define SPI_1_OSPEEDR          STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2              1
+#define SPI_2_PB13_PB14_PB15   0
+#define SPI_2_PD1_PD3_PD4      1       /* LED displays, microSD */
+#define SPI_2_OSPEEDR          STM_OSPEEDR_40MHz
+
+#define SPI_2_PORT             (&stm_gpiod)
+//#define SPI_2_SCK_PIN                1
+//#define SPI_2_MISO_PIN               3
+//#define SPI_2_MOSI_PIN               4
+
+#define HAS_I2C_1              0
+#define I2C_1_PB8_PB9          0
+
+#define HAS_I2C_2              0
+#define I2C_2_PB10_PB11                0
+
+#define PACKET_HAS_SLAVE       0
+#define PACKET_HAS_MASTER      0
+
+#define LOW_LEVEL_DEBUG                0
+
+#define HAS_GPS                        0
+#define HAS_FLIGHT             0
+#define HAS_ADC                        0
+#define HAS_ADC_TEMP           0
+#define HAS_LOG                        0
+
+#define NUM_CMDS               16
+
+/* SD card */
+#define AO_SDCARD_SPI_BUS      AO_SPI_2_PD1_PD3_PD4
+#define AO_SDCARD_SPI_CS_PORT  (&stm_gpiod)
+#define AO_SDCARD_SPI_CS_PIN   2
+#define AO_SDCARD_SPI_PORT     (&stm_gpiod)
+#define AO_SDCARD_SPI_SCK_PIN  1
+#define AO_SDCARD_SPI_MISO_PIN 3
+#define AO_SDCARD_SPI_MOSI_PIN 4
+
+/* VGA */
+#define STM_DMA1_3_STOLEN      1
+/* Buttons */
+
+#define AO_EVENT               1
+
+#define AO_BUTTON_COUNT                4
+#define AO_BUTTON_MODE         AO_EXTI_MODE_PULL_DOWN
+#define AO_BUTTON_INVERTED     0
+
+/* INPUT */
+#define AO_BUTTON_0_PORT       (&stm_gpioc)
+#define AO_BUTTON_0            8
+
+/* MP */
+#define AO_BUTTON_1_PORT       (&stm_gpioc)
+#define AO_BUTTON_1            9
+
+/* RUN */
+#define AO_BUTTON_2_PORT       (&stm_gpioc)
+#define AO_BUTTON_2            10
+
+/* LOAD */
+#define AO_BUTTON_3_PORT       (&stm_gpioc)
+#define AO_BUTTON_3            11
+
+/* AS1107 */
+#define AO_AS1107_NUM_DIGITS   8
+
+/* Set the hex digits up for decode, leave the extra leds alone */
+
+#define AO_AS1107_DECODE       ((1 << 7) |     \
+                                (1 << 6) |     \
+                                (1 << 4) |     \
+                                (1 << 3) |     \
+                                (1 << 1) |     \
+                                (1 << 0))
+
+#define AO_AS1107_SPI_INDEX    AO_SPI_2_PD1_PD3_PD4
+#define AO_AS1107_SPI_SPEED    AO_SPI_SPEED_8MHz
+#define AO_AS1107_CS_PORT      (&stm_gpiod)
+#define AO_AS1107_CS_PIN       0
+
+/* Hex keypad */
+
+#define AO_MATRIX_ROWS 4
+#define AO_MATRIX_COLS 4
+
+#define AO_MATRIX_KEYCODES {                   \
+               { 0x0, 0x1, 0x2, 0x3 },         \
+               { 0x4, 0x5, 0x6, 0x7 },         \
+               { 0x8, 0x9, 0xa, 0xb },         \
+               { 0xc, 0xd, 0xe, 0xf }          \
+       }
+
+#include <ao_matrix.h>
+
+#define AO_TIMER_HOOK  ao_matrix_poll()
+
+#define AO_MATRIX_ROW_0_PORT   (&stm_gpioc)
+#define AO_MATRIX_ROW_0_PIN    4
+
+#define AO_MATRIX_ROW_1_PORT   (&stm_gpioc)
+#define AO_MATRIX_ROW_1_PIN    1
+
+#define AO_MATRIX_ROW_2_PORT   (&stm_gpioc)
+#define AO_MATRIX_ROW_2_PIN    7
+
+#define AO_MATRIX_ROW_3_PORT   (&stm_gpioc)
+#define AO_MATRIX_ROW_3_PIN    0
+
+#define AO_MATRIX_COL_0_PORT   (&stm_gpioc)
+#define AO_MATRIX_COL_0_PIN    2
+
+#define AO_MATRIX_COL_1_PORT   (&stm_gpioc)
+#define AO_MATRIX_COL_1_PIN    3
+
+#define AO_MATRIX_COL_2_PORT   (&stm_gpioc)
+#define AO_MATRIX_COL_2_PIN    5
+
+#define AO_MATRIX_COL_3_PORT   (&stm_gpioc)
+#define AO_MATRIX_COL_3_PIN    6
+
+/* 1802 connections */
+#define MRD_PORT               (&stm_gpiob)
+#define MRD_BIT                        15
+
+#define MWR_PORT               (&stm_gpioa)
+#define MWR_BIT                        3
+
+#define TPB_PORT               (&stm_gpioa)
+#define TPB_BIT                        7
+
+#define TPA_PORT               (&stm_gpioa)
+#define TPA_BIT                        6
+
+#define MA_PORT                        (&stm_gpioe)
+#define MA_SHIFT               0
+#define MA_MASK                        0xff
+
+#define BUS_PORT               (&stm_gpioe)
+#define BUS_SHIFT              8
+#define BUS_MASK               0xff
+
+#define SC_PORT                        (&stm_gpiob)
+#define SC_SHIFT               13
+#define SC_MASK                        3
+
+#define Q_PORT                 (&stm_gpiob)
+#define Q_BIT                  12
+
+#define N_PORT                 (&stm_gpiod)
+#define N_SHIFT                        13
+#define N_MASK                 7
+
+#define EF_PORT                        (&stm_gpiob)
+#define EF_SHIFT               8
+#define EF_MASK                        0xf
+
+#define DMA_IN_PORT            (&stm_gpioa)
+#define DMA_IN_BIT             0
+
+#define DMA_OUT_PORT           (&stm_gpioa)
+#define DMA_OUT_BIT            9
+
+#define INT_PORT               (&stm_gpioa)
+#define INT_BIT                        2
+
+#define CLEAR_PORT             (&stm_gpioa)
+#define CLEAR_BIT              10
+
+#define WAIT_PORT              (&stm_gpioa)
+#define WAIT_BIT               4
+
+#define MUX_PORT               (&stm_gpiob)
+#define MUX_BIT                        1
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/cortexelf-v1/cortexelf.ld b/src/cortexelf-v1/cortexelf.ld
new file mode 100644 (file)
index 0000000..6ad2a67
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+MEMORY {
+       rom (rx) :      ORIGIN = 0x08001000, LENGTH = 492K
+       flash (r) :     ORIGIN = 0x0807c000, LENGTH = 16K
+       ram (!w) :      ORIGIN = 0x20000000, LENGTH = 81408
+       stack (!w) :    ORIGIN = 0x20013e00, LENGTH = 512
+}
+
+INCLUDE registers.ld
+
+EXTERN (stm_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .text ORIGIN(rom) : {
+               __text_start__ = .;
+               *(.interrupt)   /* Interrupt vectors */
+
+               . = ORIGIN(rom) + 0x100;
+
+
+               /* Ick. What I want is to specify the
+                * addresses of some global constants so
+                * that I can find them across versions
+                * of the application. I can't figure out
+                * how to make gnu ld do that, so instead
+                * we just load the two files that include
+                * these defines in the right order here and
+                * expect things to 'just work'. Don't change
+                * the contents of those files, ok?
+                */
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+               *(.text*)       /* Executable code */
+               *(.rodata*)     /* Constants */
+
+       } > rom
+
+       .ARM.exidx : {
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+       } > rom
+       __text_end__ = .;
+
+       /* Boot data which must live at the start of ram so that
+        * the application and bootloader share the same addresses.
+        * This must be all uninitialized data
+        */
+       .boot (NOLOAD) : {
+               __boot_start__ = .;
+               *(.boot)
+               . = ALIGN(4);
+               __boot_end__ = .;
+       } >ram
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data : {
+               __data_start__ = .;
+               *(.data)        /* initialized data */
+               . = ALIGN(4);
+               __data_end__ = .;
+       } >ram AT>rom
+
+       .bss : {
+               __bss_start__ = .;
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4);
+               __bss_end__ = .;
+       } >ram
+
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+
+       __flash__ = ORIGIN(flash);
+}
+
+ENTRY(start);
+
+
diff --git a/src/cortexelf-v1/flash-loader/Makefile b/src/cortexelf-v1/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..19cf84e
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=cortexelf-v1
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/cortexelf-v1/flash-loader/ao_pins.h b/src/cortexelf-v1/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..5d63dc2
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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_
+
+/* External crystal at 8MHz */
+#define AO_HSE         8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* MP switch, gpioc 9 */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioc
+#define AO_BOOT_APPLICATION_PIN                9
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       0
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/draw/5x7.bdf b/src/draw/5x7.bdf
new file mode 100644 (file)
index 0000000..b511f28
--- /dev/null
@@ -0,0 +1,3190 @@
+STARTFONT 2.1
+COMMENT  Copyright 1991 Massachusetts Institute of Technology
+COMMENT  
+COMMENT  Permission to use, copy, modify, and distribute this software
+COMMENT  and its documentation for any purpose and without fee is
+COMMENT  hereby granted, provided that the above copyright notice
+COMMENT  appear in all copies and that both that copyright notice and
+COMMENT  this permission notice appear in supporting documentation,
+COMMENT  and that the name of M.I.T. not be used in advertising or
+COMMENT  publicity pertaining to distribution of the software without
+COMMENT  specific, written prior permission.  M.I.T. makes no
+COMMENT  representations about the suitability of this software for
+COMMENT  any purpose.  It is provided "as is" without express or
+COMMENT  implied warranty.
+COMMENT  
+COMMENT  M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+COMMENT  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+COMMENT  FITNESS, IN NO EVENT SHALL M.I.T.  BE LIABLE FOR ANY SPECIAL,
+COMMENT  INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+COMMENT  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+COMMENT  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+COMMENT  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+COMMENT  OF THIS SOFTWARE.
+COMMENT  
+COMMENT  Author:  Stephen Gildea, MIT X Consortium, June 1991
+COMMENT  
+FONT -Misc-Fixed-Medium-R-Normal--7-70-75-75-C-50-ISO8859-1
+SIZE 7 75 75
+FONTBOUNDINGBOX 5 7 0 -1
+STARTPROPERTIES 21
+FONTNAME_REGISTRY ""
+FOUNDRY "Misc"
+FAMILY_NAME "Fixed"
+WEIGHT_NAME "Medium"
+SLANT "R"
+SETWIDTH_NAME "Normal"
+ADD_STYLE_NAME ""
+PIXEL_SIZE 7
+POINT_SIZE 70
+RESOLUTION_X 75
+RESOLUTION_Y 75
+SPACING "C"
+AVERAGE_WIDTH 50
+CHARSET_REGISTRY "ISO8859"
+CHARSET_ENCODING "1"
+FONT_ASCENT 6
+FONT_DESCENT 1
+UNDERLINE_POSITION 0
+DESTINATION 1
+DEFAULT_CHAR 0
+COPYRIGHT "Copyright 1991 Massachusetts Institute of Technology"
+ENDPROPERTIES
+CHARS 224
+STARTCHAR C000
+ENCODING 0
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+f0
+f0
+f0
+f0
+f0
+00
+ENDCHAR
+STARTCHAR C001
+ENCODING 1
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+70
+f8
+70
+20
+00
+ENDCHAR
+STARTCHAR C002
+ENCODING 2
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+50
+a0
+50
+a0
+00
+ENDCHAR
+STARTCHAR C003
+ENCODING 3
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+e0
+a0
+a0
+70
+20
+20
+ENDCHAR
+STARTCHAR C004
+ENCODING 4
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+80
+c0
+b0
+20
+30
+20
+ENDCHAR
+STARTCHAR C005
+ENCODING 5
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+80
+c0
+60
+50
+60
+50
+ENDCHAR
+STARTCHAR C006
+ENCODING 6
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+c0
+30
+20
+30
+20
+ENDCHAR
+STARTCHAR C007
+ENCODING 7
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+20
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C010
+ENCODING 8
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+70
+20
+00
+70
+00
+00
+ENDCHAR
+STARTCHAR C011
+ENCODING 9
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+d0
+b0
+90
+20
+20
+30
+ENDCHAR
+STARTCHAR C012
+ENCODING 10
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+a0
+40
+70
+20
+20
+ENDCHAR
+STARTCHAR C013
+ENCODING 11
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+e0
+00
+00
+00
+ENDCHAR
+STARTCHAR C014
+ENCODING 12
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+e0
+20
+20
+20
+ENDCHAR
+STARTCHAR C015
+ENCODING 13
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+38
+20
+20
+20
+ENDCHAR
+STARTCHAR C016
+ENCODING 14
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+38
+00
+00
+00
+ENDCHAR
+STARTCHAR C017
+ENCODING 15
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+f8
+20
+20
+20
+ENDCHAR
+STARTCHAR C020
+ENCODING 16
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+f8
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C021
+ENCODING 17
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+00
+00
+f8
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C022
+ENCODING 18
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f8
+00
+00
+00
+ENDCHAR
+STARTCHAR C023
+ENCODING 19
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+f8
+00
+00
+ENDCHAR
+STARTCHAR C024
+ENCODING 20
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+f8
+00
+ENDCHAR
+STARTCHAR C025
+ENCODING 21
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+38
+20
+20
+20
+ENDCHAR
+STARTCHAR C026
+ENCODING 22
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+e0
+20
+20
+20
+ENDCHAR
+STARTCHAR C027
+ENCODING 23
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+20
+20
+20
+f8
+00
+00
+00
+ENDCHAR
+STARTCHAR C030
+ENCODING 24
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f8
+20
+20
+20
+ENDCHAR
+STARTCHAR C031
+ENCODING 25
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+20
+20
+20
+20
+ENDCHAR
+STARTCHAR C032
+ENCODING 26
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+10
+20
+40
+20
+10
+70
+00
+ENDCHAR
+STARTCHAR C033
+ENCODING 27
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+10
+20
+40
+70
+00
+ENDCHAR
+STARTCHAR C034
+ENCODING 28
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+50
+50
+50
+00
+ENDCHAR
+STARTCHAR C035
+ENCODING 29
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+10
+70
+20
+70
+40
+00
+ENDCHAR
+STARTCHAR C036
+ENCODING 30
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+30
+40
+e0
+40
+b0
+00
+ENDCHAR
+STARTCHAR C037
+ENCODING 31
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+20
+00
+00
+00
+ENDCHAR
+STARTCHAR C040
+ENCODING 32
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR !
+ENCODING 33
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+20
+00
+20
+00
+ENDCHAR
+STARTCHAR "
+ENCODING 34
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+50
+50
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR #
+ENCODING 35
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+50
+f8
+50
+f8
+50
+00
+ENDCHAR
+STARTCHAR $
+ENCODING 36
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+70
+a0
+70
+28
+70
+00
+ENDCHAR
+STARTCHAR %
+ENCODING 37
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+90
+20
+40
+90
+10
+00
+ENDCHAR
+STARTCHAR &
+ENCODING 38
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+40
+a0
+40
+a0
+50
+00
+ENDCHAR
+STARTCHAR '
+ENCODING 39
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+40
+80
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR (
+ENCODING 40
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+40
+40
+40
+20
+00
+ENDCHAR
+STARTCHAR )
+ENCODING 41
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+20
+20
+20
+40
+00
+ENDCHAR
+STARTCHAR *
+ENCODING 42
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+a0
+40
+e0
+40
+a0
+00
+ENDCHAR
+STARTCHAR +
+ENCODING 43
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+20
+f8
+20
+20
+00
+ENDCHAR
+STARTCHAR ,
+ENCODING 44
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+60
+40
+80
+ENDCHAR
+STARTCHAR -
+ENCODING 45
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f0
+00
+00
+00
+ENDCHAR
+STARTCHAR .
+ENCODING 46
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+60
+60
+00
+ENDCHAR
+STARTCHAR /
+ENCODING 47
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+10
+20
+40
+80
+00
+00
+ENDCHAR
+STARTCHAR 0
+ENCODING 48
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+a0
+a0
+a0
+40
+00
+ENDCHAR
+STARTCHAR 1
+ENCODING 49
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+c0
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR 2
+ENCODING 50
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+10
+20
+40
+f0
+00
+ENDCHAR
+STARTCHAR 3
+ENCODING 51
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+10
+60
+10
+90
+60
+00
+ENDCHAR
+STARTCHAR 4
+ENCODING 52
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+60
+a0
+f0
+20
+20
+00
+ENDCHAR
+STARTCHAR 5
+ENCODING 53
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+10
+90
+60
+00
+ENDCHAR
+STARTCHAR 6
+ENCODING 54
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+80
+e0
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR 7
+ENCODING 55
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+10
+20
+20
+40
+40
+00
+ENDCHAR
+STARTCHAR 8
+ENCODING 56
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR 9
+ENCODING 57
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+70
+10
+60
+00
+ENDCHAR
+STARTCHAR :
+ENCODING 58
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+60
+00
+60
+60
+00
+ENDCHAR
+STARTCHAR ;
+ENCODING 59
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+60
+00
+60
+40
+80
+ENDCHAR
+STARTCHAR <
+ENCODING 60
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+40
+80
+40
+20
+00
+ENDCHAR
+STARTCHAR =
+ENCODING 61
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+f0
+00
+f0
+00
+00
+ENDCHAR
+STARTCHAR >
+ENCODING 62
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+80
+40
+20
+40
+80
+00
+ENDCHAR
+STARTCHAR ?
+ENCODING 63
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+20
+40
+00
+40
+00
+ENDCHAR
+STARTCHAR @
+ENCODING 64
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+b0
+b0
+80
+60
+00
+ENDCHAR
+STARTCHAR A
+ENCODING 65
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR B
+ENCODING 66
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+e0
+90
+90
+e0
+00
+ENDCHAR
+STARTCHAR C
+ENCODING 67
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+80
+80
+90
+60
+00
+ENDCHAR
+STARTCHAR D
+ENCODING 68
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+90
+90
+90
+e0
+00
+ENDCHAR
+STARTCHAR E
+ENCODING 69
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR F
+ENCODING 70
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+80
+00
+ENDCHAR
+STARTCHAR G
+ENCODING 71
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+80
+b0
+90
+70
+00
+ENDCHAR
+STARTCHAR H
+ENCODING 72
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+f0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR I
+ENCODING 73
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR J
+ENCODING 74
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+10
+10
+10
+10
+90
+60
+00
+ENDCHAR
+STARTCHAR K
+ENCODING 75
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+a0
+c0
+c0
+a0
+90
+00
+ENDCHAR
+STARTCHAR L
+ENCODING 76
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+80
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR M
+ENCODING 77
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+f0
+f0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR N
+ENCODING 78
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+d0
+d0
+b0
+b0
+90
+00
+ENDCHAR
+STARTCHAR O
+ENCODING 79
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR P
+ENCODING 80
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+90
+e0
+80
+80
+00
+ENDCHAR
+STARTCHAR Q
+ENCODING 81
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+d0
+60
+10
+ENDCHAR
+STARTCHAR R
+ENCODING 82
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+90
+e0
+a0
+90
+00
+ENDCHAR
+STARTCHAR S
+ENCODING 83
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+40
+20
+90
+60
+00
+ENDCHAR
+STARTCHAR T
+ENCODING 84
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR U
+ENCODING 85
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR V
+ENCODING 86
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+60
+60
+00
+ENDCHAR
+STARTCHAR W
+ENCODING 87
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+f0
+f0
+90
+00
+ENDCHAR
+STARTCHAR X
+ENCODING 88
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+60
+60
+90
+90
+00
+ENDCHAR
+STARTCHAR Y
+ENCODING 89
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+a0
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR Z
+ENCODING 90
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+10
+20
+40
+80
+f0
+00
+ENDCHAR
+STARTCHAR [
+ENCODING 91
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+80
+80
+80
+80
+e0
+00
+ENDCHAR
+STARTCHAR \
+ENCODING 92
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+80
+40
+20
+10
+00
+00
+ENDCHAR
+STARTCHAR ]
+ENCODING 93
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+20
+20
+20
+20
+e0
+00
+ENDCHAR
+STARTCHAR ^
+ENCODING 94
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR _
+ENCODING 95
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+f0
+00
+ENDCHAR
+STARTCHAR `
+ENCODING 96
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+40
+20
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR a
+ENCODING 97
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR b
+ENCODING 98
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+e0
+90
+90
+e0
+00
+ENDCHAR
+STARTCHAR c
+ENCODING 99
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+80
+80
+60
+00
+ENDCHAR
+STARTCHAR d
+ENCODING 100
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+10
+10
+70
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR e
+ENCODING 101
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR f
+ENCODING 102
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+40
+e0
+40
+40
+00
+ENDCHAR
+STARTCHAR g
+ENCODING 103
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+90
+60
+80
+70
+ENDCHAR
+STARTCHAR h
+ENCODING 104
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+e0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR i
+ENCODING 105
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+00
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR j
+ENCODING 106
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+00
+20
+20
+20
+a0
+40
+ENDCHAR
+STARTCHAR k
+ENCODING 107
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+a0
+c0
+a0
+90
+00
+ENDCHAR
+STARTCHAR l
+ENCODING 108
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR m
+ENCODING 109
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+a0
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR n
+ENCODING 110
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+e0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR o
+ENCODING 111
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR p
+ENCODING 112
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+e0
+90
+90
+e0
+80
+ENDCHAR
+STARTCHAR q
+ENCODING 113
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+90
+90
+70
+10
+ENDCHAR
+STARTCHAR r
+ENCODING 114
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+e0
+90
+80
+80
+00
+ENDCHAR
+STARTCHAR s
+ENCODING 115
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+00
+00
+70
+c0
+30
+e0
+00
+ENDCHAR
+STARTCHAR t
+ENCODING 116
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+40
+e0
+40
+40
+30
+00
+ENDCHAR
+STARTCHAR u
+ENCODING 117
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR v
+ENCODING 118
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+a0
+a0
+a0
+40
+00
+ENDCHAR
+STARTCHAR w
+ENCODING 119
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+f0
+f0
+00
+ENDCHAR
+STARTCHAR x
+ENCODING 120
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+60
+60
+90
+00
+ENDCHAR
+STARTCHAR y
+ENCODING 121
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+50
+20
+40
+ENDCHAR
+STARTCHAR z
+ENCODING 122
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+f0
+20
+40
+f0
+00
+ENDCHAR
+STARTCHAR {
+ENCODING 123
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+c0
+40
+40
+20
+00
+ENDCHAR
+STARTCHAR |
+ENCODING 124
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+40
+40
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR }
+ENCODING 125
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+80
+40
+60
+40
+40
+80
+00
+ENDCHAR
+STARTCHAR ~
+ENCODING 126
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR Blank
+ENCODING 127
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C160
+ENCODING 160
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C161
+ENCODING 161
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+00
+20
+20
+20
+20
+00
+ENDCHAR
+STARTCHAR C162
+ENCODING 162
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+70
+a0
+a0
+70
+20
+ENDCHAR
+STARTCHAR C163
+ENCODING 163
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+30
+40
+e0
+40
+b0
+00
+ENDCHAR
+STARTCHAR C164
+ENCODING 164
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+88
+70
+50
+70
+88
+00
+ENDCHAR
+STARTCHAR C165
+ENCODING 165
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+40
+e0
+40
+40
+00
+ENDCHAR
+STARTCHAR C166
+ENCODING 166
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+20
+00
+20
+20
+00
+ENDCHAR
+STARTCHAR C167
+ENCODING 167
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+30
+40
+60
+50
+30
+10
+60
+ENDCHAR
+STARTCHAR C168
+ENCODING 168
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C169
+ENCODING 169
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+88
+a8
+c8
+a8
+88
+70
+ENDCHAR
+STARTCHAR C170
+ENCODING 170
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+a0
+60
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C171
+ENCODING 171
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+48
+90
+48
+00
+00
+ENDCHAR
+STARTCHAR C172
+ENCODING 172
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+f0
+10
+00
+00
+00
+ENDCHAR
+STARTCHAR C173
+ENCODING 173
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f0
+00
+00
+00
+ENDCHAR
+STARTCHAR C174
+ENCODING 174
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+88
+e8
+c8
+c8
+88
+70
+ENDCHAR
+STARTCHAR C175
+ENCODING 175
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C176
+ENCODING 176
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+20
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C177
+ENCODING 177
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+f8
+20
+20
+f8
+00
+ENDCHAR
+STARTCHAR C178
+ENCODING 178
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+20
+40
+60
+00
+00
+00
+ENDCHAR
+STARTCHAR C179
+ENCODING 179
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+60
+20
+60
+00
+00
+00
+ENDCHAR
+STARTCHAR C180
+ENCODING 180
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C181
+ENCODING 181
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+90
+e0
+80
+ENDCHAR
+STARTCHAR C182
+ENCODING 182
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+d0
+d0
+50
+50
+50
+00
+ENDCHAR
+STARTCHAR C183
+ENCODING 183
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+60
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C184
+ENCODING 184
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+20
+40
+ENDCHAR
+STARTCHAR C185
+ENCODING 185
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+60
+20
+70
+00
+00
+00
+ENDCHAR
+STARTCHAR C186
+ENCODING 186
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+40
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C187
+ENCODING 187
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+48
+90
+00
+00
+ENDCHAR
+STARTCHAR C188
+ENCODING 188
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+80
+90
+30
+70
+10
+ENDCHAR
+STARTCHAR C189
+ENCODING 189
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+80
+b0
+10
+20
+30
+ENDCHAR
+STARTCHAR C190
+ENCODING 190
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+c0
+40
+d0
+30
+70
+10
+ENDCHAR
+STARTCHAR C191
+ENCODING 191
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+00
+40
+80
+a0
+40
+00
+ENDCHAR
+STARTCHAR Agrave
+ENCODING 192
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C193
+ENCODING 193
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C194
+ENCODING 194
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C195
+ENCODING 195
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C196
+ENCODING 196
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C197
+ENCODING 197
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C198
+ENCODING 198
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+a0
+b0
+e0
+a0
+b0
+00
+ENDCHAR
+STARTCHAR C199
+ENCODING 199
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+80
+80
+90
+60
+40
+ENDCHAR
+STARTCHAR Egrave
+ENCODING 200
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C201
+ENCODING 201
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C202
+ENCODING 202
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C203
+ENCODING 203
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C204
+ENCODING 204
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C205
+ENCODING 205
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C206
+ENCODING 206
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C207
+ENCODING 207
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C208
+ENCODING 208
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+50
+d0
+50
+50
+e0
+00
+ENDCHAR
+STARTCHAR C209
+ENCODING 209
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+b0
+90
+d0
+b0
+b0
+90
+00
+ENDCHAR
+STARTCHAR Ograve
+ENCODING 210
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C211
+ENCODING 211
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C212
+ENCODING 212
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C213
+ENCODING 213
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C214
+ENCODING 214
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C215
+ENCODING 215
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+60
+60
+90
+00
+ENDCHAR
+STARTCHAR C216
+ENCODING 216
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+b0
+b0
+d0
+d0
+e0
+00
+ENDCHAR
+STARTCHAR Ugrave
+ENCODING 217
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C218
+ENCODING 218
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C219
+ENCODING 219
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C220
+ENCODING 220
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C221
+ENCODING 221
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+a0
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR C222
+ENCODING 222
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+e0
+90
+e0
+80
+80
+00
+ENDCHAR
+STARTCHAR C223
+ENCODING 223
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+e0
+90
+d0
+a0
+80
+ENDCHAR
+STARTCHAR a-grave
+ENCODING 224
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C225
+ENCODING 225
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C226
+ENCODING 226
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C227
+ENCODING 227
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C228
+ENCODING 228
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C229
+ENCODING 229
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+60
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C230
+ENCODING 230
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+b0
+a0
+70
+00
+ENDCHAR
+STARTCHAR C231
+ENCODING 231
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+80
+80
+60
+40
+ENDCHAR
+STARTCHAR e-grave
+ENCODING 232
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C233
+ENCODING 233
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C234
+ENCODING 234
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C235
+ENCODING 235
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+00
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C236
+ENCODING 236
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+40
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C237
+ENCODING 237
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+80
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C238
+ENCODING 238
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C239
+ENCODING 239
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+00
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C240
+ENCODING 240
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+30
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C241
+ENCODING 241
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+e0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR C242
+ENCODING 242
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C243
+ENCODING 243
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C244
+ENCODING 244
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+00
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C245
+ENCODING 245
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C246
+ENCODING 246
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+00
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C247
+ENCODING 247
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+00
+f0
+00
+60
+00
+ENDCHAR
+STARTCHAR C248
+ENCODING 248
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+b0
+d0
+e0
+00
+ENDCHAR
+STARTCHAR C249
+ENCODING 249
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C250
+ENCODING 250
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C251
+ENCODING 251
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+00
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C252
+ENCODING 252
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C253
+ENCODING 253
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+90
+90
+50
+20
+40
+ENDCHAR
+STARTCHAR C254
+ENCODING 254
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+80
+e0
+90
+90
+e0
+80
+ENDCHAR
+STARTCHAR C255
+ENCODING 255
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+90
+90
+50
+20
+40
+ENDCHAR
+ENDFONT
diff --git a/src/draw/Makefile b/src/draw/Makefile
new file mode 100644 (file)
index 0000000..0a542a1
--- /dev/null
@@ -0,0 +1,4 @@
+BDF=5x7.bdf
+
+ao_font.h: font-convert $(BDF)
+       nickle font-convert $(BDF) > $@
diff --git a/src/draw/ao_blt.c b/src/draw/ao_blt.c
new file mode 100644 (file)
index 0000000..e3f4522
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * 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_draw.h"
+#include "ao_draw_int.h"
+
+#define O 0
+#define I AO_ALLONES
+
+struct ao_merge_rop {
+       uint32_t        ca1, cx1, ca2, cx2;
+};
+
+const struct ao_merge_rop ao_merge_rop[16] = {
+    {O, O, O, O},               /* clear         0x0         0 */
+    {I, O, O, O},               /* and           0x1         src AND dst */
+    {I, O, I, O},               /* andReverse    0x2         src AND NOT dst */
+    {O, O, I, O},               /* copy          0x3         src */
+    {I, I, O, O},               /* andInverted   0x4         NOT src AND dst */
+    {O, I, O, O},               /* noop          0x5         dst */
+    {O, I, I, O},               /* xor           0x6         src XOR dst */
+    {I, I, I, O},               /* or            0x7         src OR dst */
+    {I, I, I, I},               /* nor           0x8         NOT src AND NOT dst */
+    {O, I, I, I},               /* equiv         0x9         NOT src XOR dst */
+    {O, I, O, I},               /* invert        0xa         NOT dst */
+    {I, I, O, I},               /* orReverse     0xb         src OR NOT dst */
+    {O, O, I, I},               /* copyInverted  0xc         NOT src */
+    {I, O, I, I},               /* orInverted    0xd         NOT src OR dst */
+    {I, O, O, I},               /* nand          0xe         NOT src OR NOT dst */
+    {O, O, O, I},               /* set           0xf         1 */
+};
+
+#define ao_do_merge_rop(src, dst) \
+    (((dst) & (((src) & _ca1) ^ _cx1)) ^ (((src) & _ca2) ^ _cx2))
+
+#define ao_do_dst_invarient_merge_rop(src)     (((src) & _ca2) ^ _cx2)
+
+#define ao_do_mask_merge_rop(src, dst, mask) \
+    (((dst) & ((((src) & _ca1) ^ _cx1) | ~(mask))) ^ ((((src) & _ca2) ^ _cx2) & (mask)))
+
+#define ao_dst_invarient_merge_rop()   (_ca1 == 0 && _cx1 == 0)
+
+void
+ao_blt(uint32_t                *src_line,
+       int16_t         src_stride,
+       int16_t         src_x,
+       uint32_t                *dst_line,
+       int16_t         dst_stride,
+       int16_t         dst_x,
+       int16_t         width,
+       int16_t         height,
+       uint8_t         rop,
+       uint8_t         reverse,
+       uint8_t         upsidedown)
+{
+       uint32_t        *src, *dst;
+       uint32_t        _ca1, _cx1, _ca2, _cx2;
+       uint8_t         dst_invarient;
+       uint32_t        startmask, endmask;
+       int16_t         nmiddle, n;
+       uint32_t        bits1, bits;
+       int16_t         left_shift, right_shift;
+
+       _ca1 = ao_merge_rop[rop].ca1;
+       _cx1 = ao_merge_rop[rop].cx1;
+       _ca2 = ao_merge_rop[rop].ca2;
+       _cx2 = ao_merge_rop[rop].cx2;
+       dst_invarient = ao_dst_invarient_merge_rop();
+
+       if (upsidedown) {
+               src_line += (height - 1) * src_stride;
+               dst_line += (height - 1) * dst_stride;
+               src_stride = -src_stride;
+               dst_stride = -dst_stride;
+       }
+
+       ao_mask_bits(dst_x, width, startmask, nmiddle, endmask);
+       if (reverse) {
+               src_line += ((src_x + width - 1) >> AO_SHIFT) + 1;
+               dst_line += ((dst_x + width - 1) >> AO_SHIFT) + 1;
+               src_x = (src_x + width - 1) & AO_MASK;
+               dst_x = (dst_x + width - 1) & AO_MASK;
+       } else {
+               src_line += src_x >> AO_SHIFT;
+               dst_line += dst_x >> AO_SHIFT;
+               src_x &= AO_MASK;
+               dst_x &= AO_MASK;
+       }
+       if (src_x == dst_x) {
+               while (height--) {
+                       src = src_line;
+                       src_line += src_stride;
+                       dst = dst_line;
+                       dst_line += dst_stride;
+                       if (reverse) {
+                               if (endmask) {
+                                       bits = *--src;
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--)
+                                               *--dst = ao_do_dst_invarient_merge_rop(*--src);
+                               }
+                               else {
+                                       while (n--) {
+                                               bits = *--src;
+                                               --dst;
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                       }
+                               }
+                               if (startmask) {
+                                       bits = *--src;
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                               }
+                       }
+                       else {
+                               if (startmask) {
+                                       bits = *src++;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                                       dst++;
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--)
+                                               *dst++ = ao_do_dst_invarient_merge_rop(*src++);
+                               }
+                               else {
+                                       while (n--) {
+                                               bits = *src++;
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                               dst++;
+                                       }
+                               }
+                               if (endmask) {
+                                       bits = *src;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                       }
+               }
+       } else {
+               if (src_x > dst_x) {
+                       left_shift = src_x - dst_x;
+                       right_shift = AO_UNIT - left_shift;
+               } else {
+                       right_shift = dst_x - src_x;
+                       left_shift = AO_UNIT - right_shift;
+               }
+               while (height--) {
+                       src = src_line;
+                       src_line += src_stride;
+                       dst = dst_line;
+                       dst_line += dst_stride;
+
+                       bits1 = 0;
+                       if (reverse) {
+                               if (src_x < dst_x)
+                                       bits1 = *--src;
+                               if (endmask) {
+                                       bits = ao_right(bits1, right_shift);
+                                       if (ao_right(endmask, left_shift)) {
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                       }
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--) {
+                                               bits = ao_right(bits1, right_shift);
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                               --dst;
+                                               *dst = ao_do_dst_invarient_merge_rop(bits);
+                                       }
+                               } else {
+                                       while (n--) {
+                                               bits = ao_right(bits1, right_shift);
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                               --dst;
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                       }
+                               }
+                               if (startmask) {
+                                       bits = ao_right(bits1, right_shift);
+                                       if (ao_right(startmask, left_shift)) {
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                       }
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                               }
+                       }
+                       else {
+                               if (src_x > dst_x)
+                                       bits1 = *src++;
+                               if (startmask) {
+                                       bits = ao_left(bits1, left_shift);
+                                       if (ao_left(startmask, right_shift)) {
+                                               bits1 = *src++;
+                                               bits |= ao_right(bits1, right_shift);
+                                       }
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                                       dst++;
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--) {
+                                               bits = ao_left(bits1, left_shift);
+                                               bits1 = *src++;
+                                               bits |= ao_right(bits1, right_shift);
+                                               *dst = ao_do_dst_invarient_merge_rop(bits);
+                                               dst++;
+                                       }
+                               }
+                               else {
+                                       while (n--) {
+                                               bits = ao_left(bits1, left_shift);
+                                               bits1 = *src++;
+                                               bits |= ao_right(bits1, right_shift);
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                               dst++;
+                                       }
+                               }
+                               if (endmask) {
+                                       bits = ao_left(bits1, left_shift);
+                                       if (ao_left(endmask, right_shift)) {
+                                               bits1 = *src;
+                                               bits |= ao_right(bits1, right_shift);
+                                       }
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                       }
+               }
+       }
+}
+
+void
+ao_solid(uint32_t      and,
+        uint32_t       xor,
+        uint32_t       *dst,
+        int16_t        dst_stride,
+        int16_t        dst_x,
+        int16_t        width,
+        int16_t        height)
+{
+       uint32_t        startmask, endmask;
+       int16_t         nmiddle;
+       int16_t         n;
+
+       dst += dst_x >> AO_SHIFT;
+       dst_x &= AO_MASK;
+
+       ao_mask_bits(dst_x, width, startmask, nmiddle, endmask);
+
+       if (startmask)
+               dst_stride--;
+
+       dst_stride -= nmiddle;
+       while (height--) {
+               if (startmask) {
+                       *dst = ao_do_mask_rrop(*dst, and, xor, startmask);
+                       dst++;
+               }
+               n = nmiddle;
+               if (!and)
+                       while (n--)
+                               *dst++ = xor;
+               else
+                       while (n--) {
+                               *dst = ao_do_rrop(*dst, and, xor);
+                               dst++;
+                       }
+               if (endmask)
+                       *dst = ao_do_mask_rrop(*dst, and, xor, endmask);
+               dst += dst_stride;
+       }
+}
diff --git a/src/draw/ao_copy.c b/src/draw/ao_copy.c
new file mode 100644 (file)
index 0000000..47067bb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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_draw.h"
+#include "ao_draw_int.h"
+
+#define bound(val,max,other) do {              \
+               if (val < 0) {                  \
+                       other -= val;           \
+                       val = 0;                \
+               }                               \
+               if (val > max) {                \
+                       other -= (val - max);   \
+                       val = max;              \
+               }                               \
+       } while (0)
+
+#define bound2(a, max_a, b, max_b) do {                \
+               bound(a, max_a, b);             \
+               bound(b, max_b, a);             \
+       } while (0)
+
+void
+ao_copy(const struct ao_bitmap *dst,
+       int16_t                 dst_x,
+       int16_t                 dst_y,
+       int16_t                 width,
+       int16_t                 height,
+       const struct ao_bitmap  *src,
+       int16_t                 src_x,
+       int16_t                 src_y,
+       uint8_t                 rop)
+{
+       int16_t         dst_x2 = dst_x + width, dst_y2 = dst_y + height;
+       int16_t         src_x2 = src_x + width, src_y2 = src_y + height;
+       uint8_t         reverse = 0;
+       uint8_t         upsidedown = 0;
+
+       bound2(dst_x, dst->width, src_x, src->width);
+       bound2(dst_x2, dst->width, src_x2, src->width);
+       bound2(dst_y, dst->height, src_y, src->height);
+       bound2(dst_y2, dst->height, src_y2, src->height);
+
+       if (dst == src) {
+               reverse = (dst_x > src_x);
+               upsidedown = (dst_y > src_y);
+       }
+
+       if (dst_x < dst_x2 && dst_y < dst_y2) {
+               ao_blt(src->base + src_y * src->stride,
+                      src->stride,
+                      src_x,
+                      dst->base + dst_y * dst->stride,
+                      dst->stride,
+                      dst_x,
+                      dst_x2 - dst_x,
+                      dst_y2 - dst_y,
+                      rop,
+                      reverse,
+                      upsidedown);
+       }
+}
+
diff --git a/src/draw/ao_draw.h b/src/draw/ao_draw.h
new file mode 100644 (file)
index 0000000..92150fc
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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_DRAW_H_
+#define _AO_DRAW_H_
+
+struct ao_bitmap {
+       uint32_t        *base;
+       int16_t         stride; /* in units */
+       int16_t         width;  /* in pixels */
+       int16_t         height; /* in pixels */
+};
+
+struct ao_pattern {
+       uint8_t         pattern[8];
+};
+
+void
+ao_copy(const struct ao_bitmap *dst,
+       int16_t                 dst_x,
+       int16_t                 dst_y,
+       int16_t                 width,
+       int16_t                 height,
+       const struct ao_bitmap  *src,
+       int16_t                 src_x,
+       int16_t                 src_y,
+       uint8_t                 rop);
+
+void
+ao_rect(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       int16_t                 width,
+       int16_t                 height,
+       uint32_t                fill,
+       uint8_t                 rop);
+
+void
+ao_pattern(const struct ao_bitmap      *dst,
+          int16_t                      x,
+          int16_t                      y,
+          int16_t                      width,
+          int16_t                      height,
+          const struct ao_pattern      *pattern,
+          int16_t                      pat_x,
+          int16_t                      pat_y,
+          uint8_t                      rop);
+
+void
+ao_line(const struct ao_bitmap *dst,
+       int16_t                 x1,
+       int16_t                 y1,
+       int16_t                 x2,
+       int16_t                 y2,
+       uint32_t                fill,
+       uint8_t                 rop);
+
+void
+ao_text(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       char                    *string,
+       uint32_t                fill,
+       uint8_t                 rop);
+
+struct ao_font {
+       int     width;
+       int     height;
+       int     ascent;
+       int     descent;
+};
+
+extern const struct ao_font ao_font;
+
+#define AO_SHIFT       5
+#define AO_UNIT                (1 << AO_SHIFT)
+#define AO_MASK                (AO_UNIT - 1)
+#define AO_ALLONES     ((uint32_t) -1)
+
+/*
+ *         dst
+ *        0   1
+ *
+ *     0  a   b
+ *  src
+ *     1  c   d
+ *
+ *     ROP = abcd
+ */
+
+#define AO_CLEAR         0x0   /* 0 */
+#define AO_AND           0x1   /* src AND dst */
+#define AO_AND_REVERSE   0x2   /* src AND NOT dst */
+#define AO_COPY          0x3   /* src */
+#define AO_AND_INVERTED  0x4   /* NOT src AND dst */
+#define AO_NOOP          0x5   /* dst */
+#define AO_XOR           0x6   /* src XOR dst */
+#define AO_OR            0x7   /* src OR dst */
+#define AO_NOR           0x8   /* NOT src AND NOT dst */
+#define AO_EQUIV         0x9   /* NOT src XOR dst */
+#define AO_INVERT        0xa   /* NOT dst */
+#define AO_OR_REVERSE    0xb   /* src OR NOT dst */
+#define AO_COPY_INVERTED 0xc   /* NOT src */
+#define AO_OR_INVERTED   0xd   /* NOT src OR dst */
+#define AO_NAND          0xe   /* NOT src OR NOT dst */
+#define AO_SET           0xf   /* 1 */
+
+#endif /* _AO_DRAW_H_ */
diff --git a/src/draw/ao_draw_int.h b/src/draw/ao_draw_int.h
new file mode 100644 (file)
index 0000000..433aa40
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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_DRAW_INT_H_
+#define _AO_DRAW_INT_H_
+
+static inline uint32_t
+ao_expand(uint32_t bits)
+{
+       return ~((bits & 1)-1);
+}
+
+static inline uint32_t
+ao_xor(uint8_t rop, uint32_t fg)
+{
+       fg = ao_expand(fg);
+
+       return (fg & ao_expand(rop >> 1)) |
+               (~fg & ao_expand(rop >> 3));
+}
+
+static inline uint32_t
+ao_and(uint8_t rop, uint32_t fg)
+{
+       fg = ao_expand(fg);
+
+       return (fg & ao_expand(rop ^ (rop >> 1))) |
+               (~fg & ao_expand((rop>>2) ^ (rop>>3)));
+}
+
+static inline uint32_t
+ao_left(uint32_t bits, int16_t shift) {
+       return bits >> shift;
+}
+
+static inline uint32_t
+ao_right(uint32_t bits, int16_t shift) {
+       return bits << shift;
+}
+
+static inline uint32_t
+ao_right_mask(int16_t x) {
+       if ((AO_UNIT - x) & AO_MASK)
+               return ao_left(AO_ALLONES,(AO_UNIT - x) & AO_MASK);
+       else
+               return 0;
+}
+
+static inline uint32_t
+ao_left_mask(int16_t x) {
+       if (x & AO_MASK)
+               return ao_right(AO_ALLONES, x & AO_MASK);
+       else
+               return 0;
+}
+
+static inline uint32_t
+ao_bits_mask(int16_t x, int16_t w) {
+       return ao_right(AO_ALLONES, x & AO_MASK) &
+               ao_left(AO_ALLONES,(AO_UNIT - (x + w)) & AO_MASK);
+}
+
+#define ao_mask_bits(x,w,l,n,r) { \
+    n = (w); \
+    r = ao_right_mask((x)+n); \
+    l = ao_left_mask(x); \
+    if (l) { \
+       n -= AO_UNIT - ((x) & AO_MASK); \
+       if (n < 0) { \
+           n = 0; \
+           l &= r; \
+           r = 0; \
+       } \
+    } \
+    n >>= AO_SHIFT; \
+}
+
+#define ao_clip(val,min,max) do {              \
+               if (val < min) {                \
+                       val = min;              \
+               } else if (val > max) {         \
+                       val = max;              \
+               }                               \
+       } while (0)
+
+static inline uint32_t
+ao_do_mask_rrop(uint32_t dst, uint32_t and, uint32_t xor, uint32_t mask) {
+       return (dst & (and | ~mask)) ^ (xor & mask);
+}
+
+static inline uint32_t
+ao_do_rrop(uint32_t dst, uint32_t and, uint32_t xor) {
+       return (dst & and) ^ xor;
+}
+
+void
+ao_blt(uint32_t                *src_line,
+       int16_t         src_stride,
+       int16_t         src_x,
+       uint32_t                *dst_line,
+       int16_t         dst_stride,
+       int16_t         dst_x,
+       int16_t         width,
+       int16_t         height,
+       uint8_t         rop,
+       uint8_t         reverse,
+       uint8_t         upsidedown);
+
+void
+ao_solid(uint32_t      and,
+        uint32_t       xor,
+        uint32_t       *dst,
+        int16_t        dst_stride,
+        int16_t        dst_x,
+        int16_t        width,
+        int16_t        height);
+
+int16_t
+ao_glyph(const struct ao_bitmap        *dst,
+        int16_t                x,
+        int16_t                y,
+        uint8_t                c,
+        uint8_t                rop);
+
+#endif /* _AO_DRAW_INT_H_ */
diff --git a/src/draw/ao_font.h b/src/draw/ao_font.h
new file mode 100644 (file)
index 0000000..5e31dd1
--- /dev/null
@@ -0,0 +1,139 @@
+static const uint8_t glyph_bytes[1568] = {
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x04, 0x0e, 0x1f, 0x0e, 0x04, 0x00, 0x0a, 0x05, 
+       0x0a, 0x05, 0x0a, 0x05, 0x00, 0x05, 0x07, 0x05, 0x05, 0x0e, 0x04, 0x04, 0x03, 0x01, 0x03, 0x0d, 
+       0x04, 0x0c, 0x04, 0x03, 0x01, 0x03, 0x06, 0x0a, 0x06, 0x0a, 0x01, 0x01, 0x03, 0x0c, 0x04, 0x0c, 
+       0x04, 0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0e, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x09, 
+       0x0b, 0x0d, 0x09, 0x04, 0x04, 0x0c, 0x05, 0x05, 0x05, 0x02, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 
+       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x04, 
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x04, 
+       0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x00, 0x1f, 0x00, 0x04, 0x04, 0x04, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 
+       0x04, 0x04, 0x04, 0x04, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, 
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x02, 0x04, 0x08, 0x0e, 0x00, 0x02, 0x04, 0x08, 
+       0x04, 0x02, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x0e, 0x04, 0x0e, 
+       0x02, 0x00, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x00, 0x0a, 0x0a, 
+       0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x00, 0x00, 0x0e, 0x05, 0x0e, 
+       0x14, 0x0e, 0x00, 0x01, 0x09, 0x04, 0x02, 0x09, 0x08, 0x00, 0x00, 0x02, 0x05, 0x02, 0x05, 0x0a, 
+       0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x02, 
+       0x04, 0x04, 0x04, 0x04, 0x02, 0x00, 0x00, 0x05, 0x02, 0x07, 0x02, 0x05, 0x00, 0x00, 0x04, 0x04, 
+       0x1f, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 
+       0x02, 0x05, 0x05, 0x05, 0x05, 0x02, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x07, 0x00, 0x06, 0x09, 
+       0x08, 0x04, 0x02, 0x0f, 0x00, 0x0f, 0x08, 0x06, 0x08, 0x09, 0x06, 0x00, 0x04, 0x06, 0x05, 0x0f, 
+       0x04, 0x04, 0x00, 0x0f, 0x01, 0x07, 0x08, 0x09, 0x06, 0x00, 0x06, 0x01, 0x07, 0x09, 0x09, 0x06, 
+       0x00, 0x0f, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x06, 0x09, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06, 
+       0x09, 0x09, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 
+       0x00, 0x06, 0x02, 0x01, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 
+       0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x02, 0x01, 0x00, 0x02, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 
+       0x06, 0x09, 0x0d, 0x0d, 0x01, 0x06, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x07, 0x09, 
+       0x07, 0x09, 0x09, 0x07, 0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x00, 0x07, 0x09, 0x09, 0x09, 
+       0x09, 0x07, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x01, 
+       0x00, 0x06, 0x09, 0x01, 0x0d, 0x09, 0x0e, 0x00, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00, 0x07, 
+       0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x08, 0x08, 0x08, 0x08, 0x09, 0x06, 0x00, 0x09, 0x05, 0x03, 
+       0x03, 0x05, 0x09, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x09, 0x0f, 0x0f, 0x09, 0x09, 
+       0x09, 0x00, 0x09, 0x0b, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 
+       0x07, 0x09, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x09, 0x09, 0x0b, 0x06, 0x08, 0x07, 0x09, 
+       0x09, 0x07, 0x05, 0x09, 0x00, 0x06, 0x09, 0x02, 0x04, 0x09, 0x06, 0x00, 0x07, 0x02, 0x02, 0x02, 
+       0x02, 0x02, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x06, 0x06, 
+       0x00, 0x09, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00, 0x09, 0x09, 0x06, 0x06, 0x09, 0x09, 0x00, 0x05, 
+       0x05, 0x05, 0x02, 0x02, 0x02, 0x00, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x0f, 0x00, 0x07, 0x01, 0x01, 
+       0x01, 0x01, 0x07, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x04, 
+       0x07, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 
+       0x03, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x01, 0x01, 
+       0x07, 0x09, 0x09, 0x07, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x00, 0x08, 0x08, 0x0e, 0x09, 
+       0x09, 0x0e, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04, 0x0a, 0x02, 0x07, 0x02, 0x02, 
+       0x00, 0x00, 0x00, 0x0e, 0x09, 0x06, 0x01, 0x0e, 0x01, 0x01, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02, 
+       0x00, 0x03, 0x02, 0x02, 0x07, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x05, 0x02, 0x01, 0x01, 0x05, 
+       0x03, 0x05, 0x09, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00, 0x05, 0x0f, 0x09, 
+       0x09, 0x00, 0x00, 0x00, 0x07, 0x09, 0x09, 0x09, 0x00, 0x00, 0x00, 0x06, 0x09, 0x09, 0x06, 0x00, 
+       0x00, 0x00, 0x07, 0x09, 0x09, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x09, 0x09, 0x0e, 0x08, 0x00, 0x00, 
+       0x07, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x0c, 0x07, 0x00, 0x02, 0x02, 0x07, 0x02, 
+       0x02, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x02, 
+       0x00, 0x00, 0x00, 0x09, 0x09, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x00, 
+       0x00, 0x09, 0x09, 0x0a, 0x04, 0x02, 0x00, 0x00, 0x0f, 0x04, 0x02, 0x0f, 0x00, 0x04, 0x02, 0x03, 
+       0x02, 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x06, 0x02, 0x02, 
+       0x01, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, 
+       0x0e, 0x05, 0x05, 0x0e, 0x04, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x11, 0x0e, 0x0a, 
+       0x0e, 0x11, 0x00, 0x05, 0x05, 0x02, 0x07, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, 
+       0x00, 0x0c, 0x02, 0x06, 0x0a, 0x0c, 0x08, 0x06, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 
+       0x11, 0x15, 0x13, 0x15, 0x11, 0x0e, 0x06, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 
+       0x09, 0x12, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 
+       0x00, 0x00, 0x0e, 0x11, 0x17, 0x13, 0x13, 0x11, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x1f, 0x00, 0x06, 0x04, 
+       0x02, 0x06, 0x00, 0x00, 0x00, 0x06, 0x06, 0x04, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x07, 0x01, 0x0e, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 
+       0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x04, 
+       0x06, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 
+       0x12, 0x09, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x0c, 0x0e, 0x08, 0x01, 0x01, 0x01, 0x0d, 0x08, 
+       0x04, 0x0c, 0x03, 0x03, 0x02, 0x0b, 0x0c, 0x0e, 0x08, 0x02, 0x00, 0x02, 0x01, 0x05, 0x02, 0x00, 
+       0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 
+       0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 
+       0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x0e, 0x05, 0x0d, 0x07, 0x05, 0x0d, 
+       0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x02, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 
+       0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 
+       0x01, 0x01, 0x0f, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 
+       0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 
+       0x07, 0x0a, 0x0b, 0x0a, 0x0a, 0x07, 0x00, 0x0d, 0x09, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09, 
+       0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 
+       0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 
+       0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x0e, 0x0d, 0x0d, 0x0b, 0x0b, 0x07, 0x00, 0x09, 
+       0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 
+       0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x05, 0x05, 0x05, 0x02, 0x02, 
+       0x02, 0x00, 0x01, 0x07, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x07, 0x09, 0x0b, 0x05, 0x01, 
+       0x02, 0x04, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x02, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x0a, 
+       0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x05, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x00, 0x0e, 0x09, 
+       0x0d, 0x0a, 0x00, 0x06, 0x06, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x05, 0x0e, 
+       0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x02, 0x02, 0x04, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04, 
+       0x02, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x02, 0x05, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x05, 0x00, 0x06, 
+       0x0d, 0x03, 0x06, 0x00, 0x01, 0x02, 0x03, 0x02, 0x02, 0x07, 0x00, 0x02, 0x01, 0x03, 0x02, 0x02, 
+       0x07, 0x00, 0x02, 0x05, 0x03, 0x02, 0x02, 0x07, 0x00, 0x05, 0x00, 0x03, 0x02, 0x02, 0x07, 0x00, 
+       0x02, 0x0c, 0x06, 0x09, 0x09, 0x06, 0x00, 0x0a, 0x05, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02, 0x04, 
+       0x06, 0x09, 0x09, 0x06, 0x00, 0x04, 0x02, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06, 0x00, 0x06, 0x09, 
+       0x09, 0x06, 0x00, 0x0a, 0x05, 0x06, 0x09, 0x09, 0x06, 0x00, 0x05, 0x00, 0x06, 0x09, 0x09, 0x06, 
+       0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x0b, 0x07, 0x00, 0x02, 
+       0x04, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x06, 0x00, 0x09, 
+       0x09, 0x09, 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x0a, 
+       0x04, 0x02, 0x00, 0x01, 0x07, 0x09, 0x09, 0x07, 0x01, 0x0a, 0x00, 0x09, 0x09, 0x0a, 0x04, 0x02, 
+};
+
+static const uint16_t glyph_pos[256] = {
+          0,    7,   14,   21,   28,   35,   42,   49, 
+         56,   63,   70,   77,   84,   91,   98,  105, 
+        112,  119,  126,  133,  140,  147,  154,  161, 
+        168,  175,  182,  189,  196,  203,  210,  217, 
+        224,  231,  238,  245,  252,  259,  266,  273, 
+        280,  287,  294,  301,  308,  315,  322,  329, 
+        336,  343,  350,  357,  364,  371,  378,  385, 
+        392,  399,  406,  413,  420,  427,  434,  441, 
+        448,  455,  462,  469,  476,  483,  490,  497, 
+        504,  511,  518,  525,  532,  539,  546,  553, 
+        560,  567,  574,  581,  588,  595,  602,  609, 
+        616,  623,  630,  637,  644,  651,  658,  665, 
+        672,  679,  686,  693,  700,  707,  714,  721, 
+        728,  735,  742,  749,  756,  763,  770,  777, 
+        784,  791,  798,  805,  812,  819,  826,  833, 
+        840,  847,  854,  861,  868,  875,  882,  889, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+        896,  903,  910,  917,  924,  931,  938,  945, 
+        952,  959,  966,  973,  980,  987,  994, 1001, 
+       1008, 1015, 1022, 1029, 1036, 1043, 1050, 1057, 
+       1064, 1071, 1078, 1085, 1092, 1099, 1106, 1113, 
+       1120, 1127, 1134, 1141, 1148, 1155, 1162, 1169, 
+       1176, 1183, 1190, 1197, 1204, 1211, 1218, 1225, 
+       1232, 1239, 1246, 1253, 1260, 1267, 1274, 1281, 
+       1288, 1295, 1302, 1309, 1316, 1323, 1330, 1337, 
+       1344, 1351, 1358, 1365, 1372, 1379, 1386, 1393, 
+       1400, 1407, 1414, 1421, 1428, 1435, 1442, 1449, 
+       1456, 1463, 1470, 1477, 1484, 1491, 1498, 1505, 
+       1512, 1519, 1526, 1533, 1540, 1547, 1554, 1561, 
+};
+
+#define GLYPH_WIDTH 5
+#define GLYPH_HEIGHT 7
+#define GLYPH_ASCENT 6
diff --git a/src/draw/ao_line.c b/src/draw/ao_line.c
new file mode 100644 (file)
index 0000000..ed1fc21
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * 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_draw.h"
+#include "ao_draw_int.h"
+
+#define ao_mask(x,w)   (ao_right(AO_ALLONES,(x) & AO_MASK) & \
+                        ao_left(AO_ALLONES,(FB_UNIT - ((x)+(w))) & AO_MASK))
+
+
+/* out of clip region codes */
+#define OUT_LEFT 0x08
+#define OUT_RIGHT 0x04
+#define OUT_ABOVE 0x02
+#define OUT_BELOW 0x01
+
+/* major axis for bresenham's line */
+#define X_AXIS 0
+#define Y_AXIS 1
+
+/*
+ * Line clipping. Clip to the box, bringing the coordinates forward while
+ * preserving the actual slope and error
+ *
+ *
+ *     X major line, clip X:
+ *
+ *     adjust_x = -x;
+ *
+ *     e += adjust_x * e1;
+ *
+ *     adjust_y = (e + -e3-1) / -e3;
+ *
+ *     e -= adjust_y / -e3;
+ *
+ *     X major line, clip Y:
+ *
+ *     adjust_y = -y;
+
+ *
+ *     e -= adjust_y / -e3;
+ *
+ *     adjust_x = e / e1;
+ */
+
+
+
+
+static void
+ao_bres(const struct ao_bitmap *dst_bitmap,
+       int16_t         signdx,
+       int16_t         signdy,
+       int16_t         axis,
+       int16_t         x1,
+       int16_t         y1,
+       int16_t         e,
+       int16_t         e1,
+       int16_t         e3,
+       int16_t         len,
+       uint32_t        and,
+       uint32_t        xor)
+{
+       int16_t         stride = dst_bitmap->stride;
+       uint32_t        *dst = dst_bitmap->base;
+       uint32_t        mask0, mask;
+
+       mask0 = 1;
+       if (signdx < 0)
+               mask0 = ao_right(1, AO_UNIT - 1);
+
+       if (signdy < 0)
+               stride = -stride;
+
+       dst = dst + y1 * stride + (x1 >> AO_SHIFT);
+       mask = ao_right(1, x1 & AO_MASK);
+
+       while (len--) {
+               /* clip each point */
+
+               *dst = ao_do_mask_rrop(*dst, and, xor, mask);
+
+               if (axis == X_AXIS) {
+                       if (signdx < 0)
+                               mask = ao_left(mask, 1);
+                       else
+                               mask = ao_right(mask, 1);
+                       if (!mask) {
+                               dst += signdx;
+                               mask = mask0;
+                       }
+                       e += e1;
+                       if (e >= 0) {
+                               dst += stride;
+                               e += e3;
+                       }
+               } else {
+                       dst += stride;
+                       e += e1;
+                       if (e >= 0) {
+                               if (signdx < 0)
+                                       mask = ao_left(mask, 1);
+                               else
+                                       mask = ao_right(mask, 1);
+                               if (!mask) {
+                                       dst += signdx;
+                                       mask = mask0;
+                               }
+                               e += e3;
+                       }
+               }
+       }
+}
+
+struct ao_cc {
+       int16_t major;
+       int16_t minor;
+       int16_t sign_major;
+       int16_t sign_minor;
+       int16_t e;
+       int16_t e1;
+       int16_t e3;
+       int8_t  first;
+};
+
+/* line clipping box */
+struct ao_cbox {
+       int16_t maj1, min1;
+       int16_t maj2, min2;
+};
+
+/* -b <= a, so we need to make a bigger */
+static int16_t
+div_ceil(int32_t a, int16_t b) {
+       return (a + b + b - 1) / b - 1;
+}
+
+static int16_t
+div_floor_plus_one(int32_t a, int16_t b) {
+       return (a + b) / b;
+}
+
+static int8_t
+ao_clip_line(struct ao_cc *c, struct ao_cbox *b)
+{
+       int32_t adjust_major = 0, adjust_minor = 0;
+
+       /* Clip major axis */
+       if (c->major < b->maj1) {
+               if (c->sign_major <= 0)
+                       return FALSE;
+               adjust_major = b->maj1 - c->major;
+       } else if (c->major >= b->maj2) {
+               if (c->sign_major >= 0)
+                       return FALSE;
+               adjust_major = c->major - (b->maj2-1);
+       }
+
+       /* Clip minor axis */
+       if (c->minor < b->min1) {
+               if (c->sign_minor <= 0)
+                       return FALSE;
+               adjust_minor = b->min1 - c->minor;
+       } else if (c->minor >= b->min2) {
+               if (c->sign_minor >= 0)
+                       return FALSE;
+               adjust_minor = c->minor - (b->min2-1);
+       }
+
+       /* If unclipped, we're done */
+       if (adjust_major == 0 && adjust_minor == 0)
+               return TRUE;
+
+       /* See how much minor adjustment would happen during
+        * a major clip. This is a bit tricky because line drawing
+        * isn't symmetrical when the line passes exactly between
+        * two pixels, we have to pick which one gets drawn
+        */
+       int32_t adj_min;
+
+       if (!c->first)
+               adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3);
+       else
+               adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3);
+
+       if (adj_min < adjust_minor) {
+               if (c->first)
+                       adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1);
+               else
+                       adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1);
+       } else {
+               adjust_minor = adj_min;
+       }
+
+       c->e += adjust_major * c->e1 + adjust_minor * c->e3;
+
+       c->major += c->sign_major * adjust_major;
+       c->minor += c->sign_minor * adjust_minor;
+
+       return TRUE;
+}
+
+void
+ao_line(const struct ao_bitmap *dst,
+       int16_t                 x1,
+       int16_t                 y1,
+       int16_t                 x2,
+       int16_t                 y2,
+       uint32_t                fill,
+       uint8_t                 rop)
+{
+       int16_t adx, ady;
+       int16_t e, e1, e2, e3;
+       int16_t signdx = 1, signdy = 1;
+       int16_t axis;
+       int16_t len;
+       struct ao_cc    clip_1, clip_2;
+       struct ao_cbox  cbox;
+
+       if ((adx = x2 - x1) < 0) {
+               adx = -adx;
+               signdx = -1;
+       }
+       if ((ady = y2 - y1) < 0) {
+               ady = -ady;
+               signdy = -1;
+       }
+
+       if (adx > ady) {
+               axis = X_AXIS;
+               e1 = ady << 1;
+               e2 = e1 - (adx << 1);
+               e = e1 - adx;
+
+               clip_1.major = x1;
+               clip_1.minor = y1;
+               clip_2.major = x2;
+               clip_2.minor = y2;
+               clip_1.sign_major = signdx;
+               clip_1.sign_minor = signdy;
+
+               cbox.maj1 = 0;
+               cbox.maj2 = dst->width;
+               cbox.min1 = 0;
+               cbox.min2 = dst->height;
+       } else {
+               axis = Y_AXIS;
+               e1 = adx << 1;
+               e2 = e1 - (ady << 1);
+               e = e1 - ady;
+
+               clip_1.major = y1;
+               clip_1.minor = x1;
+               clip_2.major = y2;
+               clip_2.minor = x2;
+               clip_1.sign_major = signdy;
+               clip_1.sign_minor = signdx;
+
+               cbox.maj1 = 0;
+               cbox.maj2 = dst->height;
+               cbox.min1 = 0;
+               cbox.min2 = dst->width;
+       }
+
+       e3 = e2 - e1;
+       e = e - e1;
+
+       clip_1.first = TRUE;
+       clip_2.first = FALSE;
+       clip_2.e = clip_1.e = e;
+       clip_2.e1 = clip_1.e1 = e1;
+       clip_2.e3 = clip_1.e3 = e3;
+       clip_2.sign_major = -clip_1.sign_major;
+       clip_2.sign_minor = -clip_1.sign_minor;
+
+       if (!ao_clip_line(&clip_1, &cbox))
+               return;
+
+       if (!ao_clip_line(&clip_2, &cbox))
+               return;
+
+       len = clip_1.sign_major * (clip_2.major - clip_1.major) + clip_2.first;
+
+       if (len <= 0)
+               return;
+
+       if (adx > ady) {
+               x1 = clip_1.major;
+               y1 = clip_1.minor;
+       } else {
+               x1 = clip_1.minor;
+               y1 = clip_1.major;
+       }
+       ao_bres(dst,
+               signdx,
+               signdy,
+               axis,
+               x1,
+               y1,
+               clip_1.e, e1, e3, len,
+               ao_and(rop, fill),
+               ao_xor(rop, fill));
+}
diff --git a/src/draw/ao_pattern.c b/src/draw/ao_pattern.c
new file mode 100644 (file)
index 0000000..0d1dc76
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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_draw.h"
+#include "ao_draw_int.h"
+
+static inline uint32_t
+ao_pattern_expand(uint8_t v, uint8_t rot)
+{
+       uint32_t        r;
+
+       if (rot)
+               v = ao_left(v, 8-rot) | ao_right(v, rot);
+       r = v;
+       return (r << 24) | (r << 16) | (r << 8) | (r);
+}
+
+static inline int
+min(int a, int b) {
+       return a < b ? a : b;
+}
+
+void
+ao_pattern(const struct ao_bitmap      *dst,
+          int16_t                      x,
+          int16_t                      y,
+          int16_t                      width,
+          int16_t                      height,
+          const struct ao_pattern      *pattern,
+          int16_t                      pat_x,
+          int16_t                      pat_y,
+          uint8_t                      rop)
+{
+       uint32_t        pat[8];
+
+       int16_t x2 = x + width;
+       int16_t y2 = y + height;
+
+       ao_clip(x, 0, dst->width);
+       ao_clip(x2, 0, dst->width);
+       ao_clip(y, 0, dst->height);
+       ao_clip(y2, 0, dst->height);
+
+       if (x < x2 && y < y2) {
+               int     xrot = (x - pat_x) & 7;
+               int     yrot = (y - pat_y) & 7;
+               int     i;
+               int16_t dst_x, dst_y;
+
+               for (i = 0; i < 8; i++)
+                       pat[(i + yrot) & 7] = ao_pattern_expand(pattern->pattern[i], xrot);
+               for (dst_y = y; dst_y < y2; dst_y += 8) {
+                       int     h = min(y2 - dst_y, 8);
+                       for (dst_x = x; dst_x < x2; dst_x += 8) {
+                               int     w = min(x2 - dst_x, 8);
+
+                               ao_blt(pat, 1, 0,
+                                      dst->base + dst_y * dst->stride,
+                                      dst->stride,
+                                      dst_x,
+                                      w, h,
+                                      rop,
+                                      0, 0);
+                       }
+               }
+       }
+}
+
diff --git a/src/draw/ao_rect.c b/src/draw/ao_rect.c
new file mode 100644 (file)
index 0000000..71fa4ae
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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_draw.h"
+#include "ao_draw_int.h"
+
+void
+ao_rect(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       int16_t                 width,
+       int16_t                 height,
+       uint32_t                fill,
+       uint8_t                 rop)
+{
+       int16_t x2 = x + width;
+       int16_t y2 = y + height;
+
+       ao_clip(x, 0, dst->width);
+       ao_clip(x2, 0, dst->width);
+       ao_clip(y, 0, dst->height);
+       ao_clip(y2, 0, dst->height);
+
+       if (x < x2 && y < y2) {
+               ao_solid(ao_and(rop, fill),
+                        ao_xor(rop, fill),
+                        dst->base + y * dst->stride,
+                        dst->stride,
+                        x,
+                        x2 - x,
+                        y2 - y);
+       }
+}
+
diff --git a/src/draw/ao_text.c b/src/draw/ao_text.c
new file mode 100644 (file)
index 0000000..7ce2a62
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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_draw.h"
+#include "ao_draw_int.h"
+#include "ao_font.h"
+
+const struct ao_font ao_font = {
+       .width = GLYPH_WIDTH,
+       .height = GLYPH_HEIGHT,
+       .ascent = GLYPH_ASCENT,
+       .descent = GLYPH_HEIGHT - GLYPH_ASCENT,
+};
+
+void
+ao_text(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       char                    *string,
+       uint32_t                fill,
+       uint8_t                 rop)
+{
+       uint32_t        src[GLYPH_HEIGHT];
+       char            c;
+       int             h;
+
+       struct ao_bitmap        src_bitmap = {
+               .base = src,
+               .stride = 1,
+               .width = GLYPH_WIDTH,
+               .height = GLYPH_HEIGHT
+       };
+
+       y -= GLYPH_ASCENT;
+
+       rop = (rop & 3) | 0x4;
+
+       if ((fill&1) == 0)
+               rop ^= 3;
+
+       while ((c = *string++)) {
+               const uint8_t   *bytes = &glyph_bytes[glyph_pos[(uint8_t) c]];
+
+               for (h = 0; h < GLYPH_HEIGHT; h++)
+                       src[h] = bytes[h];
+
+               ao_copy(dst,
+                       x, y, GLYPH_WIDTH, GLYPH_HEIGHT,
+                       &src_bitmap,
+                       0, 0, rop);
+               x += GLYPH_WIDTH;
+       }
+}
diff --git a/src/draw/font-convert b/src/draw/font-convert
new file mode 100755 (executable)
index 0000000..1985e41
--- /dev/null
@@ -0,0 +1,150 @@
+#!/usr/bin/nickle
+
+typedef struct {
+       int[]   bytes;
+       int     width;
+       int     height;
+       int     encoding;
+       int     location;
+} glyph_t;
+
+typedef struct {
+       glyph_t[...]    glyphs;
+       int             default_char;
+       int             ascent;
+} font_t;
+
+glyph_t
+read_glyph(file f)
+{
+       glyph_t glyph = { .encoding = -1, .bytes = (int[...]){}, .width = 0 };
+
+       while (!File::end(f)) {
+               string  l = fgets(f);
+
+               string[*] tokens = String::split(l, " ");
+               if (dim(tokens) == 0)
+                       continue;
+
+               switch (tokens[0]) {
+               case "ENCODING":
+                       glyph.encoding = atoi(tokens[1]);
+                       break;
+               case "DWIDTH":
+                       glyph.width = atoi(tokens[1]);
+                       break;
+               case "BBX":
+                       glyph.height = atoi(tokens[2]);
+                       break;
+               case "ENDCHAR":
+                       return glyph;
+               case "BITMAP":
+                       while (!File::end(f)) {
+                               string l = fgets(f);
+                               if (l == "ENDCHAR")
+                                       return glyph;
+                               glyph.bytes[dim(glyph.bytes)] = atoi(l, 16);
+                       }
+                       break;
+               }
+       }
+       return glyph;
+}
+
+font_t read_font(file f) {
+       font_t  font = { .glyphs = {}, .default_char = -1 };
+       bool in_head = true;
+
+       while (in_head && !File::end(f)) {
+               string l = File::fgets(f);
+
+               string[*] tokens = String::split(l, " ");
+               switch (tokens[0]) {
+               case "DEFAULT_CHAR":
+                       font.default_char = atoi(tokens[1]);
+                       break;
+               case "FONT_ASCENT":
+                       font.ascent = atoi(tokens[1]);
+                       break;
+               case "CHARS":
+                       in_head = false;
+                       break;
+               }
+       }
+       while (!File::end(f)) {
+               glyph_t glyph = read_glyph(f);
+               if (glyph.encoding == -1)
+                       break;
+               font.glyphs[dim(font.glyphs)] = glyph;
+       }
+       return font;
+}
+
+int
+flip_byte(int x)
+{
+       int     dest = 0;
+
+       for (int i = 0; i < 8; i++)
+               dest |= ((x >> (7 - i)) & 1) << i;
+       return dest;
+}
+
+void print_font(font_t font) {
+       int     width = font.glyphs[0].width;
+       int     height = font.glyphs[0].height;
+       int[256] pos = { -1 ... };
+       int[...] bytes;
+
+       if (false) {
+       for (int i = 1; i < dim(font.glyphs); i++) {
+               if (font.glyphs[i].width != width ||
+                  font.glyphs[i].height != height)
+               {
+                       File::fprintf(stderr, "font not constant size, glyph %d is %dx%d\n",
+                                     font.glyphs[i].encoding, font.glyphs[i].width, font.glyphs[i].height);
+                       exit(1);
+               }
+       }
+       }
+
+       if (font.default_char == -1)
+               font.default_char = font.glyphs[0].encoding;
+
+       /* build byte array */
+       for (int i = 0; i < dim(font.glyphs); i++) {
+               pos[font.glyphs[i].encoding] = dim(bytes);
+               for (int b = 0; b < dim(font.glyphs[i].bytes); b++)
+                       bytes[dim(bytes)] = font.glyphs[i].bytes[b];
+       }
+
+       /* Fill in default glyph */
+       for (int i = 0; i < dim(pos); i++)
+               if (pos[i] == -1)
+                       pos[i] = pos[font.default_char];
+
+       printf("static const uint8_t glyph_bytes[%d] = {", dim(bytes));
+       for (int b = 0; b < dim(bytes); b++) {
+               if ((b & 15) == 0)
+                       printf("\n\t");
+               printf("0x%02x, ", flip_byte(bytes[b]));
+       }
+       printf("\n};\n\n");
+
+       printf("static const uint16_t glyph_pos[%d] = {", dim(pos));
+       for (int i = 0; i < dim(pos); i++) {
+               if ((i & 7) == 0)
+                       printf("\n\t");
+               printf("%4d, ", pos[i]);
+       }
+       printf("\n};\n\n");
+
+       printf("#define GLYPH_WIDTH %d\n", width);
+       printf("#define GLYPH_HEIGHT %d\n", height);
+       printf("#define GLYPH_ASCENT %d\n", font.ascent);
+}
+
+twixt (file f = File::open(argv[1], "r"); File::close(f)) {
+       font_t font = read_font(f);
+       print_font(font);
+}
diff --git a/src/draw/line.5c b/src/draw/line.5c
new file mode 100644 (file)
index 0000000..747768b
--- /dev/null
@@ -0,0 +1,389 @@
+#!/usr/bin/nickle
+
+autoimport Cairo;
+autoload PRNG;
+
+int
+sign(int x)
+{
+       return x == 0 ? 0 : x < 0 ? -1 : 1;
+}
+
+int X_AXIS = 0;
+int Y_AXIS = 1;
+
+typedef struct {
+       int     major;
+       int     minor;
+       int     sign_major;
+       int     sign_minor;
+       int     e;
+       int     e1;
+       int     e3;
+       bool    first;
+} clip_context;
+
+typedef struct {
+       int     maj1, min1, maj2, min2;
+} clip_box;
+
+typedef struct {
+       int     x1, y1, x2, y2;
+} box;
+
+typedef struct {
+       int     x, y;
+} point;
+
+typedef struct {
+       int     x1, y1, x2, y2;
+       box     b;
+       point[] clipped;
+       point[] run;
+} test;
+
+box    bounds = { .x1 = 10, .x2 = 30, .y1 = 10, .y2 = 30 };
+
+int
+div_ceil(a, b) {
+       a += b;
+       assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b);
+       return (a + b - 1) // b - 1;
+}
+
+int
+div_floor_plus_one(a, b) {
+       a += b;
+       assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b);
+       return a // b;
+}
+
+bool
+clip(*clip_context c, *clip_box b)
+{
+       int     adjust_major = 0, adjust_minor = 0;
+
+       /* Clip major axis */
+       if (c->major < b->maj1) {
+               if (c->sign_major <= 0)
+                       return false;
+               adjust_major = b->maj1 - c->major;
+       } else if (c->major >= b->maj2) {
+               if (c->sign_major >= 0)
+                       return false;
+               adjust_major = c->major - (b->maj2-1);
+       }
+
+       /* Clip minor axis */
+       if (c->minor < b->min1) {
+               if (c->sign_minor <= 0)
+                       return false;
+               adjust_minor = b->min1 - c->minor;
+       } else if (c->minor >= b->min2) {
+               if (c->sign_minor >= 0)
+                       return false;
+               adjust_minor = c->minor - (b->min2-1);
+       }
+
+       /* If unclipped, we're done */
+       if (adjust_major == 0 && adjust_minor == 0)
+               return true;
+
+       /* See how much minor adjustment would happen during
+        * a major clip. This is a bit tricky because line drawing
+        * isn't symmetrical when the line passes exactly between
+        * two pixels, we have to pick which one gets drawn
+        */
+       int     adj_min;
+
+       if (!c->first)
+               adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3);
+       else
+               adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3);
+
+       /* Compare that to the minor clip and pick
+        * the larger amount.
+        */
+       printf ("\tinitial major %d minor %d error %d e1 %d e3 %d\n", c->major, c->minor, c->e, c->e1, c->e3);
+
+       if (adj_min < adjust_minor) {
+               printf("\tminor clip dominates %d < %d. adjust major %d -> ",
+                      adj_min, adjust_minor, adjust_major);
+               if (c->first)
+                       adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1);
+               else
+                       adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1);
+               printf("%d\n", adjust_major);
+       } else {
+               printf("\tminor clip dominates %d > %d. adjust minor %d -> ",
+                      adj_min, adjust_minor, adjust_minor);
+               adjust_minor = adj_min;
+               printf("%d\n", adjust_minor);
+       }
+
+       c->e += adjust_major * c->e1 + adjust_minor * c->e3;
+
+       c->major += c->sign_major * adjust_major;
+       c->minor += c->sign_minor * adjust_minor;
+
+       printf ("\tadjust major %d adjust minor %d e %d e1 %d e3 %e\n",
+               adjust_major, adjust_minor, c->e, c->e1, c->e3);
+
+       if (c->e >= 0)
+               printf ("error positive e %d e1 %d e3 %d\n",
+                       c->e, c->e1, c->e3);
+       if (c->e < c->e3)
+               printf ("error magnitude too large e %d e1 %d e3 %d\n", c->e, c->e1, c->e3);
+
+       return true;
+}
+
+test
+line(int x1, int y1, int x2, int y2, *box b) {
+
+       int     dx = x2 - x1;
+       int     dy = y2 - y1;
+       int     signdx = sign(dx);
+       int     signdy = sign(dy);
+       int     adx = abs(dx);
+       int     ady = abs(dy);
+       int     axis;
+       int     e, e1, e2, e3;
+       int     len;
+       clip_context    clip_1, clip_2;
+       clip_box        c;
+       bool            clipped = false;
+       test            t = {
+               .x1 = x1,
+               .y1 = y1,
+               .x2 = x2,
+               .y2 = y2,
+               .b = *b,
+               .clipped = (point[...]) {},
+               .run = (point[...]) {}
+       };
+
+       if (adx >= ady) {
+               axis = X_AXIS;
+               e1 = ady << 1;
+               e2 = e1 - (adx << 1);
+               e = e1 - adx;
+               len = adx;
+
+               clip_1.major = x1;
+               clip_1.minor = y1;
+               clip_2.major = x2;
+               clip_2.minor = y2;
+               clip_1.sign_major = signdx;
+               clip_1.sign_minor = signdy;
+
+               c.maj1 = b->x1;
+               c.maj2 = b->x2;
+               c.min1 = b->y1;
+               c.min2 = b->y2;
+       } else {
+               axis = Y_AXIS;
+               e1 = adx << 1;
+               e2 = e1 - (ady << 1);
+               e = e1 - ady;
+               len = ady;
+
+               clip_1.major = y1;
+               clip_1.minor = x1;
+               clip_2.major = y2;
+               clip_2.minor = x2;
+               clip_1.sign_major = signdy;
+               clip_1.sign_minor = signdx;
+               c.maj1 = b->y1;
+               c.maj2 = b->y2;
+               c.min1 = b->x1;
+               c.min2 = b->x2;
+       }
+
+       e3 = e2 - e1;
+       e = e - e1;
+
+       clip_1.first = true;
+       clip_2.first = false;
+       clip_2.e = clip_1.e = e;
+       clip_2.e1 = clip_1.e1 = e1;
+       clip_2.e3 = clip_1.e3 = e3;
+       clip_2.sign_major = -clip_1.sign_major;
+       clip_2.sign_minor = -clip_1.sign_minor;
+
+       printf ("clip start:\n");
+       if (!clip(&clip_1, &c))
+               clipped = true;
+
+       printf("clip end:\n");
+       if (!clip(&clip_2, &c))
+               clipped = true;
+
+       int     clip_len;
+       int     clip_x, clip_y;
+       int     clip_e;
+       int     x_major, x_minor;
+       int     y_major, y_minor;
+
+       clip_len = clip_1.sign_major * (clip_2.major - clip_1.major);
+       if (clip_len < 0)
+               clipped = true;
+
+       int x, y;
+
+       if (axis == X_AXIS) {
+               x = clip_1.major;
+               y = clip_1.minor;
+               x_major = clip_1.sign_major;
+               x_minor = 0;
+               y_major = 0;
+               y_minor = clip_1.sign_minor;
+       } else {
+               x = clip_1.minor;
+               y = clip_1.major;
+               x_major = 0;
+               x_minor = clip_1.sign_minor;
+               y_major = clip_1.sign_major;
+               y_minor = 0;
+       }
+
+       clip_e = clip_1.e;
+
+       if (clipped)
+               clip_len = -1;
+
+       while (clip_len-- >= 0) {
+               t.clipped[dim(t.clipped)] = (point) { .x = x, .y = y };
+               x += x_major;
+               y += y_major;
+               clip_e += e1;
+               if (clip_e >= 0) {
+                       x += x_minor;
+                       y += y_minor;
+                       clip_e += e3;
+               }
+       }
+
+       x = x1;
+       y = y1;
+
+       while (len-- >= 0) {
+               if (bounds.x1 <= x && x < bounds.x2 &&
+                   bounds.y1 <= y && y < bounds.y2) {
+                       t.run[dim(t.run)] = (point) { .x = x, .y = y };
+               }
+               x += x_major;
+               y += y_major;
+               e += e1;
+               if (e >= 0) {
+                       x += x_minor;
+                       y += y_minor;
+                       e += e3;
+               }
+       }
+       return t;
+}
+
+void read_events (Cairo::cairo_t cr)
+{
+       file    event = Cairo::open_event(cr);
+
+       while (!File::end(event)) {
+               string  event_line = File::fgets(event);
+               if (String::index(event_line, "delete") >= 0)
+                       exit(0);
+       }
+}
+
+#for (int y = 0; y < 20; y++)
+
+void
+show(cairo_t cr, test t)
+{
+       rectangle(cr, 0, 0, 40, 40);
+       set_source_rgba(cr, 1, 1, 1, 1);
+       fill(cr);
+
+       set_source_rgba(cr, 0, 1, 0, .2);
+       set_line_width(cr, 0.1);
+       for (int x = 0; x < 40; x++) {
+               move_to(cr, 0, x);
+               line_to(cr, 40, x);
+               move_to(cr, x, 0);
+               line_to(cr, x, 40);
+       }
+       stroke(cr);
+
+       rectangle(cr, t.b.x1, t.b.y1, t.b.x2 - t.b.x1, t.b.y2 - t.b.y1);
+       set_line_width(cr, 0.1);
+       set_source_rgba(cr, 0, 0, 0, 1);
+       stroke(cr);
+
+       move_to(cr, t.x1+.5, t.y1+.5);
+       line_to(cr, t.x2+.5, t.y2+.5);
+       move_to(cr, t.x2, t.y2);
+       line_to(cr, t.x2+1, t.y2+1);
+       move_to(cr, t.x2+1, t.y2);
+       line_to(cr, t.x2, t.y2+1);
+       stroke(cr);
+
+       void pixels(point[] pt) {
+               for (int i = 0; i < dim(pt); i++) {
+                       rectangle(cr, pt[i].x, pt[i].y, 1, 1);
+               }
+               fill(cr);
+       }
+
+       set_source_rgba(cr, 1, 0, 0, .5);
+       pixels(t.clipped);
+
+       set_source_rgba(cr, 0, 0, 1, .5);
+       pixels(t.run);
+}
+
+bool
+compare(test t)
+{
+       if (dim(t.clipped) != dim(t.run))
+               return false;
+
+       for (int i = 0; i < dim(t.clipped); i++)
+               if (t.clipped[i] != t.run[i])
+                       return false;
+       return true;
+}
+
+void
+doit(int i)
+{
+       int     n;
+       *box    b = &bounds;
+
+       cairo_t cr = new(800, 800);
+
+       scale(cr, 20, 20);
+
+       for (;;) {
+               PRNG::srandom(i);
+               int     x1 = PRNG::randint(40);
+               int     x2 = PRNG::randint(40);
+               int     y1 = PRNG::randint(40);
+               int     y2 = PRNG::randint(40);
+
+               test t = line (x1, y1, x2, y2, &bounds);
+               show(cr, t);
+               if (!compare(t)) {
+                       printf("line %d -- %d x %d - %d x %d\n", i, x1, y1, x2, y2);
+                       gets();
+               }
+               i++;
+       }
+
+       read_events(cr);
+}
+
+int i = 0;
+if (dim(argv) > 1)
+       i = atoi(argv[1]);
+
+doit(i);
diff --git a/src/drivers/ao_as1107.c b/src/drivers/ao_as1107.c
new file mode 100644 (file)
index 0000000..e0172d9
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.h>
+#include <ao_as1107.h>
+
+static uint8_t as1107_configured;
+static uint8_t as1107_mutex;
+
+static void
+ao_as1107_start(void) {
+       ao_spi_get_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX, AO_AS1107_SPI_SPEED);
+}
+
+static void
+ao_as1107_stop(void) {
+       ao_spi_put_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX);
+}
+
+static void
+_ao_as1107_cmd(uint8_t addr, uint8_t value)
+{
+       uint8_t packet[2] = { addr, value };
+
+       ao_as1107_start();
+       ao_spi_send(packet, 2, AO_AS1107_SPI_INDEX);
+       ao_as1107_stop();
+}
+
+static void
+_ao_as1107_setup(void)
+{
+       if (!as1107_configured) {
+               as1107_configured = 1;
+               _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_RESET);
+               _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_NOP);
+               _ao_as1107_cmd(AO_AS1107_DECODE_MODE, AO_AS1107_DECODE);
+               _ao_as1107_cmd(AO_AS1107_SCAN_LIMIT, AO_AS1107_NUM_DIGITS - 1);
+               _ao_as1107_cmd(AO_AS1107_INTENSITY, 0x0f);
+               _ao_as1107_cmd(AO_AS1107_FEATURE,
+                              (0 << AO_AS1107_FEATURE_CLK_EN) |
+                              (0 << AO_AS1107_FEATURE_REG_RES) |
+                              (1 << AO_AS1107_FEATURE_DECODE_SEL) |
+                              (1 << AO_AS1107_FEATURE_SPI_EN) |
+                              (0 << AO_AS1107_FEATURE_BLINK_EN) |
+                              (0 << AO_AS1107_FEATURE_BLINK_FREQ) |
+                              (0 << AO_AS1107_FEATURE_SYNC) |
+                              (0 << AO_AS1107_FEATURE_BLINK_START));
+               _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_NORMAL_NOP);
+       }
+}
+
+void
+ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values)
+{
+       uint8_t i;
+       ao_mutex_get(&as1107_mutex);
+       _ao_as1107_setup();
+       for (i = 0; i < count; i++)
+       {
+               _ao_as1107_cmd(AO_AS1107_DIGIT(start + i),
+                              values[i]);
+       }
+       ao_mutex_put(&as1107_mutex);
+}
+
+void
+ao_as1107_write_8(uint8_t start, uint8_t value)
+{
+       uint8_t values[2];
+
+       values[0] = (value >> 4);
+       values[1] = value & 0xf;
+       ao_as1107_write(start, 2, values);
+}
+
+void
+ao_as1107_write_16(uint8_t start, uint16_t value)
+{
+       uint8_t values[4];
+
+       values[0] = (value >> 12);
+       values[1] = (value >> 8) & 0xf;
+       values[2] = (value >> 4) & 0xf;
+       values[3] = (value) & 0xf;
+       ao_as1107_write(start, 4, values);
+}
+
+void
+ao_as1107_init(void)
+{
+       as1107_configured = 0;
+       ao_spi_init_cs(AO_AS1107_CS_PORT, (1 << AO_AS1107_CS_PIN));
+}
diff --git a/src/drivers/ao_as1107.h b/src/drivers/ao_as1107.h
new file mode 100644 (file)
index 0000000..a22b17d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_AS1107_H_
+#define _AO_AS1107_H_
+
+#define AO_AS1107_NO_OP                0x00
+#define AO_AS1107_DIGIT(n)     (0x01 + (n))
+#define AO_AS1107_DECODE_MODE  0x09
+#define AO_AS1107_INTENSITY    0x0a
+#define AO_AS1107_SCAN_LIMIT   0x0b
+#define AO_AS1107_SHUTDOWN     0x0c
+#define  AO_AS1107_SHUTDOWN_SHUTDOWN_RESET     0x00
+#define  AO_AS1107_SHUTDOWN_SHUTDOWN_NOP       0x80
+#define  AO_AS1107_SHUTDOWN_NORMAL_RESET       0x01
+#define  AO_AS1107_SHUTDOWN_NORMAL_NOP         0x81
+
+#define AO_AS1107_FEATURE      0x0e
+#define  AO_AS1107_FEATURE_CLK_EN      0       /* external clock enable */
+#define  AO_AS1107_FEATURE_REG_RES     1
+#define  AO_AS1107_FEATURE_DECODE_SEL  2       /* select HEX decode */
+#define  AO_AS1107_FEATURE_SPI_EN      3
+#define  AO_AS1107_FEATURE_BLINK_EN    4
+#define  AO_AS1107_FEATURE_BLINK_FREQ  5
+#define  AO_AS1107_FEATURE_SYNC                6
+#define  AO_AS1107_FEATURE_BLINK_START 7
+#define AO_AS1107_DISPLAY_TEST 0x0f
+
+void ao_as1107_init(void);
+
+void
+ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values);
+
+void
+ao_as1107_write_8(uint8_t start, uint8_t value);
+
+void
+ao_as1107_write_16(uint8_t start, uint16_t value);
+
+#ifndef AO_AS1107_DECODE
+#error "must define AO_AS1107_DECODE"
+#endif
+
+#ifndef AO_AS1107_NUM_DIGITS
+#error "must define AO_AS1107_NUM_DIGITS"
+#endif
+
+#endif /* _AO_AS1107_H_ */
index 725ac45a762334a6bdbf5a303d1bb028200081e6..07e92c670f3a1c590aed332b875d3f8fc66e46b3 100644 (file)
@@ -39,8 +39,16 @@ static struct ao_button_state        ao_button_state[AO_BUTTON_COUNT];
 #define bit(q) AO_BUTTON_ ## q
 #define pin(q) AO_BUTTON_ ## q ## _PIN
 
+#ifndef AO_BUTTON_INVERTED
+#define AO_BUTTON_INVERTED     1
+#endif
+
+#if AO_BUTTON_INVERTED
 /* pins are inverted */
 #define ao_button_value(b)     !ao_gpio_get(port(b), bit(b), pin(b))
+#else
+#define ao_button_value(b)     ao_gpio_get(port(b), bit(b), pin(b))
+#endif
 
 static uint8_t
 _ao_button_get(uint8_t b)
index a67071d24d879c44e348bb8ecb5ff8831e624e9c..c1c21e0d404e2a0259dd3b20ae23e5a0ad464c77 100644 (file)
@@ -39,7 +39,7 @@ static uint8_t ao_radio_abort;                /* radio operation should abort */
 
 #define FOSC   26000000
 
-#define ao_radio_select()      ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_6MHz)
+#define ao_radio_select()      ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_CC115L_SPI_SPEED)
 #define ao_radio_deselect()    ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)
 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS)
 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS)
index 2bc997348b8b47375f258842a96a3067f9e2aff6..de282000ad95eeefd5a48d93ba3f5b717092ba61 100644 (file)
@@ -51,7 +51,11 @@ extern const uint32_t        ao_radio_cal;
 #define FOSC   40000000
 #endif
 
-#define ao_radio_select()      ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_SPI_SPEED_FAST)
+#ifndef AO_CC1200_SPI_SPEED
+#error AO_CC1200_SPI_SPEED undefined
+#endif
+
+#define ao_radio_select()      ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_CC1200_SPI_SPEED)
 #define ao_radio_deselect()    ao_spi_put_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS)
 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1200_SPI_BUS)
 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1200_SPI_BUS)
@@ -1323,7 +1327,7 @@ static void ao_radio_packet(void) {
 void
 ao_radio_test_recv(void)
 {
-       uint8_t bytes[34];
+       static uint8_t  bytes[34];
        uint8_t b;
 
        if (ao_radio_recv(bytes, 34, 0)) {
diff --git a/src/drivers/ao_console.c b/src/drivers/ao_console.c
new file mode 100644 (file)
index 0000000..cbde38c
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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_console.h"
+#include "ao_ps2.h"
+#include "ao_vga.h"
+
+static uint8_t console_row, console_col;
+
+#define ao_console_bitmap      ao_vga_bitmap
+
+static uint8_t console_rows, console_cols;
+
+static void
+ao_console_scroll(void)
+{
+       ao_copy(&ao_console_bitmap,
+               0, 0,
+               ao_console_bitmap.width,
+               ao_console_bitmap.height - ao_font.height,
+               &ao_console_bitmap,
+               0, ao_font.height,
+               AO_COPY);
+       ao_rect(&ao_console_bitmap,
+               0,
+               (console_rows - 1) * ao_font.height,
+               ao_console_bitmap.width,
+               ao_font.height,
+               1,
+               AO_COPY);
+}
+
+static void
+ao_console_cursor(void)
+{
+       ao_rect(&ao_console_bitmap,
+               console_col * ao_font.width,
+               console_row * ao_font.height,
+               ao_font.width,
+               ao_font.height,
+               1,
+               AO_XOR);
+}
+
+static void
+ao_console_clear(void)
+{
+       ao_rect(&ao_console_bitmap,
+               0, 0,
+               ao_console_bitmap.width,
+               ao_console_bitmap.height,
+               1,
+               AO_COPY);
+}
+
+static void
+ao_console_space(void)
+{
+       ao_rect(&ao_console_bitmap,
+               console_col * ao_font.width,
+               console_row * ao_font.height,
+               ao_font.width,
+               ao_font.height,
+               1,
+               AO_COPY);
+}
+
+static void
+ao_console_newline(void)
+{
+       if (++console_row == console_rows) {
+               ao_console_scroll();
+               console_row--;
+       }
+}
+
+void
+ao_console_putchar(char c)
+{
+       if (' ' <= c && c < 0x7f) {
+               char    text[2];
+               ao_console_space();
+               text[0] = c;
+               text[1] = '\0';
+               ao_text(&ao_console_bitmap,
+                       console_col * ao_font.width,
+                       console_row * ao_font.height + ao_font.ascent,
+                       text,
+                       0,
+                       AO_COPY);
+               if (++console_col == console_cols) {
+                       console_col = 0;
+                       ao_console_newline();
+               }
+       } else {
+               ao_console_cursor();
+               switch (c) {
+               case '\r':
+                       console_col = 0;
+                       break;
+               case '\t':
+                       console_col += 8 - (console_col & 7);
+                       if (console_col >= console_cols) {
+                               console_col = 0;
+                               ao_console_newline();
+                       }
+                       break;
+               case '\n':
+                       ao_console_newline();
+                       break;
+               case '\f':
+                       console_col = console_row = 0;
+                       ao_console_clear();
+                       break;
+               case '\177':
+               case '\010':
+                       if (console_col)
+                               console_col--;
+                       break;
+               }
+       }
+       ao_console_cursor();
+}
+
+void
+ao_console_init(void)
+{
+       console_cols = ao_console_bitmap.width / ao_font.width;
+       console_rows = ao_console_bitmap.height / ao_font.height;
+#if CONSOLE_STDIN
+       ao_ps2_stdin = 1;
+       ao_add_stdio(_ao_ps2_pollchar,
+                    ao_console_putchar,
+                    NULL);
+#endif
+       ao_console_clear();
+       ao_console_cursor();
+       ao_vga_enable(1);
+}
diff --git a/src/drivers/ao_console.h b/src/drivers/ao_console.h
new file mode 100644 (file)
index 0000000..33d3658
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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_CONSOLE_H_
+#define _AO_CONSOLE_H_
+
+void
+ao_console_putchar(char c);
+
+void
+ao_console_init(void);
+
+#endif /* _AO_CONSOLE_H_ */
index d1c69d81b2761d86106200af90c63f7f31ca6b12..d1df6eac4e59d7788721eb4a02814f093eb53dc9 100644 (file)
@@ -22,6 +22,7 @@
 #define AO_EVENT_NONE          0
 #define AO_EVENT_QUADRATURE    1
 #define AO_EVENT_BUTTON                2
+#define AO_EVENT_KEY           3
 
 struct ao_event {
        uint8_t         type;
index fb8eecff177322cf9b46a959f87fee4bbe9fbf89..43e7df238c800eedf2face8c68ddb043273a1fd8 100644 (file)
@@ -1615,7 +1615,7 @@ ao_fat_hexdump_cmd(void)
                ao_cmd_status = ao_cmd_syntax_error;
                return;
        }
-               
+
        fd = ao_fat_open(name, AO_FAT_OPEN_READ);
        if (fd < 0) {
                printf ("Open failed: %d\n", fd);
@@ -1649,5 +1649,7 @@ void
 ao_fat_init(void)
 {
        ao_bufio_init();
+#if FAT_COMMANDS
        ao_cmd_register(&ao_fat_cmds[0]);
+#endif
 }
index 00f10ecce2718e5268c211b1b26fb9a10441e5ea..e1806ca394f95815c84838b3f4fafdefd07d9538 100644 (file)
@@ -661,7 +661,7 @@ ao_lco_monitor(void)
                       ao_lco_armed, ao_lco_firing);
 
                if (ao_lco_armed && ao_lco_firing) {
-                       ao_lco_ignite();
+                       ao_lco_ignite(AO_PAD_FIRE);
                } else {
                        ao_lco_update();
                        if (ao_lco_armed) {
index dcc0c6d011c64986c7234976ce4b5be46ea4de4b..8de21fb6702075e25317dfb891e50223fa517122 100644 (file)
@@ -61,9 +61,9 @@ lco_arm(void)
 }
 
 static void
-lco_ignite(void)
+lco_ignite(uint8_t cmd)
 {
-       ao_lco_ignite();
+       ao_lco_ignite(cmd);
 }
 
 static void
@@ -145,7 +145,40 @@ lco_fire_cmd(void) __reentrant
                secs = 100;
        for (i = 0; i < secs; i++) {
                printf("fire %d\n", i); flush();
-               lco_ignite();
+               lco_ignite(AO_PAD_FIRE);
+               ao_delay(AO_MS_TO_TICKS(100));
+       }
+}
+
+static void
+lco_static_cmd(void) __reentrant
+{
+       uint8_t         secs;
+       uint8_t         i;
+       int8_t          r;
+
+       lco_args();
+       ao_cmd_decimal();
+       secs = ao_cmd_lex_i;
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       r = lco_query();
+       if (r != AO_RADIO_CMAC_OK) {
+               printf("query failed %d\n", r);
+               return;
+       }
+
+       for (i = 0; i < 4; i++) {
+               printf("arm %d\n", i); flush();
+               lco_arm();
+       }
+
+       secs = secs * 10 - 5;
+       if (secs > 100)
+               secs = 100;
+       for (i = 0; i < secs; i++) {
+               printf("fire %d\n", i); flush();
+               lco_ignite(AO_PAD_STATIC);
                ao_delay(AO_MS_TO_TICKS(100));
        }
 }
@@ -171,12 +204,22 @@ lco_ignite_cmd(void) __reentrant
        uint8_t i;
        lco_args();
        for (i = 0; i < 4; i++)
-               lco_ignite();
+               lco_ignite(AO_PAD_FIRE);
+}
+
+
+static void
+lco_endstatic_cmd(void) __reentrant
+{
+       lco_ignite(AO_PAD_ENDSTATIC);
 }
 
 static __code struct ao_cmds ao_lco_cmds[] = {
        { lco_report_cmd,       "l <box> <channel>\0Get remote status" },
        { lco_fire_cmd,         "F <box> <channel> <secs>\0Fire remote igniters" },
+       { lco_fire_cmd,         "F <box> <channel> <secs>\0Fire remote igniters" },
+       { lco_static_cmd,       "S <box> <channel> <secs>\0Initiate static test" },
+       { lco_endstatic_cmd,    "D\0End static test (and download someday)" },
        { lco_arm_cmd,          "a <box> <channel>\0Arm remote igniter" },
        { lco_ignite_cmd,       "i <box> <channel>\0Pulse remote igniter" },
        { 0, NULL },
index 862cb1be76d628745a8402da16cce6ac2e4655eb..92b344ed66c8d3a8b367c51f285f6bf75968823f 100644 (file)
@@ -47,7 +47,7 @@ ao_lco_query(uint16_t box, struct ao_pad_query *query, uint16_t *tick_offset)
        ao_mutex_get(&ao_lco_mutex);
        command.tick = ao_time();
        command.box = box;
-       command.cmd = AO_LAUNCH_QUERY;
+       command.cmd = AO_PAD_QUERY;
        command.channels = 0;
        ao_radio_cmac_send(&command, sizeof (command));
        sent_time = ao_time();
@@ -64,19 +64,19 @@ ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset)
        ao_mutex_get(&ao_lco_mutex);
        command.tick = ao_time() - tick_offset;
        command.box = box;
-       command.cmd = AO_LAUNCH_ARM;
+       command.cmd = AO_PAD_ARM;
        command.channels = channels;
        ao_radio_cmac_send(&command, sizeof (command));
        ao_mutex_put(&ao_lco_mutex);
 }
 
 void
-ao_lco_ignite(void)
+ao_lco_ignite(uint8_t cmd)
 {
        ao_mutex_get(&ao_lco_mutex);
        command.tick = 0;
        command.box = 0;
-       command.cmd = AO_LAUNCH_FIRE;
+       command.cmd = cmd;
        command.channels = 0;
        ao_radio_cmac_send(&command, sizeof (command));
        ao_mutex_put(&ao_lco_mutex);
index 6b06f92849cac7f92de8a4fb84fd50a6bb95af89..9d4a27ba3abfe949277dd9d75da1b37f4ce95590 100644 (file)
@@ -28,6 +28,6 @@ void
 ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset);
 
 void
-ao_lco_ignite(void);
+ao_lco_ignite(uint8_t cmd);
 
 #endif /* _AO_LCO_FUNC_H_ */
index 1cb0546c0fc0f8e5dc207977ae82d56b6da54ba1..e2f867454c5183e1f63cb30d212681093110c438 100644 (file)
@@ -287,7 +287,7 @@ ao_lco_monitor(void)
                       ao_lco_armed, ao_lco_firing);
 
                if (ao_lco_armed && ao_lco_firing) {
-                       ao_lco_ignite();
+                       ao_lco_ignite(AO_PAD_FIRE);
                } else {
                        ao_lco_get_channels();
                        if (ao_lco_armed) {
diff --git a/src/drivers/ao_matrix.c b/src/drivers/ao_matrix.c
new file mode 100644 (file)
index 0000000..fa2d0c5
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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.h>
+#include <ao_matrix.h>
+#include <ao_event.h>
+#include <ao_exti.h>
+
+#define row_port(q)    AO_MATRIX_ROW_ ## q ## _PORT
+#define row_bit(q)     AO_MATRIX_ROW_ ## q ## _PIN
+#define row_pin(q)     AO_MATRIX_ROW_ ## q ## _PIN
+
+#define col_port(q)    AO_MATRIX_COL_ ## q ## _PORT
+#define col_bit(q)     AO_MATRIX_COL_ ## q ## _PIN
+#define col_pin(q)     AO_MATRIX_COL_ ## q ## _PIN
+
+static void
+_ao_matrix_drive_row(uint8_t row, uint8_t val)
+{
+       switch (row) {
+#define drive(n) case n: ao_gpio_set(row_port(n), row_bit(n), row_pin(n), val); break
+               drive(0);
+#if AO_MATRIX_ROWS > 1
+               drive(1);
+#endif
+#if AO_MATRIX_ROWS > 2
+               drive(2);
+#endif
+#if AO_MATRIX_ROWS > 3
+               drive(3);
+#endif
+#if AO_MATRIX_ROWS > 4
+               drive(4);
+#endif
+#if AO_MATRIX_ROWS > 5
+               drive(5);
+#endif
+#if AO_MATRIX_ROWS > 6
+               drive(6);
+#endif
+#if AO_MATRIX_ROWS > 7
+               drive(7);
+#endif
+       }
+}
+
+static uint8_t
+_ao_matrix_read_cols(void)
+{
+       uint8_t v = 0;
+#define read(n)        (v |= ao_gpio_get(col_port(n), col_bit(n), col_pin(n)) << n)
+
+       read(0);
+#if AO_MATRIX_ROWS > 1
+       read(1);
+#endif
+#if AO_MATRIX_ROWS > 2
+       read(2);
+#endif
+#if AO_MATRIX_ROWS > 3
+       read(3);
+#endif
+#if AO_MATRIX_ROWS > 4
+       read(4);
+#endif
+#if AO_MATRIX_ROWS > 5
+       read(5);
+#endif
+#if AO_MATRIX_ROWS > 6
+       read(6);
+#endif
+#if AO_MATRIX_ROWS > 7
+       read(7);
+#endif
+       return v;
+}
+
+static uint8_t
+_ao_matrix_read(uint8_t row) {
+       uint8_t state;
+       _ao_matrix_drive_row(row, 0);
+       state = _ao_matrix_read_cols();
+       _ao_matrix_drive_row(row, 1);
+       return state;
+}
+
+#define AO_MATRIX_DEBOUNCE_INTERVAL    AO_MS_TO_TICKS(50)
+
+static uint8_t ao_matrix_keymap[AO_MATRIX_ROWS][AO_MATRIX_COLS] = AO_MATRIX_KEYCODES;
+
+static uint8_t         ao_matrix_state[AO_MATRIX_ROWS];
+static AO_TICK_TYPE    ao_matrix_tick[AO_MATRIX_ROWS];
+
+static void
+_ao_matrix_poll_one(uint8_t row) {
+       uint8_t state = _ao_matrix_read(row);
+
+       if (state != ao_matrix_state[row]) {
+               AO_TICK_TYPE    now = ao_time();
+
+               if ((now - ao_matrix_tick[row]) >= AO_MATRIX_DEBOUNCE_INTERVAL) {
+                       uint8_t col;
+                       uint8_t changes = state ^ ao_matrix_state[row];
+
+                       for (col = 0; col < AO_MATRIX_COLS; col++) {
+                               if (changes & (1 << col)) {
+                                       ao_event_put_isr(AO_EVENT_KEY,
+                                                        ao_matrix_keymap[row][col],
+                                                        ((state >> col) & 1) == 0);
+                               }
+                       }
+                       ao_matrix_state[row] = state;
+               }
+               ao_matrix_tick[row] = now;
+       }
+}
+
+void
+ao_matrix_poll(void)
+{
+       uint8_t row;
+
+       for (row = 0; row < AO_MATRIX_ROWS; row++)
+               _ao_matrix_poll_one(row);
+}
+
+#define init_row(b) do {                                               \
+               ao_enable_output(row_port(b), row_bit(b), row_pin(v), 1); \
+               ao_gpio_set_output_mode(row_port(b), row_bit(b), row_pin(b), AO_OUTPUT_OPEN_DRAIN); \
+       } while (0)
+
+#define init_col(b) do { \
+               ao_enable_input(col_port(b), col_bit(b), AO_EXTI_MODE_PULL_UP); \
+       } while(0)
+
+void
+ao_matrix_init(void)
+{
+       uint8_t row;
+
+       init_row(0);
+#if AO_MATRIX_ROWS > 1
+       init_row(1);
+#endif
+#if AO_MATRIX_ROWS > 2
+       init_row(2);
+#endif
+#if AO_MATRIX_ROWS > 3
+       init_row(3);
+#endif
+#if AO_MATRIX_ROWS > 4
+       init_row(4);
+#endif
+#if AO_MATRIX_ROWS > 5
+       init_row(5);
+#endif
+#if AO_MATRIX_ROWS > 6
+       init_row(6);
+#endif
+#if AO_MATRIX_ROWS > 7
+       init_row(7);
+#endif
+
+       init_col(0);
+#if AO_MATRIX_COLS > 1
+       init_col(1);
+#endif
+#if AO_MATRIX_COLS > 2
+       init_col(2);
+#endif
+#if AO_MATRIX_COLS > 3
+       init_col(3);
+#endif
+#if AO_MATRIX_COLS > 4
+       init_col(4);
+#endif
+#if AO_MATRIX_COLS > 5
+       init_col(5);
+#endif
+#if AO_MATRIX_COLS > 6
+       init_col(6);
+#endif
+#if AO_MATRIX_COLS > 7
+       init_col(7);
+#endif
+       for (row = 0; row < AO_MATRIX_ROWS; row++) {
+               ao_matrix_state[row] = _ao_matrix_read(row);
+               ao_matrix_tick[row] = ao_time();
+       }
+}
diff --git a/src/drivers/ao_matrix.h b/src/drivers/ao_matrix.h
new file mode 100644 (file)
index 0000000..ab5a1c5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_MATRIX_H_
+#define _AO_MATRIX_H_
+
+void
+ao_matrix_poll(void);
+
+void
+ao_matrix_init(void);
+
+#endif /* _AO_MATRIX_H_ */
index ffa833fef341341eca543fe12077dbe578fd3c32..16b4ae60eb19e4d8ee23eff06f930a8fc12828a3 100644 (file)
@@ -316,7 +316,7 @@ ao_pad(void)
                        command.tick, command.box, ao_pad_box, command.cmd, command.channels);
 
                switch (command.cmd) {
-               case AO_LAUNCH_ARM:
+               case AO_PAD_ARM:
                        if (command.box != ao_pad_box) {
                                PRINTD ("box number mismatch\n");
                                break;
@@ -338,7 +338,7 @@ ao_pad(void)
                        ao_pad_arm_time = ao_time();
                        break;
 
-               case AO_LAUNCH_QUERY:
+               case AO_PAD_QUERY:
                        if (command.box != ao_pad_box) {
                                PRINTD ("box number mismatch\n");
                                break;
@@ -357,7 +357,7 @@ ao_pad(void)
                                query.igniter_status[3]);
                        ao_radio_cmac_send(&query, sizeof (query));
                        break;
-               case AO_LAUNCH_FIRE:
+               case AO_PAD_FIRE:
                        if (!ao_pad_armed) {
                                PRINTD ("not armed\n");
                                break;
@@ -372,6 +372,29 @@ ao_pad(void)
                        ao_pad_arm_time = ao_time();
                        ao_wakeup(&ao_pad_ignite);
                        break;
+               case AO_PAD_STATIC:
+                       if (!ao_pad_armed) {
+                               PRINTD ("not armed\n");
+                               break;
+                       }
+#if HAS_LOG
+                       if (!ao_log_running) ao_log_start();
+#endif
+                       if ((uint16_t) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) {
+                               PRINTD ("late pad arm_time %d time %d\n",
+                                       ao_pad_arm_time, ao_time());
+                               break;
+                       }
+                       PRINTD ("ignite\n");
+                       ao_pad_ignite = ao_pad_armed;
+                       ao_pad_arm_time = ao_time();
+                       ao_wakeup(&ao_pad_ignite);
+                       break;
+               case AO_PAD_ENDSTATIC:
+#if HAS_LOG
+                       ao_log_stop();
+#endif
+                       break;
                }
        }
 }
index 648d3005f000172babbfc594cebb6aeaa5bb86af..e41152224257db8ef4f74dca5bcbd6d88c48554d 100644 (file)
@@ -54,6 +54,11 @@ struct ao_pad_query {
  */
 #define AO_PAD_FIRE            3
 
+/* Fire current armed pads for 200ms, no report, logging test stand sensors
+ */
+#define AO_PAD_STATIC          4
+#define AO_PAD_ENDSTATIC       5
+
 #define AO_PAD_FIRE_TIME       AO_MS_TO_TICKS(200)
 
 #define AO_PAD_ARM_STATUS_DISARMED     0
diff --git a/src/drivers/ao_ps2.c b/src/drivers/ao_ps2.c
new file mode 100644 (file)
index 0000000..29eecea
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * 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_ps2.h"
+#include "ao_exti.h"
+
+static struct ao_fifo  ao_ps2_rx_fifo;
+
+static uint16_t                ao_ps2_tx;
+static uint8_t         ao_ps2_tx_count;
+
+static AO_TICK_TYPE    ao_ps2_tick;
+static uint16_t                ao_ps2_value;
+static uint8_t         ao_ps2_count;
+
+uint8_t                        ao_ps2_stdin;
+
+uint8_t                        ao_ps2_scancode_set;
+
+#define AO_PS2_CLOCK_MODE(pull) ((pull) | AO_EXTI_MODE_FALLING | AO_EXTI_PRIORITY_MED)
+
+static void
+ao_ps2_isr(void);
+
+static uint8_t
+_ao_ps2_parity(uint8_t value)
+{
+       uint8_t parity = 1;
+       uint8_t b;
+
+       for (b = 0; b < 8; b++) {
+               parity ^= (value & 1);
+               value >>= 1;
+       }
+       return parity;
+}
+
+static int
+_ao_ps2_poll(void)
+{
+       uint8_t u;
+       if (ao_fifo_empty(ao_ps2_rx_fifo)) {
+               return AO_READ_AGAIN;
+       }
+       ao_fifo_remove(ao_ps2_rx_fifo, u);
+
+       return (int) u;
+}
+
+uint8_t
+ao_ps2_get(void)
+{
+       int c;
+       ao_arch_block_interrupts();
+       while ((c = _ao_ps2_poll()) == AO_READ_AGAIN)
+               ao_sleep(&ao_ps2_rx_fifo);
+       ao_arch_release_interrupts();
+       return (uint8_t) c;
+}
+
+
+int
+ao_ps2_poll(void)
+{
+       int     c;
+       ao_arch_block_interrupts();
+       c = _ao_ps2_poll();
+       ao_arch_release_interrupts();
+       return (uint8_t) c;
+}
+
+void
+ao_ps2_put(uint8_t c)
+{
+       ao_arch_block_interrupts();
+       ao_ps2_tx = ((uint16_t) c) | (_ao_ps2_parity(c) << 8) | (3 << 9);
+       ao_ps2_tx_count = 11;
+       ao_exti_disable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT);
+       ao_arch_release_interrupts();
+
+       /* pull the clock pin down */
+       ao_enable_output(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, AO_PS2_CLOCK_PIN, 0);
+       ao_delay(0);
+
+       /* pull the data pin down for the start bit */
+       ao_enable_output(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, 0);
+       ao_delay(0);
+
+       /* switch back to input mode for the interrupt to work */
+       ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT,
+                     AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP),
+                     ao_ps2_isr);
+       ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT);
+
+       /* wait for the bits to drain */
+       while (ao_ps2_tx_count)
+               ao_sleep(&ao_ps2_tx_count);
+
+}
+
+static uint8_t ao_ps2_down[128 / 8];
+
+static void
+ao_ps2_set_down(uint8_t code, uint8_t value)
+{
+       uint8_t shift = (code & 0x07);
+       uint8_t byte = code >> 3;
+
+       ao_ps2_down[byte] = (ao_ps2_down[byte] & ~(1 << shift)) | (value << shift);
+}
+
+uint8_t
+ao_ps2_is_down(uint8_t code)
+{
+       uint8_t shift = (code & 0x07);
+       uint8_t byte = code >> 3;
+
+       return (ao_ps2_down[byte] >> shift) & 1;
+}
+
+static void
+_ao_ps2_set_leds(void)
+{
+       uint8_t led = 0;
+       if (ao_ps2_is_down(AO_PS2_CAPS_LOCK))
+               led |= AO_PS2_SET_LEDS_CAPS;
+       if (ao_ps2_is_down(AO_PS2_NUM_LOCK))
+               led |= AO_PS2_SET_LEDS_NUM;
+       if (ao_ps2_is_down(AO_PS2_SCROLL_LOCK))
+               led |= AO_PS2_SET_LEDS_SCROLL;
+       ao_arch_release_interrupts();
+       ao_ps2_put(AO_PS2_SET_LEDS);
+       while (ao_ps2_get() != 0xfa);
+       ao_ps2_put(led);
+       ao_arch_block_interrupts();
+}
+
+static uint8_t
+ao_ps2_is_lock(uint8_t code) {
+       switch (code) {
+       case AO_PS2_CAPS_LOCK:
+       case AO_PS2_NUM_LOCK:
+       case AO_PS2_SCROLL_LOCK:
+               return 1;
+       }
+       return 0;
+}
+
+static void
+_ao_ps2_set_scancode_set(uint8_t set)
+{
+       ao_ps2_scancode_set = set;
+       ao_arch_release_interrupts();
+       ao_ps2_put(AO_PS2_SET_SCAN_CODE_SET);
+       while (ao_ps2_get() != 0xfa);
+       ao_ps2_put(set);
+       ao_ps2_put(AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK);
+       while (ao_ps2_get() != 0xfa);
+       ao_arch_block_interrupts();
+}
+
+static int
+_ao_ps2_poll_key(void)
+{
+       int     c;
+       uint8_t set_led = 0;
+       static uint8_t  saw_break;
+
+       c = _ao_ps2_poll();
+       if (c < 0) {
+               if (ao_ps2_scancode_set != 3) {
+                       _ao_ps2_set_scancode_set(3);
+               }
+               return c;
+       }
+
+       if (c == AO_PS2_BREAK) {
+               saw_break = 1;
+               return AO_READ_AGAIN;
+       }
+       if (c & 0x80)
+               return AO_READ_AGAIN;
+
+       if (ao_ps2_is_lock(c)) {
+               if (saw_break) {
+                       saw_break = 0;
+                       return AO_READ_AGAIN;
+               }
+               if (ao_ps2_is_down(c))
+                       saw_break = 1;
+               set_led = 1;
+       }
+       if (saw_break) {
+               saw_break = 0;
+               ao_ps2_set_down(c, 0);
+               c |= 0x80;
+       } else
+               ao_ps2_set_down(c, 1);
+       if (set_led)
+               _ao_ps2_set_leds();
+
+       if (ao_ps2_scancode_set != 3)
+               _ao_ps2_set_scancode_set(3);
+
+       return c;
+}
+
+int
+ao_ps2_poll_key(void)
+{
+       int     c;
+       ao_arch_block_interrupts();
+       c = _ao_ps2_poll_key();
+       ao_arch_release_interrupts();
+       return c;
+}
+
+uint8_t
+ao_ps2_get_key(void)
+{
+       int     c;
+       ao_arch_block_interrupts();
+       while ((c = _ao_ps2_poll_key()) == AO_READ_AGAIN)
+               ao_sleep(&ao_ps2_rx_fifo);
+       ao_arch_release_interrupts();
+       return (uint8_t) c;
+}
+
+static const uint8_t   ao_ps2_asciimap[128][2] = {
+       [AO_PS2_A] = { 'a', 'A' },
+       [AO_PS2_B] = { 'b', 'B' },
+       [AO_PS2_C] = { 'c', 'C' },
+       [AO_PS2_D] = { 'd', 'D' },
+       [AO_PS2_E] = { 'e', 'E' },
+       [AO_PS2_F] = { 'f', 'F' },
+       [AO_PS2_G] = { 'g', 'G' },
+       [AO_PS2_H] = { 'h', 'H' },
+       [AO_PS2_I] = { 'i', 'I' },
+       [AO_PS2_J] = { 'j', 'J' },
+       [AO_PS2_K] = { 'k', 'K' },
+       [AO_PS2_L] = { 'l', 'L' },
+       [AO_PS2_M] = { 'm', 'M' },
+       [AO_PS2_N] = { 'n', 'N' },
+       [AO_PS2_O] = { 'o', 'O' },
+       [AO_PS2_P] = { 'p', 'P' },
+       [AO_PS2_Q] = { 'q', 'Q' },
+       [AO_PS2_R] = { 'r', 'R' },
+       [AO_PS2_S] = { 's', 'S' },
+       [AO_PS2_T] = { 't', 'T' },
+       [AO_PS2_U] = { 'u', 'U' },
+       [AO_PS2_V] = { 'v', 'V' },
+       [AO_PS2_W] = { 'w', 'W' },
+       [AO_PS2_X] = { 'x', 'X' },
+       [AO_PS2_Y] = { 'y', 'Y' },
+       [AO_PS2_Z] = { 'z', 'Z' },
+
+       [AO_PS2_0] = { '0', ')' },
+       [AO_PS2_1] = { '1', '!' },
+       [AO_PS2_2] = { '2', '@' },
+       [AO_PS2_3] = { '3', '#' },
+       [AO_PS2_4] = { '4', '$' },
+       [AO_PS2_5] = { '5', '%' },
+       [AO_PS2_6] = { '6', '^' },
+       [AO_PS2_7] = { '7', '&' },
+       [AO_PS2_8] = { '8', '*' },
+       [AO_PS2_9] = { '9', '(' },
+
+       [AO_PS2_GRAVE] = { '`', '~' },
+       [AO_PS2_HYPHEN] = { '-', '_' },
+       [AO_PS2_EQUAL] = { '=', '+' },
+       [AO_PS2_BACKSLASH] = { '\\', '|' },
+       [AO_PS2_BACKSPACE] = { '\010', '\010' },
+       [AO_PS2_SPACE] = { ' ', ' ' },
+       [AO_PS2_TAB] = { '\t', '\t' },
+
+       [AO_PS2_ENTER] = { '\r', '\r' },
+       [AO_PS2_ESC] = { '\033', '\033' },
+
+       [AO_PS2_OPEN_SQ] = { '[', '{' },
+       [AO_PS2_DELETE] = { '\177', '\177' },
+
+       [AO_PS2_KP_TIMES] = { '*', '*' },
+       [AO_PS2_KP_PLUS] = { '+', '+' },
+       [AO_PS2_KP_ENTER] = { '\r', '\r' },
+       [AO_PS2_KP_DECIMAL] = { '.', '.' },
+       [AO_PS2_KP_0] = { '0', '0' },
+       [AO_PS2_KP_1] = { '1', '1' },
+       [AO_PS2_KP_2] = { '2', '2' },
+       [AO_PS2_KP_3] = { '3', '3' },
+       [AO_PS2_KP_4] = { '4', '4' },
+       [AO_PS2_KP_5] = { '5', '5' },
+       [AO_PS2_KP_6] = { '6', '6' },
+       [AO_PS2_KP_7] = { '7', '7' },
+       [AO_PS2_KP_8] = { '8', '8' },
+       [AO_PS2_KP_9] = { '9', '9' },
+       [AO_PS2_CLOSE_SQ] = { ']', '}' },
+       [AO_PS2_SEMICOLON] = { ';', ':' },
+       [AO_PS2_ACUTE] = { '\'', '"' },
+       [AO_PS2_COMMA] = { ',', '<' },
+       [AO_PS2_PERIOD] = { '.', '>' },
+       [AO_PS2_SLASH] = { '/', '?' },
+};
+
+int
+ao_ps2_ascii(uint8_t key)
+{
+       uint8_t col;
+       char a;
+
+       /* Skip key releases */
+       if (key & 0x80)
+               return AO_READ_AGAIN;
+
+       col = 0;
+       if (ao_ps2_is_down(AO_PS2_L_SHIFT) || ao_ps2_is_down(AO_PS2_R_SHIFT))
+               col = 1;
+
+       /* caps lock */
+       a = ao_ps2_asciimap[key][0];
+       if (!a)
+               return AO_READ_AGAIN;
+
+       if ('a' <= a && a <= 'z')
+               if (ao_ps2_is_down(AO_PS2_CAPS_LOCK))
+                       col ^= 1;
+       a = ao_ps2_asciimap[key][col];
+       if ('@' <= a && a <= 0x7f && (ao_ps2_is_down(AO_PS2_L_CTRL) || ao_ps2_is_down(AO_PS2_R_CTRL)))
+               a &= 0x1f;
+       return a;
+}
+
+int
+_ao_ps2_pollchar(void)
+{
+       int     key;
+
+       key = _ao_ps2_poll_key();
+       if (key < 0)
+               return key;
+       return ao_ps2_ascii(key);
+}
+
+char
+ao_ps2_getchar(void)
+{
+       int     c;
+       ao_arch_block_interrupts();
+       while ((c = _ao_ps2_pollchar()) == AO_READ_AGAIN)
+               ao_sleep(&ao_ps2_rx_fifo);
+       ao_arch_release_interrupts();
+       return (char) c;
+}
+
+static void
+ao_ps2_isr(void)
+{
+       uint8_t bit;
+
+       if (ao_ps2_tx_count) {
+               ao_gpio_set(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, ao_ps2_tx&1);
+               ao_ps2_tx >>= 1;
+               ao_ps2_tx_count--;
+               if (!ao_ps2_tx_count) {
+                       ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_EXTI_MODE_PULL_UP);
+                       ao_wakeup(&ao_ps2_tx_count);
+               }
+               return;
+       }
+       /* reset if its been a while */
+       if ((ao_tick_count - ao_ps2_tick) > AO_MS_TO_TICKS(100))
+               ao_ps2_count = 0;
+       ao_ps2_tick = ao_tick_count;
+
+       bit = ao_gpio_get(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN);
+       if (ao_ps2_count == 0) {
+               /* check for start bit, ignore if not zero */
+               if (bit)
+                       return;
+               ao_ps2_value = 0;
+       } else if (ao_ps2_count < 9) {
+               ao_ps2_value |= (bit << (ao_ps2_count - 1));
+       } else if (ao_ps2_count == 10) {
+               ao_fifo_insert(ao_ps2_rx_fifo, ao_ps2_value);
+               ao_wakeup(&ao_ps2_rx_fifo);
+               if (ao_ps2_stdin)
+                       ao_wakeup(&ao_stdin_ready);
+               ao_ps2_count = 0;
+               return;
+       }
+       ao_ps2_count++;
+}
+
+void
+ao_ps2_init(void)
+{
+       ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT,
+                       AO_EXTI_MODE_PULL_UP);
+
+       ao_enable_port(AO_PS2_CLOCK_PORT);
+
+       ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT,
+                     AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP),
+                     ao_ps2_isr);
+       ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT);
+
+       ao_ps2_scancode_set = 2;
+}
diff --git a/src/drivers/ao_ps2.h b/src/drivers/ao_ps2.h
new file mode 100644 (file)
index 0000000..f1f05ee
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * 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_PS2_H_
+#define _AO_PS2_H_
+
+extern uint8_t                 ao_ps2_stdin;
+
+int
+ao_ps2_poll(void);
+
+uint8_t
+ao_ps2_get(void);
+
+void
+ao_ps2_put(uint8_t b);
+
+uint8_t
+ao_ps2_is_down(uint8_t code);
+
+int
+ao_ps2_poll_key(void);
+
+uint8_t
+ao_ps2_get_key(void);
+
+int
+ao_ps2_ascii(uint8_t key);
+
+int
+_ao_ps2_pollchar(void);
+
+char
+ao_ps2_getchar(void);
+
+void
+ao_ps2_init(void);
+
+/* From http://computer-engineering.org/ps2keyboard/ */
+
+/* Device responds with ACK and then resets */
+#define AO_PS2_RESET                           0xff
+
+/* Device retransmits last byte */
+#define AO_PS2_RESEND                          0xfe
+
+/* Setting key report only works in mode 3 */
+
+/* Disable break and typematic for specified mode 3 keys. Terminate with invalid key */
+#define AO_PS2_SET_KEY_MAKE                    0xfd
+
+/* Disable typematic for keys */
+#define AO_PS2_SET_KEY_MAKE_BREAK              0xfc
+
+/* Disable break code for keys */
+#define AO_PS2_SET_KEY_TYPEMATIC               0xfb
+
+/* Enable make, break and typematic */
+#define AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK    0xfa
+
+/* Disable break and typematic for all */
+#define AO_PS2_SET_ALL_MAKE                    0xf9
+
+/* Disable typematic for all */
+#define AO_PS2_SET_ALL_MAKE_BREAK              0xf8
+
+/* Disable break for all */
+#define AO_PS2_SET_ALL_TYPEMATIC               0xf7
+
+/* Set keyboard to default (repeat, report and scan code set 2) */
+#define AO_PS2_SET_DEFAULT                     0xf6
+
+/* Disable and reset to default */
+#define AO_PS2_DISABLE                         0xf5
+
+/* Enable */
+#define AO_PS2_ENABLE                          0xf4
+
+/* Set repeat rate. Bytes 5-6 are the start delay, bits 0-4 are the rate */
+#define AO_PS2_SET_REPEAT_RATE                 0xf3
+
+/* Read keyboard id. Returns two bytes */
+#define AO_PS2_GETID                           0xf2
+
+/* Set scan code (1, 2, or 3) */
+#define AO_PS2_SET_SCAN_CODE_SET               0xf0
+
+/* Echo. Keyboard replies with Echo */
+#define AO_PS2_ECHO                            0xee
+
+/* Set LEDs */
+#define AO_PS2_SET_LEDS                                0xed
+# define AO_PS2_SET_LEDS_SCROLL                        0x01
+# define AO_PS2_SET_LEDS_NUM                   0x02
+# define AO_PS2_SET_LEDS_CAPS                  0x04
+
+#define AO_PS2_BREAK                           0xf0
+#define AO_PS2_ACK                             0xfa
+#define AO_PS2_ERROR                           0xfc
+#define AO_PS2_NAK                             0xfe
+
+/* Scan code set 3 */
+
+#define AO_PS2_A               0x1c
+#define AO_PS2_B               0x32
+#define AO_PS2_C               0x21
+#define AO_PS2_D               0x23
+#define AO_PS2_E               0x24
+#define AO_PS2_F               0x2b
+#define AO_PS2_G               0x34
+#define AO_PS2_H               0x33
+#define AO_PS2_I               0x43
+#define AO_PS2_J               0x3b
+#define AO_PS2_K               0x42
+#define AO_PS2_L               0x4b
+#define AO_PS2_M               0x3a
+#define AO_PS2_N               0x31
+#define AO_PS2_O               0x44
+#define AO_PS2_P               0x4d
+#define AO_PS2_Q               0x15
+#define AO_PS2_R               0x2d
+#define AO_PS2_S               0x1b
+#define AO_PS2_T               0x2c
+#define AO_PS2_U               0x3c
+#define AO_PS2_V               0x2a
+#define AO_PS2_W               0x1d
+#define AO_PS2_X               0x22
+#define AO_PS2_Y               0x35
+#define AO_PS2_Z               0x1a
+#define AO_PS2_0               0x45
+#define AO_PS2_1               0x16
+#define AO_PS2_2               0x1e
+#define AO_PS2_3               0x26
+#define AO_PS2_4               0x25
+#define AO_PS2_5               0x2e
+#define AO_PS2_6               0x36
+#define AO_PS2_7               0x3d
+#define AO_PS2_8               0x3e
+#define AO_PS2_9               0x46
+#define AO_PS2_GRAVE           0x0e
+#define AO_PS2_HYPHEN          0x4e
+#define AO_PS2_EQUAL           0x55
+#define AO_PS2_BACKSLASH       0x5c
+#define AO_PS2_BACKSPACE       0x66
+#define AO_PS2_SPACE           0x29
+#define AO_PS2_TAB             0x0d
+#define AO_PS2_CAPS_LOCK       0x14
+#define AO_PS2_L_SHIFT         0x12
+#define AO_PS2_L_CTRL          0x11
+#define AO_PS2_L_WIN           0x8b
+#define AO_PS2_L_ALT           0x19
+#define AO_PS2_R_SHIFT         0x59
+#define AO_PS2_R_CTRL          0x58
+#define AO_PS2_R_WIN           0x8c
+#define AO_PS2_R_ALT           0x39
+#define AO_PS2_APPS            0x8d
+#define AO_PS2_ENTER           0x5a
+#define AO_PS2_ESC             0x08
+#define AO_PS2_F1              0x07
+#define AO_PS2_F2              0x0f
+#define AO_PS2_F3              0x17
+#define AO_PS2_F4              0x1f
+#define AO_PS2_F5              0x27
+#define AO_PS2_F6              0x2f
+#define AO_PS2_F7              0x37
+#define AO_PS2_F8              0x3f
+#define AO_PS2_F9              0x47
+#define AO_PS2_F10             0x4f
+#define AO_PS2_F11             0x56
+#define AO_PS2_F12             0x5e
+#define AO_PS2_PRNT_SCRN       0x57
+#define AO_PS2_SCROLL_LOCK     0x5f
+#define AO_PS2_PAUSE           0x62
+#define AO_PS2_OPEN_SQ         0x54
+#define AO_PS2_INSERT          0x67
+#define AO_PS2_HOME            0x6e
+#define AO_PS2_PG_UP           0x6f
+#define AO_PS2_DELETE          0x64
+#define AO_PS2_END             0x65
+#define AO_PS2_PG_DN           0x6d
+#define AO_PS2_UP              0x63
+#define AO_PS2_LEFT            0x61
+#define AO_PS2_DOWN            0x60
+#define AO_PS2_RIGHT           0x6a
+#define AO_PS2_NUM_LOCK                0x76
+#define AO_PS2_KP_TIMES                0x7e
+#define AO_PS2_KP_PLUS         0x7c
+#define AO_PS2_KP_ENTER                0x79
+#define AO_PS2_KP_DECIMAL      0x71
+#define AO_PS2_KP_0            0x70
+#define AO_PS2_KP_1            0x69
+#define AO_PS2_KP_2            0x72
+#define AO_PS2_KP_3            0x7a
+#define AO_PS2_KP_4            0x6b
+#define AO_PS2_KP_5            0x73
+#define AO_PS2_KP_6            0x74
+#define AO_PS2_KP_7            0x6c
+#define AO_PS2_KP_8            0x75
+#define AO_PS2_KP_9            0x7d
+#define AO_PS2_CLOSE_SQ                0x5b
+#define AO_PS2_SEMICOLON       0x4c
+#define AO_PS2_ACUTE           0x52
+#define AO_PS2_COMMA           0x41
+#define AO_PS2_PERIOD          0x49
+#define AO_PS2_SLASH           0x4a
+
+#define AO_PS2_RELEASE_FLAG    0x80
+
+#endif /* _AO_PS2_H_ */
index 4b17c5e3ebac427c2d3856a3485f8306ee23afe0..45454000f663c6c662af747fa71cfab83d465835 100644 (file)
@@ -38,13 +38,19 @@ extern uint8_t ao_radio_mutex;
 #define ao_sdcard_deselect()           ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1)
 
 /* Include SD card commands */
+#ifndef SDCARD_DEBUG
 #define SDCARD_DEBUG   0
+#endif
 
 /* Spew SD tracing */
+#ifndef SDCARD_TRACE
 #define SDCARD_TRACE   0
+#endif
 
 /* Emit error and warning messages */
+#ifndef SDCARD_WARN
 #define SDCARD_WARN    0
+#endif
 
 static uint8_t initialized;
 static uint8_t present;
diff --git a/src/drivers/ao_vga.c b/src/drivers/ao_vga.c
new file mode 100644 (file)
index 0000000..909e310
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * 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_vga.h"
+
+/* VGA output from the SPI port
+ *
+ * Connections:
+ *
+ *                     STM     VGA
+ *     GND                     4,6,7,8,9,10
+ *     HSYNC           PA5     13
+ *     VSYNC           PB5     14
+ *     RGB             PB4     1,2,3
+ *
+ *     pixel clock     PA8 -> PB3
+ *     pixel enable    PA1 -> PA15
+ */
+
+/* GRF formula for 640x480 yields a pixel clock very close to 24MHz. Pad by
+ * three scanlines to hit exactly that value
+ */
+
+#define HACTIVE        (640)
+#define HSYNC_START    (656)
+#define HSYNC_END      (720)
+#define HTOTAL         (800)
+
+#define        VACTIVE         480
+#define VSYNC_START    481
+#define VSYNC_END      484
+#define VTOTAL         500
+
+/*
+ * The horizontal counter is set so that the end of hsync is reached
+ * at the maximum counter value. That means that the hblank interval
+ * is offset by HSYNC_END.
+ */
+
+#define HSYNC          (HSYNC_END - HSYNC_START)
+#define HBLANK_END     (HTOTAL - HSYNC_END)
+#define HBLANK_START   (HBLANK_END + HACTIVE)
+
+/*
+ * The vertical counter is set so that the end of vsync is reached at
+ * the maximum counter value.  That means that the vblank interval is
+ * offset by VSYNC_END. We send a blank line at the start of the
+ * frame, so each of these is off by one
+ */
+#define VSYNC          (VSYNC_END - VSYNC_START)
+#define VBLANK_END     (VTOTAL - VSYNC_END)
+#define VBLANK_START   (VBLANK_END + VACTIVE)
+
+#define WIDTH_BYTES    (AO_VGA_WIDTH >> 3)
+#define SCANOUT                ((WIDTH_BYTES+2) >> 1)
+
+uint32_t       ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT];
+
+const struct ao_bitmap ao_vga_bitmap = {
+       .base = ao_vga_fb,
+       .stride = AO_VGA_STRIDE,
+       .width = AO_VGA_WIDTH,
+       .height = AO_VGA_HEIGHT
+};
+
+static uint32_t        *scanline;
+
+#define DMA_INDEX      STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX)
+
+#define DMA_CCR(en)    ((0 << STM_DMA_CCR_MEM2MEM) |                   \
+                        (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) | \
+                        (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) |  \
+                        (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) |  \
+                        (1 << STM_DMA_CCR_MINC) |                      \
+                        (0 << STM_DMA_CCR_PINC) |                      \
+                        (0 << STM_DMA_CCR_CIRC) |                      \
+                        (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | \
+                        (0 << STM_DMA_CCR_TCIE) |                      \
+                        (en << STM_DMA_CCR_EN))
+
+
+void stm_tim2_isr(void)
+{
+       int16_t line = stm_tim3.cnt;
+
+       if (VBLANK_END <= line && line < VBLANK_START) {
+               /* Disable */
+               stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(0);
+               /* Reset DMA engine for the next scanline */
+               stm_dma.channel[DMA_INDEX].cmar = scanline;
+               stm_dma.channel[DMA_INDEX].cndtr = SCANOUT;
+
+               /* reset SPI */
+               (void) stm_spi1.dr;
+               (void) stm_spi1.sr;
+
+               /* Enable */
+               stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(1);
+               if (((line - VBLANK_END) & 1))
+                       scanline += AO_VGA_STRIDE;
+       } else {
+               scanline = ao_vga_fb;
+       }
+       stm_tim2.sr = 0;
+}
+
+
+void
+ao_vga_init(void)
+{
+       uint32_t        cfgr;
+
+       /* Initialize spi1 using MISO PB4 for output */
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+
+       stm_ospeedr_set(&stm_gpiob, 4, STM_OSPEEDR_40MHz);
+       stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
+       stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
+       stm_afr_set(&stm_gpioa, 15, STM_AFR_AF5);
+
+       /* turn on SPI */
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+
+       stm_spi1.cr1 = ((1 << STM_SPI_CR1_BIDIMODE) |           /* Two wire mode */
+                       (1 << STM_SPI_CR1_BIDIOE) |
+                       (0 << STM_SPI_CR1_CRCEN) |              /* CRC disabled */
+                       (0 << STM_SPI_CR1_CRCNEXT) |
+                       (1 << STM_SPI_CR1_DFF) |
+                       (0 << STM_SPI_CR1_RXONLY) |             /* transmit, not receive */
+                       (0 << STM_SPI_CR1_SSM) |                /* Software SS handling */
+                       (1 << STM_SPI_CR1_SSI) |                /*  ... */
+                       (1 << STM_SPI_CR1_LSBFIRST) |           /* Little endian */
+                       (1 << STM_SPI_CR1_SPE) |                /* Enable SPI unit */
+                       (0 << STM_SPI_CR1_BR) |                 /* baud rate to pclk/2 */
+                       (0 << STM_SPI_CR1_MSTR) |               /* slave */
+                       (0 << STM_SPI_CR1_CPOL) |               /* Format 0 */
+                       (0 << STM_SPI_CR1_CPHA));
+       stm_spi1.cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (1 << STM_SPI_CR2_TXDMAEN) |
+                       (0 << STM_SPI_CR2_RXDMAEN));
+
+       (void) stm_spi1.dr;
+       (void) stm_spi1.sr;
+
+       /* Grab the DMA channel for SPI1 MOSI */
+       stm_dma.channel[DMA_INDEX].cpar = &stm_spi1.dr;
+       stm_dma.channel[DMA_INDEX].cmar = ao_vga_fb;
+
+       /*
+        * Hsync Configuration
+        */
+       /* Turn on timer 2 */
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM2EN);
+
+       /* tim2 runs at full speed */
+       stm_tim2.psc = 0;
+
+       /* Disable channels while modifying */
+       stm_tim2.ccer = 0;
+
+       /* Channel 1 hsync PWM values */
+       stm_tim2.ccr1 = HSYNC;
+
+       /* Channel 2 trigger scanout */
+       /* wait for the time to start scanout */
+       stm_tim2.ccr2 = HBLANK_END;
+
+       stm_tim2.ccr3 = 32;
+
+       /* Configure channel 1 to output on the pin and
+        * channel 2 to to set the trigger for the vsync timer
+        */
+       stm_tim2.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
+                         (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M)  |
+                         (1 << STM_TIM234_CCMR1_OC2PE) |
+                         (0 << STM_TIM234_CCMR1_OC2FE) |
+                         (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) |
+
+                         (0 << STM_TIM234_CCMR1_OC1CE) |
+                         (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M)  |
+                         (1 << STM_TIM234_CCMR1_OC1PE) |
+                         (0 << STM_TIM234_CCMR1_OC1FE) |
+                         (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
+
+       stm_tim2.ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) |
+                         (0 << STM_TIM234_CCMR2_OC4M)  |
+                         (0 << STM_TIM234_CCMR2_OC4PE) |
+                         (0 << STM_TIM234_CCMR2_OC4FE) |
+                         (0 << STM_TIM234_CCMR2_CC4S) |
+
+                         (0 << STM_TIM234_CCMR2_OC3CE) |
+                         (STM_TIM234_CCMR2_OC3M_PWM_MODE_1 << STM_TIM234_CCMR2_OC3M)  |
+                         (1 << STM_TIM234_CCMR2_OC3PE) |
+                         (0 << STM_TIM234_CCMR2_OC3FE) |
+                         (0 << STM_TIM234_CCMR2_CC3S));
+
+       /* One scanline */
+       stm_tim2.arr = HTOTAL;
+
+       stm_tim2.cnt = 0;
+
+       /* Update the register contents */
+       stm_tim2.egr |= (1 << STM_TIM234_EGR_UG);
+
+       /* Enable the timer */
+
+       /* Enable the output */
+       stm_tim2.ccer = ((0 << STM_TIM234_CCER_CC2NP) |
+                        (STM_TIM234_CCER_CC2P_ACTIVE_HIGH << STM_TIM234_CCER_CC2P) |
+                        (1 << STM_TIM234_CCER_CC2E) |
+                        (0 << STM_TIM234_CCER_CC1NP) |
+                        (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) |
+                        (1 << STM_TIM234_CCER_CC1E));
+
+       stm_tim2.cr2 = ((0 << STM_TIM234_CR2_TI1S) |
+                       (STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) |
+                       (0 << STM_TIM234_CR2_CCDS));
+
+       /* hsync is not a slave timer */
+       stm_tim2.smcr = 0;
+
+       /* Send an interrupt on channel 3 */
+       stm_tim2.dier = ((1 << STM_TIM234_DIER_CC3IE));
+
+       stm_tim2.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
+                       (1 << STM_TIM234_CR1_ARPE) |
+                       (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
+                       (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) |
+                       (0 << STM_TIM234_CR1_OPM) |
+                       (1 << STM_TIM234_CR1_URS) |
+                       (0 << STM_TIM234_CR1_UDIS) |
+                       (0 << STM_TIM234_CR1_CEN));
+
+       /* Hsync is on PA5 which is Timer 2 CH1 output */
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+       stm_ospeedr_set(&stm_gpioa, 5, STM_OSPEEDR_40MHz);
+       stm_afr_set(&stm_gpioa, 5, STM_AFR_AF1);
+
+       /* pixel transmit enable is on PA1 */
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+       stm_ospeedr_set(&stm_gpioa, 1, STM_OSPEEDR_40MHz);
+       stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1);
+
+       /*
+        * Vsync configuration
+        */
+
+       /* Turn on timer 3, slaved to timer 1 using ITR1 (table 61) */
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM3EN);
+
+       /* No prescale */
+       stm_tim3.psc = 0;
+
+       /* Channel 1 or 2 vsync PWM values */
+       stm_tim3.ccr1 = VSYNC;
+       stm_tim3.ccr2 = VSYNC;
+
+       stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
+                         (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M)  |
+                         (1 << STM_TIM234_CCMR1_OC2PE) |
+                         (0 << STM_TIM234_CCMR1_OC2FE) |
+                         (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) |
+
+                         (0 << STM_TIM234_CCMR1_OC1CE) |
+                         (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M)  |
+                         (1 << STM_TIM234_CCMR1_OC1PE) |
+                         (0 << STM_TIM234_CCMR1_OC1FE) |
+                         (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
+
+       stm_tim3.arr = VTOTAL;
+       stm_tim3.cnt = 0;
+
+       /* Update the register contents */
+       stm_tim3.egr |= (1 << STM_TIM234_EGR_UG);
+
+       /* Enable the timer */
+
+       /* Enable the output */
+       stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC1NP) |
+                        (STM_TIM234_CCER_CC2P_ACTIVE_LOW << STM_TIM234_CCER_CC2P) |
+                        (1 << STM_TIM234_CCER_CC2E) |
+                        (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) |
+                        (1 << STM_TIM234_CCER_CC1E));
+
+       stm_tim3.cr2 = ((0 << STM_TIM234_CR2_TI1S) |
+                       (STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) |
+                       (0 << STM_TIM234_CR2_CCDS));
+
+       stm_tim3.smcr = 0;
+       stm_tim3.smcr = ((0 << STM_TIM234_SMCR_ETP) |
+                        (0 << STM_TIM234_SMCR_ECE) |
+                        (STM_TIM234_SMCR_ETPS_OFF << STM_TIM234_SMCR_ETPS) |
+                        (STM_TIM234_SMCR_ETF_NONE << STM_TIM234_SMCR_ETF) |
+                        (0 << STM_TIM234_SMCR_MSM) |
+                        (STM_TIM234_SMCR_TS_ITR1 << STM_TIM234_SMCR_TS) |
+                        (0 << STM_TIM234_SMCR_OCCS) |
+                        (STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK << STM_TIM234_SMCR_SMS));
+
+       stm_tim3.dier = 0;
+
+       stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
+                       (1 << STM_TIM234_CR1_ARPE) |
+                       (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
+                       (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) |
+                       (0 << STM_TIM234_CR1_OPM) |
+                       (1 << STM_TIM234_CR1_URS) |
+                       (0 << STM_TIM234_CR1_UDIS) |
+                       (1 << STM_TIM234_CR1_CEN));
+
+       /* Vsync is on PB5 which is is Timer 3 CH2 output */
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+       stm_ospeedr_set(&stm_gpiob, 5, STM_OSPEEDR_40MHz);
+       stm_afr_set(&stm_gpiob, 5, STM_AFR_AF2);
+
+       /* Use MCO for the pixel clock, that appears on PA8 */
+       cfgr = stm_rcc.cfgr & ~((STM_RCC_CFGR_MCOPRE_MASK << STM_RCC_CFGR_MCOPRE) |
+                               (STM_RCC_CFGR_MCOSEL_MASK << STM_RCC_CFGR_MCOSEL));
+
+       cfgr |= ((STM_RCC_CFGR_MCOPRE_DIV_2 << STM_RCC_CFGR_MCOPRE) |
+                (STM_RCC_CFGR_MCOSEL_SYSCLK << STM_RCC_CFGR_MCOSEL));
+
+       stm_rcc.cfgr = cfgr;
+
+       stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz);
+       stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0);
+
+       /* Enable the scanline interrupt */
+       stm_nvic_set_priority(STM_ISR_TIM2_POS, AO_STM_NVIC_NONMASK_PRIORITY);
+       stm_nvic_set_enable(STM_ISR_TIM2_POS);
+}
+
+uint8_t        enabled;
+
+void
+ao_vga_enable(int enable)
+{
+       if (enable) {
+               if (!enabled) {
+                       ++ao_task_minimize_latency;
+                       enabled = 1;
+               }
+               stm_tim2.cr1 |= (1 << STM_TIM234_CR1_CEN);
+       } else {
+               if (enabled) {
+                       --ao_task_minimize_latency;
+                       enabled = 0;
+               }
+               stm_tim2.cr1 &= ~(1 << STM_TIM234_CR1_CEN);
+       }
+}
diff --git a/src/drivers/ao_vga.h b/src/drivers/ao_vga.h
new file mode 100644 (file)
index 0000000..7d9d6b3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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_VGA_H_
+#define _AO_VGA_H_
+
+#include "ao_draw.h"
+
+void
+ao_vga_init(void);
+
+void
+ao_vga_enable(int active);
+
+/* Active frame buffer */
+#define AO_VGA_WIDTH           320
+#define AO_VGA_HEIGHT          240
+
+/* Pad on the right so that there are zeros on the output after the line */
+#define AO_VGA_HPAD            32
+
+#define AO_VGA_STRIDE          ((AO_VGA_WIDTH + AO_VGA_HPAD) >> AO_SHIFT)
+
+extern uint32_t        ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT];
+
+extern const struct ao_bitmap ao_vga_bitmap;
+
+#endif /* _AO_VGA_H_ */
index fb41d7a9ff8b024ac133f879cdac222d5ec05b3e..e56fbb2e4acec01b99a3ce4af8e37147fffc49bf 100644 (file)
@@ -170,6 +170,9 @@ void
 ao_put_string(__code char *s);
 
 void
+ao_cmd_readline(void);
+
+char
 ao_cmd_lex(void);
 
 void
@@ -853,33 +856,6 @@ struct ao_fifo {
 #include <ao_aes.h>
 #endif
 
-/* ao_launch.c */
-
-struct ao_launch_command {
-       uint16_t        tick;
-       uint16_t        serial;
-       uint8_t         cmd;
-       uint8_t         channel;
-       uint16_t        unused;
-};
-
-#define AO_LAUNCH_QUERY                1
-
-struct ao_launch_query {
-       uint16_t        tick;
-       uint16_t        serial;
-       uint8_t         channel;
-       uint8_t         valid;
-       uint8_t         arm_status;
-       uint8_t         igniter_status;
-};
-
-#define AO_LAUNCH_ARM          2
-#define AO_LAUNCH_FIRE         3
-
-void
-ao_launch_init(void);
-
 /*
  * ao_log_single.c
  */
index 10716afd5e8e0ffe9fab17fb459874a6dfa748d5..881f3500ab7efd4c4d5dd992eef09269a3c0d11b 100644 (file)
@@ -24,13 +24,15 @@ __pdata uint32_t ao_cmd_lex_u32;
 __pdata char   ao_cmd_lex_c;
 __pdata enum ao_cmd_status ao_cmd_status;
 
+#ifndef AO_CMD_LEN
 #if AO_PYRO_NUM
-#define CMD_LEN 128
+#define AO_CMD_LEN 128
 #else
-#define CMD_LEN        48
+#define AO_CMD_LEN     48
+#endif
 #endif
 
-static __xdata char    cmd_line[CMD_LEN];
+static __xdata char    cmd_line[AO_CMD_LEN];
 static __pdata uint8_t cmd_len;
 static __pdata uint8_t cmd_i;
 
@@ -48,8 +50,8 @@ backspace(void)
        ao_put_string ("\010 \010");
 }
 
-static void
-readline(void)
+void
+ao_cmd_readline(void)
 {
        char c;
        if (ao_echo())
@@ -88,7 +90,7 @@ readline(void)
                        break;
                }
 
-               if (cmd_len >= CMD_LEN - 2)
+               if (cmd_len >= AO_CMD_LEN - 2)
                        continue;
                cmd_line[cmd_len++] = c;
                if (ao_echo())
@@ -99,12 +101,13 @@ readline(void)
        cmd_i = 0;
 }
 
-void
+char
 ao_cmd_lex(void)
 {
        ao_cmd_lex_c = '\n';
        if (cmd_i < cmd_len)
                ao_cmd_lex_c = cmd_line[cmd_i++];
+       return ao_cmd_lex_c;
 }
 
 static void
@@ -307,7 +310,7 @@ version(void)
 #endif
 #endif
 #if defined(AO_BOOT_APPLICATION_BASE) && defined(AO_BOOT_APPLICATION_BOUND)
-              , (uint32_t) AO_BOOT_APPLICATION_BOUND - (uint32_t) AO_BOOT_APPLICATION_BASE
+              , (unsigned) ((uint32_t) AO_BOOT_APPLICATION_BOUND - (uint32_t) AO_BOOT_APPLICATION_BASE)
 #endif
                );
        printf("software-version %s\n", ao_version);
@@ -376,7 +379,7 @@ ao_cmd(void)
        void (*__xdata func)(void);
 
        for (;;) {
-               readline();
+               ao_cmd_readline();
                ao_cmd_lex();
                ao_cmd_white();
                c = ao_cmd_lex_c;
index 13eb05bfd7ee4c32aed8120909a779a2440cb69a..a2f2c6ca9679f8b93946ff3bc3d418d5e4209d2a 100644 (file)
@@ -47,10 +47,12 @@ extern __pdata enum ao_flight_state ao_log_state;
 #define AO_LOG_FORMAT_TELEMEGA_OLD     5       /* 32 byte typed telemega records */
 #define AO_LOG_FORMAT_EASYMINI         6       /* 16-byte MS5607 baro only, 3.0V supply */
 #define AO_LOG_FORMAT_TELEMETRUM       7       /* 16-byte typed telemetrum records */
-#define AO_LOG_FORMAT_TELEMINI         8       /* 16-byte MS5607 baro only, 3.3V supply */
+#define AO_LOG_FORMAT_TELEMINI2                8       /* 16-byte MS5607 baro only, 3.3V supply, cc1111 SoC */
 #define AO_LOG_FORMAT_TELEGPS          9       /* 32 byte telegps records */
 #define AO_LOG_FORMAT_TELEMEGA         10      /* 32 byte typed telemega records with 32 bit gyro cal */
 #define AO_LOG_FORMAT_DETHERM          11      /* 16-byte MS5607 baro only, no ADC */
+#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_NONE             127     /* No log at all */
 
 extern __code uint8_t ao_log_format;
@@ -299,6 +301,32 @@ struct ao_log_mega {
                                                 ((l)->u.gps.altitude_high = (a) >> 16), \
                                                 (l)->u.gps.altitude_low = (a))
 
+struct ao_log_firetwo {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       uint16_t        idle_pressure;  /* 6 */
+                       uint16_t        idle_thrust;    /* 8 */
+               } flight;       /* 16 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;        /* 8 */
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint16_t        pressure;       /* 4 */
+                       uint16_t        thrust;         /* 6 */
+                       uint16_t        thermistor[4];  /* 8 */
+               } sensor;       /* 24 */
+               uint8_t         align[28];              /* 4 */
+       } u;    /* 32 */
+};
+
 struct ao_log_metrum {
        char                    type;                   /* 0 */
        uint8_t                 csum;                   /* 1 */
diff --git a/src/kernel/ao_log_firetwo.c b/src/kernel/ao_log_firetwo.c
new file mode 100644 (file)
index 0000000..4b42abe
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2017 Bdale Garbee <bdale@gag.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_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata struct ao_log_firetwo log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEFIRETWO;
+
+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_firetwo); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_firetwo(__xdata struct ao_log_firetwo *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_firetwo));
+                       ao_log_current_pos += sizeof (struct ao_log_firetwo);
+               }
+       } 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;
+
+/* a hack to make sure that ao_log_metrums fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_firetwo))] ;
+#endif
+
+void
+ao_log(void)
+{
+       uint16_t ao_idle_pressure = 0;          // write code to capture pre-test values someday
+       uint16_t ao_idle_thrust = 0;
+       uint16_t ao_flight_state = ao_flight_startup;
+
+       ao_storage_setup();
+
+       do {
+               ao_log_scan();
+       
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+       
+               log.type = AO_LOG_FLIGHT;
+               log.tick = ao_time();
+               log.u.flight.idle_pressure = ao_idle_pressure;
+               log.u.flight.idle_thrust = ao_idle_thrust;
+               log.u.flight.flight = ao_flight_number;
+               ao_log_firetwo(&log);
+
+               /* Write the whole contents of the ring to the log
+               * when starting up.
+               */
+               ao_log_data_pos = ao_data_ring_next(ao_data_head);
+               ao_log_state = ao_flight_startup;
+               for (;;) {
+                       /* Write samples to EEPROM */
+                       while (ao_log_data_pos != ao_data_head) {
+                               log.tick = ao_data_ring[ao_log_data_pos].tick;
+                               log.type = AO_LOG_SENSOR;
+                               log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].adc.pressure;
+                               log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].adc.thrust;
+       //                      for (i = 0; i < 4; i++) {
+       //                              log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i];
+       //                      }
+                               ao_log_firetwo(&log);
+                               ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+                       }
+                       /* Write state change to EEPROM */
+                       if (ao_flight_state != ao_log_state) {
+                               ao_log_state = ao_flight_state;
+                               log.type = AO_LOG_STATE;
+                               log.tick = ao_time();
+                               log.u.state.state = ao_log_state;
+                               log.u.state.reason = 0;
+                               ao_log_firetwo(&log);
+       
+                               if (ao_log_state == ao_flight_landed)
+                                       ao_log_stop();
+                       }
+       
+                       ao_log_flush();
+
+                       if (!ao_log_running) break;
+
+                       /* Wait for a while */
+                       ao_delay(AO_MS_TO_TICKS(100));
+               }
+       } while (ao_log_running);
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_firetwo)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
index 813e866ac9eb93c43b2bbc8d53b9d12f61e238aa..a0881f9e3a8262fce6ec2b925363c5fcbb75ac32 100644 (file)
@@ -75,7 +75,8 @@ uint16_t      ao_pyro_fired;
 #endif
 
 #if PYRO_DBG
-#define DBG(...)       do { printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } while (0)
+int pyro_dbg;
+#define DBG(...)       do { if (pyro_dbg) printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } while (0)
 #else
 #define DBG(...)
 #endif
index 6592d6168988270cd3cd88d28d1cb1572b1fbc68..af48b390daae0c0095c074dd6818aabc27e86d76 100644 (file)
@@ -45,9 +45,16 @@ static const uint8_t flight_reports[] = {
 #define mid(time)      ao_beep_for(AO_BEEP_MID, time)
 #define high(time)     ao_beep_for(AO_BEEP_HIGH, time)
 #else
-#define low(time)      ao_led_for(AO_LED_GREEN, time)
-#define mid(time)      ao_led_for(AO_LED_RED, time)
-#define high(time)     ao_led_for(AO_LED_GREEN|AO_LED_RED, time)
+#ifndef AO_LED_LOW
+#define AO_LED_LOW     AO_LED_GREEN
+#endif
+#ifndef AO_LED_MID
+#define AO_LED_MID     AO_LED_RED
+#endif
+
+#define low(time)      ao_led_for(AO_LED_LOW, time)
+#define mid(time)      ao_led_for(AO_LED_MID, time)
+#define high(time)     ao_led_for(AO_LED_MID|AO_LED_LOW, time)
 #endif
 #define pause(time)    ao_delay(time)
 
index b79d465afa4975180faab8b3589b4d97bb210d52..f0ee0a14e5070f3b0c61b800dec4eda9526b7edf 100644 (file)
@@ -55,6 +55,9 @@
 #ifndef PACKET_HAS_SLAVE
 #define PACKET_HAS_SLAVE       0
 #endif
+#ifndef CONSOLE_STDIN
+#define CONSOLE_STDIN          0
+#endif
 
 #define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN + \
                          USE_SERIAL_1_STDIN +  \
@@ -67,7 +70,7 @@
                          USE_SERIAL_8_STDIN +  \
                          USE_SERIAL_9_STDIN)
 
-#define AO_NUM_STDIOS  (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN)
+#define AO_NUM_STDIOS  (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN + CONSOLE_STDIN)
 
 __xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS];
 
index e8a092aaf660fcf6bbec48706e14d2f7936e297b..de23ea02421013e4186801b85664abb81630d99a 100644 (file)
@@ -373,7 +373,11 @@ ao_yield(void) ao_arch_naked_define
                if (!ao_list_is_empty(&run_queue))
                        break;
                /* Wait for interrupts when there's nothing ready */
-               ao_arch_wait_interrupt();
+               if (ao_task_minimize_latency) {
+                       ao_arch_release_interrupts();
+                       ao_arch_block_interrupts();
+               } else
+                       ao_arch_wait_interrupt();
        }
        ao_cur_task = ao_list_first_entry(&run_queue, struct ao_task, queue);
 #else
index 15085bf4d0b10599d6c8b972eae3d66f7c91cc2c..fa8178240e45b97f60c71717eb77d76fd3e3e69c 100644 (file)
@@ -270,7 +270,7 @@ ao_send_mini(void)
        __xdata struct ao_data *packet = (__xdata struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];
 
        telemetry.generic.tick = packet->tick;
-       telemetry.generic.type = AO_TELEMETRY_MINI;
+       telemetry.generic.type = AO_SEND_MINI;
 
        telemetry.mini.state = ao_flight_state;
 
index c0f5e3c532cb7ff7c46796a1dd9aa292b48e02ac..45aaeb075c2f6d7deb9b0ddda379d37a5feb30b9 100644 (file)
@@ -270,7 +270,8 @@ struct ao_telemetry_metrum_data {
        /* 32 */
 };
 
-#define AO_TELEMETRY_MINI              0x10
+#define AO_TELEMETRY_MINI2             0x10    /* CC1111 based */
+#define AO_TELEMETRY_MINI3             0x11    /* STMF042 based */
 
 struct ao_telemetry_mini {
        uint16_t        serial;         /*  0 */
diff --git a/src/lambdakey-v1.0/.gitignore b/src/lambdakey-v1.0/.gitignore
new file mode 100644 (file)
index 0000000..6462d93
--- /dev/null
@@ -0,0 +1,2 @@
+lambdakey-*
+ao_product.h
diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile
new file mode 100644 (file)
index 0000000..2609bea
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# AltOS build
+#
+#
+
+include ../stmf0/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_task.h \
+       ao_lisp.h \
+       ao_lisp_const.h \
+       ao_lisp_os.h \
+       stm32f0.h \
+       Makefile
+
+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_dma_stm.c \
+       ao_stdio.c \
+       ao_mutex.c \
+       ao_panic.c \
+       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
+
+PRODUCT=LambdaKey-v1.0
+PRODUCT_DEF=-DLAMBDAKEY
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld
+
+PROGNAME=lambdakey-v1.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_lambdakey.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) lambda.ld altos.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+load: $(PROG)
+       stm-load $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/lambdakey-v1.0/ao_lambdakey.c b/src/lambdakey-v1.0/ao_lambdakey.c
new file mode 100644 (file)
index 0000000..8bd344c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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>
+
+static void lisp_cmd() {
+       ao_lisp_read_eval_print();
+}
+
+static const struct ao_cmds blink_cmds[] = {
+       { lisp_cmd,     "l\0Run lisp interpreter" },
+       { 0, 0 }
+};
+
+
+void main(void)
+{
+       ao_led_init(LEDS_AVAILABLE);
+       ao_clock_init();
+       ao_task_init();
+       ao_timer_init();
+       ao_dma_init();
+       ao_usb_init();
+       ao_cmd_init();
+       ao_cmd_register(blink_cmds);
+       ao_start_scheduler();
+}
+
+
diff --git a/src/lambdakey-v1.0/ao_lisp_os.h b/src/lambdakey-v1.0/ao_lisp_os.h
new file mode 100644 (file)
index 0000000..1993ac4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..4413839
--- /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_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_pins.h b/src/lambdakey-v1.0/ao_pins.h
new file mode 100644 (file)
index 0000000..2ba79c0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define LED_PORT_ENABLE        STM_RCC_AHBENR_IOPBEN
+#define LED_PORT       (&stm_gpiob)
+#define LED_PIN_RED    4
+#define AO_LED_RED     (1 << LED_PIN_RED)
+#define AO_LED_PANIC   AO_LED_RED
+#define AO_CMD_LEN     128
+#define AO_LISP_POOL_TOTAL     3072
+#define AO_LISP_SAVE   1
+#define AO_STACK_SIZE  1024
+
+/* need HSI active to write to flash */
+#define AO_NEED_HSI    1
+
+#define LEDS_AVAILABLE (AO_LED_RED)
+
+#define AO_POWER_MANAGEMENT    0
+
+/* 48MHz clock based on USB */
+#define AO_HSI48       1
+
+/* HCLK = 48MHz */
+#define AO_AHB_PRESCALER       1
+#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
+
+/* APB = 48MHz */
+#define AO_APB_PRESCALER       1
+#define AO_RCC_CFGR_PPRE_DIV   STM_RCC_CFGR_PPRE_DIV_1
+
+#define HAS_USB                                1
+#define AO_USB_DIRECTIO                        0
+#define AO_PA11_PA12_RMP               1
+#define HAS_BEEP                       0
+
+#define IS_FLASH_LOADER        0
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/lambdakey-v1.0/flash-loader/.gitignore b/src/lambdakey-v1.0/flash-loader/.gitignore
new file mode 100644 (file)
index 0000000..86ebb7f
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+lambdakey*
diff --git a/src/lambdakey-v1.0/flash-loader/Makefile b/src/lambdakey-v1.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..dbded71
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=lambdakey-v1.0
+include $(TOPDIR)/stmf0/Makefile-flash.defs
diff --git a/src/lambdakey-v1.0/flash-loader/ao_pins.h b/src/lambdakey-v1.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..4b788f6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_
+
+#include <ao_flash_stm_pins.h>
+
+/* Pin 5 on debug connector */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioa
+#define AO_BOOT_APPLICATION_PIN                15
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+/* USB */
+#define HAS_USB                        1
+#define AO_USB_DIRECTIO                0
+#define AO_PA11_PA12_RMP       1
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/lambdakey-v1.0/lambda.ld b/src/lambdakey-v1.0/lambda.ld
new file mode 100644 (file)
index 0000000..5de65eb
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+MEMORY {
+       rom (rx) :   ORIGIN = 0x08001000, LENGTH = 25K
+       flash (r):   ORIGIN = 0x08007400, LENGTH = 3k
+       ram (!w) :   ORIGIN = 0x20000000, LENGTH = 6k - 128
+       stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (stm_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) {
+               __interrupt_start__ = .;
+               __interrupt_rom__ = ORIGIN(rom);
+               *(.interrupt)   /* Interrupt vectors */
+               __interrupt_end__ = .;
+       } > ram
+
+       .text ORIGIN(rom) + 0x100 : {
+               __text_start__ = .;
+
+               /* Ick. What I want is to specify the
+                * addresses of some global constants so
+                * that I can find them across versions
+                * of the application. I can't figure out
+                * how to make gnu ld do that, so instead
+                * we just load the two files that include
+                * these defines in the right order here and
+                * expect things to 'just work'. Don't change
+                * the contents of those files, ok?
+                */
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+
+               *(.text*)       /* Executable code */
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+               *(.rodata*)     /* Constants */
+
+       } > rom
+       __text_end__ = .;
+       
+
+       /* Boot data which must live at the start of ram so that
+        * the application and bootloader share the same addresses.
+        * This must be all uninitialized data
+        */
+       .boot (NOLOAD) : {
+               __boot_start__ = .;
+               *(.boot)
+               . = ALIGN(4);
+               __boot_end__ = .;
+       } >ram
+
+       /* Functions placed in RAM (required for flashing)
+        *
+        * Align to 8 bytes as that's what the ARM likes text
+        * segment alignments to be, and if we don't, then
+        * we end up with a mismatch between the location in
+        * ROM and the desired location in RAM. I don't
+        * entirely understand this, but at least this appears
+        * to work...
+        */
+
+       .textram BLOCK(8): {
+               __data_start__ = .;
+               __text_ram_start__ = .;
+               *(.ramtext)
+               __text_ram_end = .;
+       } >ram AT>rom
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data : {
+               *(.data)        /* initialized data */
+               . = ALIGN(4);
+               __data_end__ = .;
+       } >ram AT>rom
+
+       .bss : {
+               __bss_start__ = .;
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4);
+               __bss_end__ = .;
+       } >ram
+
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+
+       __flash__ = ORIGIN(flash);
+}
+
+ENTRY(start);
diff --git a/src/lisp/.gitignore b/src/lisp/.gitignore
new file mode 100644 (file)
index 0000000..76a555e
--- /dev/null
@@ -0,0 +1,2 @@
+ao_lisp_make_const
+ao_lisp_const.h
diff --git a/src/lisp/Makefile b/src/lisp/Makefile
new file mode 100644 (file)
index 0000000..25796ec
--- /dev/null
@@ -0,0 +1,22 @@
+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
new file mode 100644 (file)
index 0000000..126deeb
--- /dev/null
@@ -0,0 +1,22 @@
+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
new file mode 100644 (file)
index 0000000..998c767
--- /dev/null
@@ -0,0 +1,4 @@
+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
new file mode 100644 (file)
index 0000000..980514c
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..8c9e8ed
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..902f60e
--- /dev/null
@@ -0,0 +1,619 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..d2b60c9
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..3c8fd21
--- /dev/null
@@ -0,0 +1,184 @@
+;
+; 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
new file mode 100644 (file)
index 0000000..54a9be1
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..3be7c9c
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..05f6d25
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..77f65e9
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..526863c
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..fe7c47f
--- /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_lisp.h"
+
diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c
new file mode 100644 (file)
index 0000000..49f989e
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..d067ea0
--- /dev/null
@@ -0,0 +1,880 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..5fa3686
--- /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; 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
new file mode 100644 (file)
index 0000000..fb3b06f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..84ef2a6
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..1c994d5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..3be95d4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..4f850fb
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..53adf43
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..cd7b27a
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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 bccea5bc1e3ca250c905fdb94cf32eafda92d26e..c4521620b6b81b4e130837f8a54a5209f831e0c8 100644 (file)
@@ -4,7 +4,7 @@ endif
 
 include $(TOPDIR)/Makedefs
 
-vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math
+vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math
 vpath make-altitude $(TOPDIR)/util
 vpath make-kalman $(TOPDIR)/util
 vpath kalman.5c $(TOPDIR)/kalman
@@ -26,9 +26,12 @@ endif
 ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex
 CC=$(ARM_CC)
 
-WARN_FLAGS=-Wall -Wextra -Werror
+WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align
+
+AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \
+       -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) \
+       $(PDCLIB_INCLUDES) 
 
-AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) $(PDCLIB_INCLUDES) 
 LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\
        -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
 
index 5fc0f680fa070923558f847ef477c0b70ee8e0cc..15106dea42d620b1bbc452c9e56b6eaea2c6bc36 100644 (file)
@@ -109,7 +109,7 @@ ao_arch_memory_barrier() {
 static inline void
 ao_arch_init_stack(struct ao_task *task, void *start)
 {
-       uint32_t        *sp = (uint32_t *) (task->stack + AO_STACK_SIZE);
+       uint32_t        *sp = (uint32_t *) (void *) (task->stack + AO_STACK_SIZE);
        uint32_t        a = (uint32_t) start;
        int             i;
 
diff --git a/src/nucleao-32/.gitignore b/src/nucleao-32/.gitignore
new file mode 100644 (file)
index 0000000..cb8f78e
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+nucleo-32*
diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile
new file mode 100644 (file)
index 0000000..6904998
--- /dev/null
@@ -0,0 +1,93 @@
+#
+# AltOS build
+#
+#
+
+include ../stmf0/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_task.h \
+       ao_lisp.h \
+       ao_lisp_const.h \
+       stm32f0.h \
+       Makefile
+
+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_beep_stm.c \
+       ao_dma_stm.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_usb_stm.c \
+       ao_serial_stm.c \
+       ao_flash_stm.c \
+       ao_lisp_atom.c \
+       ao_lisp_builtin.c \
+       ao_lisp_cons.c \
+       ao_lisp_error.c \
+       ao_lisp_eval.c \
+       ao_lisp_frame.c \
+       ao_lisp_int.c \
+       ao_lisp_lambda.c \
+       ao_lisp_lex.c \
+       ao_lisp_mem.c \
+       ao_lisp_poly.c \
+       ao_lisp_read.c \
+       ao_lisp_rep.c \
+       ao_lisp_save.c \
+       ao_lisp_stack.c \
+       ao_lisp_string.c \
+       ao_lisp_os_save.c
+
+PRODUCT=Nucleo-32
+PRODUCT_DEF=-DNUCLEO
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tload.ld
+
+PROGNAME=nucleo-32
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_nucleo.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+load: $(PROG)
+       stm-load $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/nucleao-32/ao_nucleo.c b/src/nucleao-32/ao_nucleo.c
new file mode 100644 (file)
index 0000000..6b4cbaa
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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_beep.h>
+
+static void lisp_cmd() {
+       ao_lisp_read_eval_print();
+}
+
+static void beep() {
+       ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
+}
+
+static const struct ao_cmds blink_cmds[] = {
+       { lisp_cmd,     "l\0Run lisp interpreter" },
+       { beep,         "b\0Beep" },
+       { 0, 0 }
+};
+
+void main(void)
+{
+       ao_led_init(LEDS_AVAILABLE);
+       ao_clock_init();
+       ao_task_init();
+       ao_timer_init();
+       ao_dma_init();
+       ao_usb_init();
+       ao_serial_init();
+       ao_beep_init();
+       ao_cmd_init();
+       ao_cmd_register(blink_cmds);
+       ao_start_scheduler();
+}
+
+
diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h
new file mode 100644 (file)
index 0000000..cee4616
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define LED_PORT_ENABLE        STM_RCC_AHBENR_IOPBEN
+#define LED_PORT       (&stm_gpiob)
+#define LED_PIN_GREEN  3
+#define AO_LED_GREEN   (1 << LED_PIN_GREEN)
+#define AO_LED_PANIC   AO_LED_GREEN
+#define AO_CMD_LEN     128
+#define AO_LISP_POOL_TOTAL     3072
+#define AO_LISP_SAVE   1
+#define AO_STACK_SIZE  1024
+
+#define LEDS_AVAILABLE (AO_LED_GREEN)
+
+#define AO_POWER_MANAGEMENT    0
+
+/* 48MHz clock based on USB */
+#define AO_HSI48       1
+
+/* HCLK = 48MHz */
+#define AO_AHB_PRESCALER       1
+#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
+
+/* APB = 48MHz */
+#define AO_APB_PRESCALER       1
+#define AO_RCC_CFGR_PPRE_DIV   STM_RCC_CFGR_PPRE_DIV_1
+
+#define HAS_USB                                1
+#define AO_USB_DIRECTIO                        0
+#define AO_PA11_PA12_RMP               0
+#define HAS_BEEP                       1
+
+#define BEEPER_TIMER                   2
+#define BEEPER_CHANNEL                 4
+#define BEEPER_PORT                    (&stm_gpioa)
+#define BEEPER_PIN                     3
+
+#define IS_FLASH_LOADER        0
+
+#define HAS_SERIAL_2           1
+#define SERIAL_2_PA2_PA15      1
+#define USE_SERIAL_2_FLOW      0
+#define USE_SERIAL_2_STDIN     1
+#define DELAY_SERIAL_2_STDIN   0
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/nucleao-32/flash-loader/.gitignore b/src/nucleao-32/flash-loader/.gitignore
new file mode 100644 (file)
index 0000000..cb8f78e
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+nucleo-32*
diff --git a/src/nucleao-32/flash-loader/Makefile b/src/nucleao-32/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..2392e99
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=nucleo-32
+include $(TOPDIR)/stmf0/Makefile-flash.defs
diff --git a/src/nucleao-32/flash-loader/ao_pins.h b/src/nucleao-32/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..8bdbdb1
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#include <ao_flash_stm_pins.h>
+
+/* Pin D3, which is PB0 */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpiob
+#define AO_BOOT_APPLICATION_PIN                0
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+/* USB */
+#define HAS_USB                        1
+#define AO_USB_DIRECTIO                0
+#define AO_PA11_PA12_RMP       0
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/pnpservo-v1/Makefile b/src/pnpservo-v1/Makefile
new file mode 100644 (file)
index 0000000..8606b1a
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# AltOS build
+#
+#
+
+include ../stmf0/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_task.h \
+       stm32f0.h \
+       Makefile
+
+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_dma_stm.c \
+       ao_stdio.c \
+       ao_mutex.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_usb_stm.c \
+       ao_flash_stm.c 
+
+PRODUCT=PNPservo-v1
+PRODUCT_DEF=-DPNPSERVO
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld
+
+PROGNAME=pnpservo-v1
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_pnpservo.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) lambda.ld altos.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+load: $(PROG)
+       stm-load $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/pnpservo-v1/ao_pins.h b/src/pnpservo-v1/ao_pins.h
new file mode 100644 (file)
index 0000000..38f3d8e
--- /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.
+ *
+ * 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 LED_PORT_ENABLE        STM_RCC_AHBENR_IOPAEN
+#define LED_PORT       (&stm_gpioa)
+#define LED_PIN_RED    9
+#define LED_PIN_GREEN  10
+#define AO_LED_RED     (1 << LED_PIN_RED)
+#define AO_LED_GREEN   (1 << LED_PIN_GREEN)
+#define AO_LED_PANIC   AO_LED_RED
+#define AO_CMD_LEN     128
+#define AO_LISP_POOL_TOTAL     3072
+#define AO_LISP_SAVE   1
+#define AO_STACK_SIZE  1024
+
+/* need HSI active to write to flash */
+#define AO_NEED_HSI    1
+
+#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN)
+
+#define AO_POWER_MANAGEMENT    0
+
+/* 48MHz clock based on USB */
+#define AO_HSI48       1
+
+/* HCLK = 48MHz */
+#define AO_AHB_PRESCALER       1
+#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
+
+/* APB = 48MHz */
+#define AO_APB_PRESCALER       1
+#define AO_RCC_CFGR_PPRE_DIV   STM_RCC_CFGR_PPRE_DIV_1
+
+#define HAS_USB                                1
+#define AO_USB_DIRECTIO                        0
+#define AO_PA11_PA12_RMP               1
+#define HAS_BEEP                       0
+
+#define IS_FLASH_LOADER        0
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/pnpservo-v1/ao_pnpservo.c b/src/pnpservo-v1/ao_pnpservo.c
new file mode 100644 (file)
index 0000000..d4c2d49
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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>
+
+static const struct ao_cmds blink_cmds[] = {
+//     { lisp_cmd,     "l\0Run lisp interpreter" },
+       { 0, 0 }
+};
+
+
+void main(void)
+{
+       ao_led_init(LEDS_AVAILABLE);
+       ao_clock_init();
+       ao_task_init();
+       ao_timer_init();
+       ao_dma_init();
+       ao_usb_init();
+       ao_cmd_init();
+       ao_cmd_register(blink_cmds);
+       ao_start_scheduler();
+}
+
+
diff --git a/src/pnpservo-v1/flash-loader/.gitignore b/src/pnpservo-v1/flash-loader/.gitignore
new file mode 100644 (file)
index 0000000..86ebb7f
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+lambdakey*
diff --git a/src/pnpservo-v1/flash-loader/Makefile b/src/pnpservo-v1/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..3283380
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=pnpservo-v1
+include $(TOPDIR)/stmf0/Makefile-flash.defs
diff --git a/src/pnpservo-v1/flash-loader/ao_pins.h b/src/pnpservo-v1/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..4b788f6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_
+
+#include <ao_flash_stm_pins.h>
+
+/* Pin 5 on debug connector */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioa
+#define AO_BOOT_APPLICATION_PIN                15
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+/* USB */
+#define HAS_USB                        1
+#define AO_USB_DIRECTIO                0
+#define AO_PA11_PA12_RMP       1
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/pnpservo-v1/lambda.ld b/src/pnpservo-v1/lambda.ld
new file mode 100644 (file)
index 0000000..5de65eb
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+MEMORY {
+       rom (rx) :   ORIGIN = 0x08001000, LENGTH = 25K
+       flash (r):   ORIGIN = 0x08007400, LENGTH = 3k
+       ram (!w) :   ORIGIN = 0x20000000, LENGTH = 6k - 128
+       stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (stm_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) {
+               __interrupt_start__ = .;
+               __interrupt_rom__ = ORIGIN(rom);
+               *(.interrupt)   /* Interrupt vectors */
+               __interrupt_end__ = .;
+       } > ram
+
+       .text ORIGIN(rom) + 0x100 : {
+               __text_start__ = .;
+
+               /* Ick. What I want is to specify the
+                * addresses of some global constants so
+                * that I can find them across versions
+                * of the application. I can't figure out
+                * how to make gnu ld do that, so instead
+                * we just load the two files that include
+                * these defines in the right order here and
+                * expect things to 'just work'. Don't change
+                * the contents of those files, ok?
+                */
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+
+               *(.text*)       /* Executable code */
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+               *(.rodata*)     /* Constants */
+
+       } > rom
+       __text_end__ = .;
+       
+
+       /* Boot data which must live at the start of ram so that
+        * the application and bootloader share the same addresses.
+        * This must be all uninitialized data
+        */
+       .boot (NOLOAD) : {
+               __boot_start__ = .;
+               *(.boot)
+               . = ALIGN(4);
+               __boot_end__ = .;
+       } >ram
+
+       /* Functions placed in RAM (required for flashing)
+        *
+        * Align to 8 bytes as that's what the ARM likes text
+        * segment alignments to be, and if we don't, then
+        * we end up with a mismatch between the location in
+        * ROM and the desired location in RAM. I don't
+        * entirely understand this, but at least this appears
+        * to work...
+        */
+
+       .textram BLOCK(8): {
+               __data_start__ = .;
+               __text_ram_start__ = .;
+               *(.ramtext)
+               __text_ram_end = .;
+       } >ram AT>rom
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data : {
+               *(.data)        /* initialized data */
+               . = ALIGN(4);
+               __data_end__ = .;
+       } >ram AT>rom
+
+       .bss : {
+               __bss_start__ = .;
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4);
+               __bss_end__ = .;
+       } >ram
+
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+
+       __flash__ = ORIGIN(flash);
+}
+
+ENTRY(start);
diff --git a/src/stm-vga/Makefile b/src/stm-vga/Makefile
new file mode 100644 (file)
index 0000000..46a7727
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_vga.h \
+       ao_draw.h \
+       ao_draw_int.h \
+       ao_font.h \
+       ao_ps2.h
+
+#
+# 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.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_lcd_stm.c \
+       ao_lcd_font.c \
+       ao_vga.c \
+       ao_blt.c \
+       ao_copy.c \
+       ao_rect.c \
+       ao_text.c \
+       ao_line.c \
+       ao_mutex.c \
+       ao_dma_stm.c \
+       ao_adc_stm.c \
+       ao_data.c \
+       ao_i2c_stm.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       ao_ps2.c \
+       ao_console.c
+
+PRODUCT=StmVga-v0.0
+IDPRODUCT=0x000a
+
+CFLAGS = $(STM_CFLAGS) -g -Os
+
+PROG=stm-vga-$(VERSION)
+ELF=$(PROG).elf
+IHX=$(PROG).ihx
+
+SRC=$(ALTOS_SRC) ao_demo.c
+OBJ=$(SRC:.c=.o)
+
+all: $(ELF) $(IHX)
+
+$(ELF): Makefile $(OBJ)
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(LIBS)
+
+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
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/stm-vga/ao_demo.c b/src/stm-vga/ao_demo.c
new file mode 100644 (file)
index 0000000..1b443b1
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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_event.h>
+#include <ao_quadrature.h>
+#include <ao_button.h>
+#include <ao_boot.h>
+#include <ao_vga.h>
+#include <ao_ps2.h>
+#include <ao_console.h>
+
+struct ao_task ball_task;
+struct ao_task ps2_task;
+
+#define BALL_WIDTH     5
+#define BALL_HEIGHT    5
+
+static int     ball_x;
+static int     ball_y;
+static int     ball_dx, ball_dy;
+
+uint8_t                ball_enable;
+
+void
+ao_ball(void)
+{
+       ball_dx = 1;
+       ball_dy = 1;
+       ball_x = 0;
+       ball_y = 0;
+       for (;;) {
+               while (!ball_enable)
+                       ao_sleep(&ball_enable);
+               for (;;) {
+                       ao_line(&ao_vga_bitmap,
+                               -100, -100, ball_x*2, ball_y*2,
+                               1, AO_XOR);
+                       ao_text(&ao_vga_bitmap,
+                               ball_x, ball_y - 10,
+                               "Hello, Bdale!",
+                               1, AO_XOR);
+                       ao_rect(&ao_vga_bitmap,
+                               ball_x, ball_y,
+                               BALL_WIDTH,
+                               BALL_HEIGHT,
+                               1,
+                               AO_XOR);
+                       ao_delay(AO_MS_TO_TICKS(10));
+                       ao_rect(&ao_vga_bitmap,
+                               ball_x, ball_y,
+                               BALL_WIDTH,
+                               BALL_HEIGHT,
+                               1,
+                               AO_XOR);
+                       ao_text(&ao_vga_bitmap,
+                               ball_x, ball_y - 10,
+                               "Hello, Bdale!",
+                               1, AO_XOR);
+                       ao_line(&ao_vga_bitmap,
+                               -100, -100, ball_x*2, ball_y*2,
+                               1, AO_XOR);
+                       if (!ball_enable)
+                               break;
+                       ball_x += ball_dx;
+                       ball_y += ball_dy;
+                       if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) {
+                               ball_x = AO_VGA_WIDTH - BALL_WIDTH;
+                               ball_dx = -ball_dx;
+                       }
+                       if (ball_x < 0) {
+                               ball_x = -ball_x;
+                               ball_dx = -ball_dx;
+                       }
+                       if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) {
+                               ball_y = AO_VGA_HEIGHT - BALL_HEIGHT;
+                               ball_dy = -ball_dy;
+                       }
+                       if (ball_y < 0) {
+                               ball_y = -ball_y;
+                               ball_dy = -ball_dy;
+                       }
+               }
+       }
+}
+
+void
+ao_ps2(void)
+{
+       uint8_t leds = 0;
+       for (;;) {
+               uint8_t b = ao_ps2_get();
+               printf ("%02x\n", b);
+               flush();
+               if (b == 0x14) {
+                       leds ^= 4;
+                       ao_ps2_put(0xed);
+                       if (ao_ps2_get() == 0xfa)
+                               ao_ps2_put(leds);
+               }
+       }
+}
+
+static void
+ao_fb_init(void)
+{
+       ao_rect(&ao_vga_bitmap,
+               0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT,
+               1, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               10, 10, 10, 10,
+               0, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               AO_VGA_WIDTH - 20, 10, 10, 10,
+               0, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               10, AO_VGA_HEIGHT - 20, 10, 10,
+               0, AO_COPY);
+
+       ao_rect(&ao_vga_bitmap,
+               AO_VGA_WIDTH - 20, AO_VGA_HEIGHT - 20, 10, 10,
+               0, AO_COPY);
+
+       ao_text(&ao_vga_bitmap,
+               20, 100,
+               "Hello, Bdale!",
+               0, AO_COPY);
+
+       ao_text(&ao_vga_bitmap,
+               1, ao_font.ascent,
+               "UL",
+               0, AO_COPY);
+
+       ao_text(&ao_vga_bitmap,
+               1, AO_VGA_HEIGHT - ao_font.descent,
+               "BL",
+               0, AO_COPY);
+}
+
+static void
+ao_video_toggle(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_lex_i)
+               ao_fb_init();
+       ao_vga_enable(ao_cmd_lex_i);
+}
+
+static void
+ao_ball_toggle(void)
+{
+       ao_cmd_decimal();
+       ball_enable = ao_cmd_lex_i;
+       ao_wakeup(&ball_enable);
+}
+
+static void
+ao_ps2_read_keys(void)
+{
+       char    c;
+
+       for (;;) {
+               c = ao_ps2_getchar();
+               printf("%02x %c\n", c, ' ' <= c && c < 0x7f ? c : '.');
+               flush();
+               if (c == ' ')
+                       break;
+       }
+}
+
+static void
+ao_console_send(void)
+{
+       char    c;
+
+       while ((c = getchar()) != '~') {
+               ao_console_putchar(c);
+               flush();
+       }
+}
+
+__code struct ao_cmds ao_demo_cmds[] = {
+       { ao_video_toggle, "V\0Toggle video" },
+       { ao_ball_toggle, "B\0Toggle ball" },
+       { ao_ps2_read_keys, "K\0Read keys from keyboard" },
+       { ao_console_send, "C\0Send data to console, end with ~" },
+       { 0, NULL }
+};
+
+int
+main(void)
+{
+       ao_clock_init();
+
+       ao_task_init();
+
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(AO_LED_GREEN);
+       ao_led_off(AO_LED_BLUE);
+       ao_timer_init();
+       ao_dma_init();
+       ao_cmd_init();
+       ao_vga_init();
+       ao_usb_init();
+       ao_exti_init();
+       ao_ps2_init();
+       ao_console_init();
+
+       ao_add_task(&ball_task, ao_ball, "ball");
+       ao_cmd_register(&ao_demo_cmds[0]);
+
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/stm-vga/ao_lisp_os.h b/src/stm-vga/ao_lisp_os.h
new file mode 100644 (file)
index 0000000..1993ac4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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/stm-vga/ao_lisp_os_save.c b/src/stm-vga/ao_lisp_os_save.c
new file mode 100644 (file)
index 0000000..7c85399
--- /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_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;
+}
diff --git a/src/stm-vga/ao_pins.h b/src/stm-vga/ao_pins.h
new file mode 100644 (file)
index 0000000..8503c4f
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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 = 24MHz */
+#define AO_PLLDIV              4
+#define AO_RCC_CFGR_PLLDIV     (STM_RCC_CFGR_PLLDIV_4)
+
+/* HCLK = 24MHZ (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
+
+/* Allow for non-maskable interrupts at priority 0 */
+#define AO_NONMASK_INTERRUPT   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 HAS_TASK_QUEUE         1
+
+#define CONSOLE_STDIN          1
+
+#define AO_STACK_SIZE          1024
+
+#define STM_DMA1_3_STOLEN      1
+
+#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 AO_LCD_STM_SEG_ENABLED_0 (             \
+               (1 << 0) | /* PA1 */            \
+               (1 << 1) | /* PA2 */            \
+               (1 << 2) | /* PA3 */            \
+               (0 << 3) | /* PA6 */            \
+               (0 << 4) | /* PA7 */            \
+               (0 << 5) | /* PB0 */            \
+               (0 << 6) | /* PB1 */            \
+               (1 << 7) | /* PB3 */            \
+               (1 << 8) | /* PB4 */            \
+               (1 << 9) | /* PB5 */            \
+               (1 << 10) | /* PB10 */          \
+               (1 << 11) | /* PB11 */          \
+               (1 << 12) | /* PB12 */          \
+               (1 << 13) | /* PB13 */          \
+               (1 << 14) | /* PB14 */          \
+               (1 << 15) | /* PB15 */          \
+               (1 << 16) | /* PB8 */           \
+               (1 << 17) | /* PA15 */          \
+               (1 << 18) | /* PC0 */           \
+               (1 << 19) | /* PC1 */           \
+               (1 << 20) | /* PC2 */           \
+               (1 << 21) | /* PC3 */           \
+               (0 << 22) | /* PC4 */           \
+               (0 << 23) | /* PC5 */           \
+               (1 << 24) | /* PC6 */           \
+               (1 << 25) | /* PC7 */           \
+               (1 << 26) | /* PC8 */           \
+               (1 << 27) | /* PC9 */           \
+               (1 << 28) | /* PC10 or PD8 */   \
+               (1 << 29) | /* PC11 or PD9 */   \
+               (0 << 30) | /* PC12 or PD10 */  \
+               (0 << 31))  /* PD2 or PD11 */
+
+#define AO_LCD_STM_SEG_ENABLED_1 (             \
+               (0 << 0) | /* PD12 */           \
+               (0 << 1) | /* PD13 */           \
+               (0 << 2) | /* PD14 */           \
+               (0 << 3) | /* PD15 */           \
+               (0 << 4) | /* PE0 */            \
+               (0 << 5) | /* PE1 */            \
+               (0 << 6) | /* PE2 */            \
+               (0 << 7))  /* PE3 */
+
+#define AO_LCD_STM_COM_ENABLED (               \
+               (1 << 0) | /* PA8 */            \
+               (1 << 1) | /* PA9 */            \
+               (1 << 2) | /* PA10 */           \
+               (1 << 3) | /* PB9 */            \
+               (0 << 4) | /* PC10 */           \
+               (0 << 5) | /* PC11 */           \
+               (0 << 6)) /* PC12 */
+
+#define AO_LCD_28_ON_C 1
+
+#define AO_LCD_DUTY    STM_LCD_CR_DUTY_STATIC
+
+#define HAS_ADC                        1
+
+#define AO_ADC_RING            32
+
+struct ao_adc {
+       uint16_t                tick;
+       int16_t                 idd;
+       int16_t                 temp;
+       int16_t                 vref;
+};
+
+#define AO_ADC_IDD             4
+#define AO_ADC_PIN0_PORT       (&stm_gpioa)
+#define AO_ADC_PIN0_PIN                4
+
+#define AO_ADC_RCC_AHBENR      ((1 << STM_RCC_AHBENR_GPIOAEN))
+#define AO_ADC_TEMP            16
+#define AO_ADC_VREF            17
+
+#define HAS_ADC_TEMP           1
+
+#define AO_DATA_RING           32
+#define AO_NUM_ADC             3
+
+#define AO_ADC_SQ1             AO_ADC_IDD
+#define AO_ADC_SQ2             AO_ADC_TEMP
+#define AO_ADC_SQ3             AO_ADC_VREF
+       
+#define HAS_I2C_1              1
+#define I2C_1_PB6_PB7          0
+#define I2C_1_PB8_PB9          1
+
+#define HAS_I2C_2              0
+#define I2C_2_PB10_PB11                0
+
+#define AO_EVENT               1
+
+#define AO_QUADRATURE_COUNT    2
+#define AO_QUADRATURE_MODE     AO_EXTI_MODE_PULL_UP
+
+#define AO_QUADRATURE_0_PORT   &stm_gpioc
+#define AO_QUADRATURE_0_A      1
+#define AO_QUADRATURE_0_B      0
+
+#define AO_QUADRATURE_1_PORT   &stm_gpioc
+#define AO_QUADRATURE_1_A      3
+#define AO_QUADRATURE_1_B      2
+
+#define AO_BUTTON_COUNT                2
+#define AO_BUTTON_MODE         AO_EXTI_MODE_PULL_UP
+
+#define AO_BUTTON_0_PORT       &stm_gpioc
+#define AO_BUTTON_0            6
+
+#define AO_BUTTON_1_PORT       &stm_gpioc
+#define AO_BUTTON_1            7
+
+#define AO_TICK_TYPE           uint32_t
+#define AO_TICK_SIGNED         int32_t
+
+#define AO_PS2_CLOCK_PORT      (&stm_gpioc)
+#define AO_PS2_CLOCK_BIT       0
+
+#define AO_PS2_DATA_PORT       (&stm_gpioc)
+#define AO_PS2_DATA_BIT                1
+
+#endif /* _AO_PINS_H_ */
index 0ba86f5abef6352ed365e99f8ab505de4f8e8ff6..66ed4be8d77974763e35b005adfecf340b8143f3 100644 (file)
@@ -1,4 +1,4 @@
-vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:..
+vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:../draw:../lisp:..
 vpath make-altitude ../util
 vpath make-kalman ../util
 vpath kalman.5c ../kalman
@@ -26,7 +26,7 @@ LIBS=$(PDCLIB_LIBS_M3) -lgcc
 
 WARN_FLAGS=-Wall -Wextra -Werror
 
-AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I.. $(PDCLIB_INCLUDES)
+AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I../draw -I../lisp -I.. $(PDCLIB_INCLUDES)
 STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -Wcast-align \
        -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
 
diff --git a/src/stm/altos-512.ld b/src/stm/altos-512.ld
new file mode 100644 (file)
index 0000000..78c4168
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+MEMORY {
+       rom (rx) : ORIGIN = 0x08001000, LENGTH = 508K
+       ram (!w) : ORIGIN = 0x20000000, LENGTH = 81408
+       stack (!w) : ORIGIN = 0x20013e00, LENGTH = 512
+}
+
+INCLUDE registers.ld
+
+EXTERN (stm_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .text ORIGIN(rom) : {
+               __text_start__ = .;
+               *(.interrupt)   /* Interrupt vectors */
+
+               . = ORIGIN(rom) + 0x100;
+
+
+               /* Ick. What I want is to specify the
+                * addresses of some global constants so
+                * that I can find them across versions
+                * of the application. I can't figure out
+                * how to make gnu ld do that, so instead
+                * we just load the two files that include
+                * these defines in the right order here and
+                * expect things to 'just work'. Don't change
+                * the contents of those files, ok?
+                */
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+               *(.text*)       /* Executable code */
+               *(.rodata*)     /* Constants */
+
+       } > rom
+
+       .ARM.exidx : {
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+       } > rom
+       __text_end__ = .;
+
+       /* Boot data which must live at the start of ram so that
+        * the application and bootloader share the same addresses.
+        * This must be all uninitialized data
+        */
+       .boot (NOLOAD) : {
+               __boot_start__ = .;
+               *(.boot)
+               . = ALIGN(4);
+               __boot_end__ = .;
+       } >ram
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data : {
+               __data_start__ = .;
+               *(.data)        /* initialized data */
+               . = ALIGN(4);
+               __data_end__ = .;
+       } >ram AT>rom
+
+       .bss : {
+               __bss_start__ = .;
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4);
+               __bss_end__ = .;
+       } >ram
+
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+}
+
+ENTRY(start);
+
+
index 0cc29376aaf271c7002f9bef72fa7e3fb1b7307c..5f033b66219e36719164e7864b8e4121977b8934 100644 (file)
@@ -85,10 +85,6 @@ extern const uint32_t ao_radio_cal;
 #define ao_arch_task_members\
        uint32_t *sp;                   /* saved stack pointer */
 
-#define ao_arch_block_interrupts()     asm("cpsid i")
-#define ao_arch_release_interrupts()   asm("cpsie i")
-
-
 /*
  * For now, we're running at a weird frequency
  */
@@ -122,10 +118,21 @@ extern const uint32_t ao_radio_cal;
 #define AO_TIM91011_CLK                (2 * AO_PCLK2)
 #endif
 
-#define AO_STM_NVIC_HIGH_PRIORITY      4
-#define AO_STM_NVIC_CLOCK_PRIORITY     6
-#define AO_STM_NVIC_MED_PRIORITY       8
-#define AO_STM_NVIC_LOW_PRIORITY       10
+/* The stm32l implements only 4 bits of the priority fields */
+
+#if AO_NONMASK_INTERRUPT
+#define AO_STM_NVIC_NONMASK_PRIORITY   0x00
+
+/* Set the basepri register to this value to mask all
+ * non-maskable priorities
+ */
+#define AO_STM_NVIC_BASEPRI_MASK       0x10
+#endif
+
+#define AO_STM_NVIC_HIGH_PRIORITY      0x40
+#define AO_STM_NVIC_MED_PRIORITY       0x80
+#define AO_STM_NVIC_LOW_PRIORITY       0xC0
+#define AO_STM_NVIC_CLOCK_PRIORITY     0xf0
 
 void ao_lcd_stm_init(void);
 
index a9d0fa34f02fed0ab58159eb6f7293f059a00a16..522059bc3d2193510e54d431d0bd9fd6e9bd45d5 100644 (file)
@@ -202,8 +202,11 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s
 
 #define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits)
 
+#define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask)
+
 #define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits);
 
+#define ao_gpio_get_all(port) stm_gpio_get_all(port)
 
 #define ao_enable_output(port,bit,pin,v) do {                  \
                ao_enable_port(port);                           \
@@ -211,6 +214,18 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s
                stm_moder_set(port, bit, STM_MODER_OUTPUT);\
        } while (0)
 
+#define ao_enable_output_mask(port,bits,mask) do {             \
+               ao_enable_port(port);                           \
+               ao_gpio_set_mask(port, bits, mask);             \
+               ao_set_output_mask(port, mask);                 \
+       } while (0)
+
+#define AO_OUTPUT_PUSH_PULL    STM_OTYPER_PUSH_PULL
+#define AO_OUTPUT_OPEN_DRAIN   STM_OTYPER_OPEN_DRAIN
+
+#define ao_gpio_set_output_mode(port,bit,pin,mode) \
+       stm_otyper_set(port, pin, mode)
+
 #define ao_gpio_set_mode(port,bit,mode) do {                           \
                if (mode == AO_EXTI_MODE_PULL_UP)                       \
                        stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP);    \
@@ -219,36 +234,73 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s
                else                                                    \
                        stm_pupdr_set(port, bit, STM_PUPDR_NONE);       \
        } while (0)
-       
+
+#define ao_gpio_set_mode_mask(port,mask,mode) do {                     \
+               if (mode == AO_EXTI_MODE_PULL_UP)                       \
+                       stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_UP); \
+               else if (mode == AO_EXTI_MODE_PULL_DOWN)                \
+                       stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_DOWN); \
+               else                                                    \
+                       stm_pupdr_set_mask(port, mask, STM_PUPDR_NONE); \
+       } while (0)
+
+#define ao_set_input(port, bit) do {                           \
+               stm_moder_set(port, bit, STM_MODER_INPUT);      \
+       } while (0)
+
+#define ao_set_output(port, bit, pin, v) do {                  \
+               ao_gpio_set(port, bit, pin, v);                 \
+               stm_moder_set(port, bit, STM_MODER_OUTPUT);     \
+       } while (0)
+
+#define ao_set_output_mask(port, mask) do {                    \
+               stm_moder_set_mask(port, mask, STM_MODER_OUTPUT);       \
+       } while (0)
+
+#define ao_set_input_mask(port, mask) do {                             \
+               stm_moder_set_mask(port, mask, STM_MODER_INPUT);        \
+       } while (0)
+
 #define ao_enable_input(port,bit,mode) do {                            \
                ao_enable_port(port);                                   \
-               stm_moder_set(port, bit, STM_MODER_INPUT);              \
+               ao_set_input(port, bit);                                \
                ao_gpio_set_mode(port, bit, mode);                      \
        } while (0)
 
-#define ao_enable_cs(port,bit) do {                            \
+#define ao_enable_input_mask(port,mask,mode) do {      \
+               ao_enable_port(port);                   \
+               ao_gpio_set_mode_mask(port, mask, mode);        \
+               ao_set_input_mask(port, mask);          \
+       } while (0)
+
+#define _ao_enable_cs(port, bit) do {                          \
                stm_gpio_set((port), bit, 1);                   \
                stm_moder_set((port), bit, STM_MODER_OUTPUT);   \
        } while (0)
 
+#define ao_enable_cs(port,bit) do {                            \
+               ao_enable_port(port);                           \
+               _ao_enable_cs(port, bit);                       \
+       } while (0)
+
 #define ao_spi_init_cs(port, mask) do {                                \
                ao_enable_port(port);                           \
-               if ((mask) & 0x0001) ao_enable_cs(port, 0);     \
-               if ((mask) & 0x0002) ao_enable_cs(port, 1);     \
-               if ((mask) & 0x0004) ao_enable_cs(port, 2);     \
-               if ((mask) & 0x0008) ao_enable_cs(port, 3);     \
-               if ((mask) & 0x0010) ao_enable_cs(port, 4);     \
-               if ((mask) & 0x0020) ao_enable_cs(port, 5);     \
-               if ((mask) & 0x0040) ao_enable_cs(port, 6);     \
-               if ((mask) & 0x0080) ao_enable_cs(port, 7);     \
-               if ((mask) & 0x0100) ao_enable_cs(port, 8);     \
-               if ((mask) & 0x0200) ao_enable_cs(port, 9);     \
-               if ((mask) & 0x0400) ao_enable_cs(port, 10);\
-               if ((mask) & 0x0800) ao_enable_cs(port, 11);\
-               if ((mask) & 0x1000) ao_enable_cs(port, 12);\
-               if ((mask) & 0x2000) ao_enable_cs(port, 13);\
-               if ((mask) & 0x4000) ao_enable_cs(port, 14);\
-               if ((mask) & 0x8000) ao_enable_cs(port, 15);\
+               if ((mask) & 0x0001) _ao_enable_cs(port, 0);    \
+               if ((mask) & 0x0002) _ao_enable_cs(port, 1);    \
+               if ((mask) & 0x0004) _ao_enable_cs(port, 2);    \
+               if ((mask) & 0x0008) _ao_enable_cs(port, 3);    \
+               if ((mask) & 0x0010) _ao_enable_cs(port, 4);    \
+               if ((mask) & 0x0020) _ao_enable_cs(port, 5);    \
+               if ((mask) & 0x0040) _ao_enable_cs(port, 6);    \
+               if ((mask) & 0x0080) _ao_enable_cs(port, 7);    \
+               if ((mask) & 0x0100) _ao_enable_cs(port, 8);    \
+               if ((mask) & 0x0200) _ao_enable_cs(port, 9);    \
+               if ((mask) & 0x0400) _ao_enable_cs(port, 10);\
+               if ((mask) & 0x0800) _ao_enable_cs(port, 11);\
+               if ((mask) & 0x1000) _ao_enable_cs(port, 12);\
+               if ((mask) & 0x2000) _ao_enable_cs(port, 13);\
+               if ((mask) & 0x4000) _ao_enable_cs(port, 14);\
+               if ((mask) & 0x8000) _ao_enable_cs(port, 15);\
        } while (0)
 
 /* ao_dma_stm.c
@@ -345,17 +397,43 @@ extern struct ao_stm_usart        ao_stm_usart3;
 
 typedef uint32_t       ao_arch_irq_t;
 
+static inline void
+ao_arch_block_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+       asm("cpsid i");
+#endif
+}
+
+static inline void
+ao_arch_release_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("msr basepri,%0" : : "r" (0x0));
+#else
+       asm("cpsie i");
+#endif
+}
+
 static inline uint32_t
 ao_arch_irqsave(void) {
-       uint32_t        primask;
-       asm("mrs %0,primask" : "=&r" (primask));
+       uint32_t        val;
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("mrs %0,basepri" : "=r" (val));
+#else
+       asm("mrs %0,primask" : "=r" (val));
+#endif
        ao_arch_block_interrupts();
-       return primask;
+       return val;
 }
 
 static inline void
-ao_arch_irqrestore(uint32_t primask) {
-       asm("msr primask,%0" : : "r" (primask));
+ao_arch_irqrestore(uint32_t basepri) {
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("msr basepri,%0" : : "r" (basepri));
+#else
+       asm("msr primask,%0" : : "r" (basepri));
+#endif
 }
 
 static inline void
@@ -365,10 +443,17 @@ ao_arch_memory_barrier() {
 
 static inline void
 ao_arch_irq_check(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+       uint32_t        basepri;
+       asm("mrs %0,basepri" : "=r" (basepri));
+       if (basepri == 0)
+               ao_panic(AO_PANIC_IRQ);
+#else
        uint32_t        primask;
-       asm("mrs %0,primask" : "=&r" (primask));
+       asm("mrs %0,primask" : "=r" (primask));
        if ((primask & 1) == 0)
                ao_panic(AO_PANIC_IRQ);
+#endif
 }
 
 #if HAS_TASK
@@ -390,7 +475,7 @@ ao_arch_init_stack(struct ao_task *task, void *start)
        /* APSR */
        ARM_PUSH32(sp, 0);
 
-       /* PRIMASK with interrupts enabled */
+       /* BASEPRI with interrupts enabled */
        ARM_PUSH32(sp, 0);
 
        task->sp = sp;
@@ -404,8 +489,13 @@ static inline void ao_arch_save_regs(void) {
        asm("mrs r0,apsr");
        asm("push {r0}");
 
+#ifdef AO_NONMASK_INTERRUPTS
+       /* Save BASEPRI */
+       asm("mrs r0,basepri");
+#else
        /* Save PRIMASK */
        asm("mrs r0,primask");
+#endif
        asm("push {r0}");
 }
 
@@ -419,9 +509,15 @@ static inline void ao_arch_restore_stack(void) {
        /* Switch stacks */
        asm("mov sp, %0" : : "r" (ao_cur_task->sp) );
 
+#ifdef AO_NONMASK_INTERRUPTS
+       /* Restore BASEPRI */
+       asm("pop {r0}");
+       asm("msr basepri,r0");
+#else
        /* Restore PRIMASK */
        asm("pop {r0}");
        asm("msr primask,r0");
+#endif
 
        /* Restore APSR */
        asm("pop {r0}");
@@ -463,7 +559,7 @@ static inline void ao_arch_start_scheduler(void) {
 
        asm("mrs %0,msp" : "=&r" (sp));
        asm("msr psp,%0" : : "r" (sp));
-       asm("mrs %0,control" : "=&r" (control));
+       asm("mrs %0,control" : "=r" (control));
        control |= (1 << 1);
        asm("msr control,%0" : : "r" (control));
        asm("isb");
@@ -474,12 +570,24 @@ static inline void ao_arch_start_scheduler(void) {
 
 #endif
 
-#define ao_arch_wait_interrupt() do {                          \
-               asm("\twfi\n");                                 \
-               ao_arch_release_interrupts();                   \
-               asm(".global ao_idle_loc\nao_idle_loc:");       \
-               ao_arch_block_interrupts();                     \
-       } while (0)
+static inline void
+ao_arch_wait_interrupt(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+       asm(
+           "dsb\n"                     /* Serialize data */
+           "isb\n"                     /* Serialize instructions */
+           "cpsid i\n"                 /* Block all interrupts */
+           "msr basepri,%0\n"          /* Allow all interrupts through basepri */
+           "wfi\n"                     /* Wait for an interrupt */
+           "cpsie i\n"                 /* Allow all interrupts */
+           "msr basepri,%1\n"          /* Block interrupts through basepri */
+           : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+       asm("\twfi\n");
+       ao_arch_release_interrupts();
+       ao_arch_block_interrupts();
+#endif
+}
 
 #define ao_arch_critical(b) do {                       \
                uint32_t __mask = ao_arch_irqsave();    \
index 6d77966076a88aefeac0f8a281fa81b5ebe0b662..962b3acc57b2824a7f79fe768a721bd8dcb633e5 100644 (file)
@@ -29,7 +29,6 @@ uint8_t ao_dma_done[NUM_DMA];
 static struct ao_dma_config ao_dma_config[NUM_DMA];
 static uint8_t ao_dma_allocated[NUM_DMA];
 static uint8_t ao_dma_mutex[NUM_DMA];
-static uint8_t ao_dma_active;
 
 static void
 ao_dma_isr(uint8_t index) {
@@ -49,12 +48,24 @@ ao_dma_isr(uint8_t index) {
 
 void stm_dma1_channel1_isr(void) { ao_dma_isr(STM_DMA_INDEX(1)); }
 void stm_dma1_channel2_isr(void) { ao_dma_isr(STM_DMA_INDEX(2)); }
+#ifdef STM_DMA1_3_STOLEN
+#define LEAVE_DMA_ON
+#else
 void stm_dma1_channel3_isr(void) { ao_dma_isr(STM_DMA_INDEX(3)); }
+#endif
 void stm_dma1_channel4_isr(void) { ao_dma_isr(STM_DMA_INDEX(4)); }
+#ifdef STM_DMA1_5_STOLEN
+#define LEAVE_DMA_ON
+#else
 void stm_dma1_channel5_isr(void) { ao_dma_isr(STM_DMA_INDEX(5)); }
+#endif
 void stm_dma1_channel6_isr(void) { ao_dma_isr(STM_DMA_INDEX(6)); }
 void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); }
 
+#ifndef LEAVE_DMA_ON
+static uint8_t ao_dma_active;
+#endif
+
 void
 ao_dma_set_transfer(uint8_t            index,
                    volatile void       *peripheral,
@@ -68,10 +79,12 @@ ao_dma_set_transfer(uint8_t                 index,
                ao_dma_mutex[index] = 0xff;
        } else
                ao_mutex_get(&ao_dma_mutex[index]);
+#ifndef LEAVE_DMA_ON
        ao_arch_critical(
                if (ao_dma_active++ == 0)
                        stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
                );
+#endif
        stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE);
        stm_dma.channel[index].cndtr = count;
        stm_dma.channel[index].cpar = peripheral;
@@ -96,10 +109,12 @@ void
 ao_dma_done_transfer(uint8_t index)
 {
        stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN);
+#ifndef LEAVE_DMA_ON
        ao_arch_critical(
                if (--ao_dma_active == 0)
                        stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);
                );
+#endif
        if (ao_dma_allocated[index])
                ao_dma_mutex[index] = 0;
        else
@@ -120,10 +135,12 @@ ao_dma_dump_cmd(void)
 {
        int i;
 
+#ifndef LEAVE_DMA_ON
        ao_arch_critical(
                if (ao_dma_active++ == 0)
                        stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
                );
+#endif
        printf ("isr %08x ifcr%08x\n", stm_dma.isr, stm_dma.ifcr);
        for (i = 0; i < NUM_DMA; i++)
                printf("%d: done %d allocated %d mutex %2d ccr %04x cndtr %04x cpar %08x cmar %08x isr %08x\n",
@@ -136,10 +153,12 @@ ao_dma_dump_cmd(void)
                       stm_dma.channel[i].cpar,
                       stm_dma.channel[i].cmar,
                       ao_dma_config[i].isr);
+#ifndef LEAVE_DMA_ON
        ao_arch_critical(
                if (--ao_dma_active == 0)
                        stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);
                );
+#endif
 }
 
 static const struct ao_cmds ao_dma_cmds[] = {
@@ -153,9 +172,27 @@ ao_dma_init(void)
 {
        int     index;
 
+#ifdef LEAVE_DMA_ON
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+#endif
        for (index = 0; index < STM_NUM_DMA; index++) {
+#if STM_DMA1_5_STOLEN
+               if (index == STM_DMA_INDEX(5)) {
+                       ao_dma_allocated[index] = 1;
+                       ao_dma_mutex[index] = 0xff;
+                       continue;
+               }
+#endif
+#if STM_DMA1_3_STOLEN
+               if (index == STM_DMA_INDEX(3)) {
+                       ao_dma_allocated[index] = 1;
+                       ao_dma_mutex[index] = 0xff;
+                       continue;
+               }
+#endif
                stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index);
-               stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, 4);
+               stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index,
+                                     AO_STM_NVIC_MED_PRIORITY);
                ao_dma_allocated[index] = 0;
                ao_dma_mutex[index] = 0;
        }
index 3e0b3e5c84e29953833bdf235503c68932504f98..2491b609893607b2a340a455be93f59c513f860b 100644 (file)
@@ -123,7 +123,7 @@ ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) {
        (void) gpio;
 
        uint32_t        mask = 1 << pin;
-       
+
        if (mode & AO_EXTI_MODE_RISING)
                stm_exti.rtsr |= mask;
        else
index c1648421cd61727f65bd0581aaac2e5d2fb7174b..38618bbe53165f64138c0a3a39fa81c2740cbf20 100644 (file)
@@ -74,11 +74,10 @@ static void __attribute__ ((section(".ramtext"),noinline))
 _ao_flash_erase_page(uint32_t *page)
 {
        stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG);
-       
+
        *page = 0x00000000;
 
-       while (stm_flash.sr & (1 << STM_FLASH_SR_BSY))
-               ;
+       ao_flash_wait_bsy();
 }
 
 void
@@ -101,9 +100,8 @@ _ao_flash_half_page(uint32_t *dst, uint32_t *src)
 
        stm_flash.pecr |= (1 << STM_FLASH_PECR_FPRG);
        stm_flash.pecr |= (1 << STM_FLASH_PECR_PROG);
-       
-       while (stm_flash.sr & (1 << STM_FLASH_SR_BSY))
-               ;
+
+       ao_flash_wait_bsy();
 
        for (i = 0; i < 32; i++) {
                *dst++ = *src++;
index 29a8f173f948682d81b1f367d07b20ec7c0687fe..59cad4951058fce99d360da9ce91cbc47f58720c 100644 (file)
@@ -75,6 +75,9 @@ uint8_t       ao_i2c_mutex[STM_NUM_I2C];
 #if AO_PCLK1 == 16000000
 # define AO_STM_I2C_CR2_FREQ   STM_I2C_CR2_FREQ_16_MHZ
 #endif
+#if AO_PCLK1 == 24000000
+# define AO_STM_I2C_CR2_FREQ   STM_I2C_CR2_FREQ_24_MHZ
+#endif
 #if AO_PCLK1 == 32000000
 # define AO_STM_I2C_CR2_FREQ   STM_I2C_CR2_FREQ_32_MHZ
 #endif
index db0be992b4fbf65d90a455dbeef5d9cc122613f3..c625471e4b1e9ce39caaf6b7c17a346be76e6953 100644 (file)
@@ -444,7 +444,7 @@ ao_serial_init(void)
        ao_usart_init(&ao_stm_usart1);
 
        stm_nvic_set_enable(STM_ISR_USART1_POS);
-       stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
+       stm_nvic_set_priority(STM_ISR_USART1_POS, AO_STM_NVIC_MED_PRIORITY);
 #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
        ao_add_stdio(_ao_serial1_pollchar,
                     ao_serial1_putchar,
@@ -500,7 +500,7 @@ ao_serial_init(void)
 #endif
 
        stm_nvic_set_enable(STM_ISR_USART2_POS);
-       stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
+       stm_nvic_set_priority(STM_ISR_USART2_POS, AO_STM_NVIC_MED_PRIORITY);
 #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
        ao_add_stdio(_ao_serial2_pollchar,
                     ao_serial2_putchar,
@@ -544,7 +544,7 @@ ao_serial_init(void)
        ao_usart_init(&ao_stm_usart3);
 
        stm_nvic_set_enable(STM_ISR_USART3_POS);
-       stm_nvic_set_priority(STM_ISR_USART3_POS, 4);
+       stm_nvic_set_priority(STM_ISR_USART3_POS, AO_STM_NVIC_MED_PRIORITY);
 #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN
        ao_add_stdio(_ao_serial3_pollchar,
                     ao_serial3_putchar,
index f86a51169293e78a4fb930f8e132f19557c378e7..1576a6c91f78e38132b119b025415e0c112a3970 100644 (file)
@@ -90,6 +90,7 @@ ao_timer_init(void)
        stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) |
                           (1 << STM_SYSTICK_CSR_TICKINT) |
                           (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE));
+       stm_nvic.shpr15_12 |= AO_STM_NVIC_CLOCK_PRIORITY << 24;
 }
 
 #endif
index 9d72844e0c1a6710c06700f9725c13aae9d622a7..33e0617c8c4faa44cda6f73387b46aabe773546e 100644 (file)
@@ -1015,7 +1015,7 @@ ao_usb_enable(void)
        ao_arch_block_interrupts();
 
        /* Route interrupts */
-       stm_nvic_set_priority(STM_ISR_USB_LP_POS, 3);
+       stm_nvic_set_priority(STM_ISR_USB_LP_POS, AO_STM_NVIC_LOW_PRIORITY);
        stm_nvic_set_enable(STM_ISR_USB_LP_POS);
 
        ao_usb_configuration = 0;
@@ -1109,7 +1109,7 @@ struct ao_usb_dbg {
        int             line;
        char            *msg;
        uint32_t        value;
-       uint32_t        primask;
+       uint32_t        prival;
 #if TX_DBG
        uint16_t        in_count;
        uint32_t        in_epr;
@@ -1125,19 +1125,23 @@ struct ao_usb_dbg {
 #endif
 };
 
-#define NUM_USB_DBG    128
+#define NUM_USB_DBG    16
 
-static struct ao_usb_dbg dbg[128];
+static struct ao_usb_dbg dbg[NUM_USB_DBG];
 static int dbg_i;
 
 static void _dbg(int line, char *msg, uint32_t value)
 {
-       uint32_t        primask;
+       uint32_t        prival;
        dbg[dbg_i].line = line;
        dbg[dbg_i].msg = msg;
        dbg[dbg_i].value = value;
-       asm("mrs %0,primask" : "=&r" (primask));
-       dbg[dbg_i].primask = primask;
+#if AO_NONMASK_INTERRUPT
+       asm("mrs %0,basepri" : "=&r" (prival));
+#else
+       asm("mrs %0,primask" : "=&r" (prival));
+#endif
+       dbg[dbg_i].prival = prival;
 #if TX_DBG
        dbg[dbg_i].in_count = in_count;
        dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR];
index be1e1d65112c6c47f7b65ee1b3be7bc9934c2472..201f4f36647c4b5722cd9dfc5ab785065788c72a 100644 (file)
@@ -52,7 +52,32 @@ stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
                        ~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) |
                       value << STM_MODER_SHIFT(pin));
 }
-       
+
+static inline uint32_t
+stm_spread_mask(uint16_t mask) {
+       uint32_t m = mask;
+
+       /* 0000000000000000mmmmmmmmmmmmmmmm */
+       m = (m & 0xff) | ((m & 0xff00) << 8);
+       /* 00000000mmmmmmmm00000000mmmmmmmm */
+       m = (m & 0x000f000f) | ((m & 0x00f000f0) << 4);
+       /* 0000mmmm0000mmmm0000mmmm0000mmmm */
+       m = (m & 0x03030303) | ((m & 0x0c0c0c0c) << 2);
+       /* 00mm00mm00mm00mm00mm00mm00mm00mm */
+       m = (m & 0x11111111) | ((m & 0x22222222) << 2);
+       /* 0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m */
+       return m;
+}
+
+static inline void
+stm_moder_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+       uint32_t        bits32 = stm_spread_mask(mask);
+       uint32_t        mask32 = 3 * bits32;
+       uint32_t        value32 = (value & 3) * bits32;
+
+       gpio->moder = ((gpio->moder & ~mask32) | value32);
+}
+
 static inline uint32_t
 stm_moder_get(struct stm_gpio *gpio, int pin) {
        return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK;
@@ -69,7 +94,7 @@ stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
                         ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) |
                        value << STM_OTYPER_SHIFT(pin));
 }
-       
+
 static inline uint32_t
 stm_otyper_get(struct stm_gpio *gpio, int pin) {
        return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK;
@@ -83,12 +108,21 @@ stm_otyper_get(struct stm_gpio *gpio, int pin) {
 #define STM_OSPEEDR_40MHz              3
 
 static inline void
-stm_ospeedr_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+stm_ospeedr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
        gpio->ospeedr = ((gpio->ospeedr &
                        ~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) |
                       value << STM_OSPEEDR_SHIFT(pin));
 }
-       
+
+static inline void
+stm_ospeedr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+       uint32_t        bits32 = stm_spread_mask(mask);
+       uint32_t        mask32 = 3 * bits32;
+       uint32_t        value32 = (value & 3) * bits32;
+
+       gpio->ospeedr = ((gpio->ospeedr & ~mask32) | value32);
+}
+
 static inline uint32_t
 stm_ospeedr_get(struct stm_gpio *gpio, int pin) {
        return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK;
@@ -107,7 +141,16 @@ stm_pupdr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
                        ~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) |
                       value << STM_PUPDR_SHIFT(pin));
 }
-       
+
+static inline void
+stm_pupdr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+       uint32_t        bits32 = stm_spread_mask(mask);
+       uint32_t        mask32 = 3 * bits32;
+       uint32_t        value32 = (value & 3) * bits32;
+
+       gpio->pupdr = (gpio->pupdr & ~mask32) | value32;
+}
+
 static inline uint32_t
 stm_pupdr_get(struct stm_gpio *gpio, int pin) {
        return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK;
@@ -167,6 +210,12 @@ stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) {
        gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin);
 }
 
+static inline void
+stm_gpio_set_mask(struct stm_gpio *gpio, uint16_t bits, uint16_t mask) {
+       /* Use the bit set/reset register to do this atomically */
+       gpio->bsrr = ((uint32_t) (~bits & mask) << 16) | ((uint32_t) (bits & mask));
+}
+
 static inline void
 stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) {
        gpio->bsrr = bits;
@@ -518,7 +567,7 @@ extern struct stm_rcc stm_rcc;
 #define  STM_RCC_CFGR_MCOPRE_DIV_4     2
 #define  STM_RCC_CFGR_MCOPRE_DIV_8     3
 #define  STM_RCC_CFGR_MCOPRE_DIV_16    4
-#define  STM_RCC_CFGR_MCOPRE_DIV_MASK  7
+#define  STM_RCC_CFGR_MCOPRE_MASK      7
 
 #define STM_RCC_CFGR_MCOSEL    (24)
 #define  STM_RCC_CFGR_MCOSEL_DISABLE   0
@@ -897,7 +946,11 @@ struct stm_nvic {
        vuint32_t       sc;             /* 0xc10 0xe000ed10 System Control Register */
        vuint32_t       cc;             /* 0xc14 0xe000ed14 Configuration Control Register */
 
-       uint8_t         _unusedc18[0xe00 - 0xc18];
+       vuint32_t       shpr7_4;        /* 0xc18 0xe000ed18 System Hander Priority Registers */
+       vuint32_t       shpr11_8;       /* 0xc1c */
+       vuint32_t       shpr15_12;      /* 0xc20 */
+
+       uint8_t         _unusedc18[0xe00 - 0xc24];
 
        vuint32_t       stir;           /* 0xe00 */
 };
@@ -1594,6 +1647,7 @@ extern struct stm_i2c stm_i2c1, stm_i2c2;
 #define  STM_I2C_CR2_FREQ_4_MHZ                4
 #define  STM_I2C_CR2_FREQ_8_MHZ                8
 #define  STM_I2C_CR2_FREQ_16_MHZ       16
+#define  STM_I2C_CR2_FREQ_24_MHZ       24
 #define  STM_I2C_CR2_FREQ_32_MHZ       32
 #define  STM_I2C_CR2_FREQ_MASK         0x3f
 
@@ -1740,6 +1794,12 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;
 #define  STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK    7
 #define  STM_TIM234_SMCR_SMS_MASK              7
 
+#define STM_TIM234_DIER_CC4IE          4
+#define STM_TIM234_DIER_CC3IE          3
+#define STM_TIM234_DIER_CC2IE          2
+#define STM_TIM234_DIER_CC1IE          1
+#define STM_TIM234_DIER_UIE            0
+
 #define STM_TIM234_SR_CC4OF    12
 #define STM_TIM234_SR_CC3OF    11
 #define STM_TIM234_SR_CC2OF    10
@@ -1840,15 +1900,23 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;
 
 #define STM_TIM234_CCER_CC4NP  15
 #define STM_TIM234_CCER_CC4P   13
+#define  STM_TIM234_CCER_CC4P_ACTIVE_HIGH      0
+#define  STM_TIM234_CCER_CC4P_ACTIVE_LOW       1
 #define STM_TIM234_CCER_CC4E   12
 #define STM_TIM234_CCER_CC3NP  11
 #define STM_TIM234_CCER_CC3P   9
+#define  STM_TIM234_CCER_CC3P_ACTIVE_HIGH      0
+#define  STM_TIM234_CCER_CC3P_ACTIVE_LOW       1
 #define STM_TIM234_CCER_CC3E   8
 #define STM_TIM234_CCER_CC2NP  7
 #define STM_TIM234_CCER_CC2P   5
+#define  STM_TIM234_CCER_CC2P_ACTIVE_HIGH      0
+#define  STM_TIM234_CCER_CC2P_ACTIVE_LOW       1
 #define STM_TIM234_CCER_CC2E   4
 #define STM_TIM234_CCER_CC1NP  3
 #define STM_TIM234_CCER_CC1P   1
+#define  STM_TIM234_CCER_CC1P_ACTIVE_HIGH      0
+#define  STM_TIM234_CCER_CC1P_ACTIVE_LOW       1
 #define STM_TIM234_CCER_CC1E   0
 
 struct stm_usb {
index f3296b6959628d14951c0e28b28338af4b720b86..f2c53499347be2dcb0b1ca53432dd80cd2a09924 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
+vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp
 vpath make-altitude $(TOPDIR)/util
 vpath make-kalman $(TOPDIR)/util
 vpath kalman.5c $(TOPDIR)/kalman
@@ -27,7 +27,10 @@ CC=$(ARM_CC)
 
 WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align
 
-AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math $(PDCLIB_INCLUDES) 
+AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \
+       -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR)/lisp \
+       $(PDCLIB_INCLUDES) 
+
 STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\
        -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
 
diff --git a/src/stmf0/altos-raw.ld b/src/stmf0/altos-raw.ld
new file mode 100644 (file)
index 0000000..eb285e0
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+MEMORY {
+       rom (rx) :   ORIGIN = 0x08000000, LENGTH = 32K
+       ram (!w) :   ORIGIN = 0x20000000, LENGTH = 6k - 128
+       stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (stm_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .interrupt : {
+               __text_start__ = .;
+               *(.interrupt)   /* Interrupt vectors */
+       } > rom
+
+       .text ORIGIN(rom) + 0x100 : {
+
+               /* Ick. What I want is to specify the
+                * addresses of some global constants so
+                * that I can find them across versions
+                * of the application. I can't figure out
+                * how to make gnu ld do that, so instead
+                * we just load the two files that include
+                * these defines in the right order here and
+                * expect things to 'just work'. Don't change
+                * the contents of those files, ok?
+                */
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+
+               *(.text*)       /* Executable code */
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+               *(.rodata*)     /* Constants */
+
+       } > rom
+       __text_end__ = .;
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data : {
+               __data_start__ = .;
+               *(.data)        /* initialized data */
+               . = ALIGN(4);
+               __data_end__ = .;
+       } >ram AT>rom
+
+       .bss : {
+               __bss_start__ = .;
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4);
+               __bss_end__ = .;
+       } >ram
+
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+}
+
+ENTRY(start);
+
+
index 8f8933c6cc452b3769f741cf2bc615500cff4bb3..74fdf3eaeb3b595268938a0965219e157e131954 100644 (file)
@@ -55,10 +55,16 @@ SECTIONS {
                ao_product.o(.romconfig*)
 
                *(.text*)       /* Executable code */
+       } > rom
+
+       .ARM.exidx : {
                *(.ARM.exidx* .gnu.linkonce.armexidx.*)
-               *(.rodata*)     /* Constants */
+       } > rom
 
+       .rodata : {
+               *(.rodata*)     /* Constants */
        } > rom
+
        __text_end__ = .;
 
        /* Boot data which must live at the start of ram so that
diff --git a/src/stmf0/ao_adc_stm.c b/src/stmf0/ao_adc_stm.c
new file mode 100644 (file)
index 0000000..2b23dc5
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright © 2015 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.h>
+#include <ao_data.h>
+
+#define AO_ADC_DEBUG   0
+
+static uint8_t ao_adc_ready;
+
+/*
+ * Callback from DMA ISR
+ *
+ * Mark time in ring, shut down DMA engine
+ */
+static void ao_adc_done(int index)
+{
+       (void) index;
+       /* Clear ISR bits */
+       stm_adc.isr = ((1 << STM_ADC_ISR_AWD) |
+                      (1 << STM_ADC_ISR_OVR) |
+                      (1 << STM_ADC_ISR_EOSEQ) |
+                      (1 << STM_ADC_ISR_EOC));
+
+       AO_DATA_PRESENT(AO_DATA_ADC);
+       ao_dma_done_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1));
+       if (ao_data_present == AO_DATA_ALL) {
+#if HAS_MS5607
+               ao_data_ring[ao_data_head].ms5607_raw = ao_ms5607_current;
+#endif
+#if HAS_MMA655X
+               ao_data_ring[ao_data_head].mma655x = ao_mma655x_current;
+#endif
+#if HAS_HMC5883
+               ao_data_ring[ao_data_head].hmc5883 = ao_hmc5883_current;
+#endif
+#if HAS_MPU6000
+               ao_data_ring[ao_data_head].mpu6000 = ao_mpu6000_current;
+#endif
+               ao_data_ring[ao_data_head].tick = ao_tick_count;
+               ao_data_head = ao_data_ring_next(ao_data_head);
+               ao_wakeup((void *) &ao_data_head);
+       }
+       ao_adc_ready = 1;
+}
+
+/*
+ * Start the ADC sequence using the DMA engine
+ */
+void
+ao_adc_poll(void)
+{
+       if (!ao_adc_ready)
+               return;
+       ao_adc_ready = 0;
+       stm_adc.isr = 0;
+       ao_dma_set_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1),
+                           &stm_adc.dr,
+                           (void *) (&ao_data_ring[ao_data_head].adc),
+                           AO_NUM_ADC,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) |
+                           (1 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+                           (1 << STM_DMA_CCR_TCIE));
+       ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_done);
+       ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1));
+
+       stm_adc.cr |= (1 << STM_ADC_CR_ADSTART);
+}
+
+static void
+ao_adc_dump(void)
+{
+       struct ao_data  packet;
+
+       ao_data_get(&packet);
+       AO_ADC_DUMP(&packet);
+}
+
+#if AO_ADC_DEBUG
+static void
+ao_adc_one(void)
+{
+       int             ch;
+       uint16_t        value;
+
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       ch = ao_cmd_lex_i;
+       if (ch < 0 || AO_NUM_ADC <= ch) {
+               ao_cmd_status = ao_cmd_syntax_error;
+               return;
+       }
+
+       ao_timer_set_adc_interval(0);
+       ao_delay(1);
+
+       printf("At top, data %u isr %04x cr %04x\n", stm_adc.dr, stm_adc.isr, stm_adc.cr);
+
+       if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) {
+               printf("Disabling\n"); flush();
+               stm_adc.cr |= (1 << STM_ADC_CR_ADDIS);
+               while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS))
+                       ;
+               printf("Disabled\n"); flush();
+       }
+
+       /* Turn off everything */
+       stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) |
+                       (1 << STM_ADC_CR_ADSTP) |
+                       (1 << STM_ADC_CR_ADSTART) |
+                       (1 << STM_ADC_CR_ADEN));
+
+       printf("After disable, ADC status %04x\n", stm_adc.cr);
+
+       /* Configure */
+       stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) |                             /* analog watchdog channel 0 */
+                        (0 << STM_ADC_CFGR1_AWDEN) |                             /* Disable analog watchdog */
+                        (0 << STM_ADC_CFGR1_AWDSGL) |                            /* analog watchdog on all channels */
+                        (0 << STM_ADC_CFGR1_DISCEN) |                            /* Not discontinuous mode. All channels converted with one trigger */
+                        (0 << STM_ADC_CFGR1_AUTOOFF) |                           /* Leave ADC running */
+                        (1 << STM_ADC_CFGR1_WAIT) |                              /* Wait for data to be read before next conversion */
+                        (0 << STM_ADC_CFGR1_CONT) |                              /* only one set of conversions per trigger */
+                        (1 << STM_ADC_CFGR1_OVRMOD) |                            /* overwrite on overrun */
+                        (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) |   /* SW trigger */
+                        (0 << STM_ADC_CFGR1_ALIGN) |                             /* Align to LSB */
+                        (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) |            /* 12 bit resolution */
+                        (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) |    /* scan 0 .. n */
+                        (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */
+                        (0 << STM_ADC_CFGR1_DMAEN));                             /* disable DMA */
+
+       stm_adc.chselr = (1 << ch);
+
+       /* Longest sample time */
+       stm_adc.smpr = STM_ADC_SMPR_SMP_41_5 << STM_ADC_SMPR_SMP;
+
+       printf("Before enable, ADC status %04x\n", stm_adc.cr); flush();
+       /* Enable */
+       stm_adc.cr |= (1 << STM_ADC_CR_ADEN);
+       while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0)
+               ;
+
+       /* Start */
+       stm_adc.cr |= (1 << STM_ADC_CR_ADSTART);
+
+       /* Wait for conversion complete */
+       while (!(stm_adc.isr & (1 << STM_ADC_ISR_EOC)))
+               ;
+
+       value = stm_adc.dr;
+       printf ("value %u, cr is %04x isr is %04x\n",
+               value, stm_adc.cr, stm_adc.isr);
+
+
+       /* Clear ISR bits */
+       stm_adc.isr = ((1 << STM_ADC_ISR_AWD) |
+                      (1 << STM_ADC_ISR_OVR) |
+                      (1 << STM_ADC_ISR_EOSEQ) |
+                      (1 << STM_ADC_ISR_EOC));
+}
+#endif
+
+__code struct ao_cmds ao_adc_cmds[] = {
+       { ao_adc_dump,  "a\0Display current ADC values" },
+#if AO_ADC_DEBUG
+       { ao_adc_one,   "A ch\0Display one ADC channel" },
+#endif
+       { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+       uint32_t        chselr;
+
+       /* Reset ADC */
+       stm_rcc.apb2rstr |= (1 << STM_RCC_APB2RSTR_ADCRST);
+       stm_rcc.apb2rstr &= ~(1 << STM_RCC_APB2RSTR_ADCRST);
+
+       /* Turn on ADC pins */
+       stm_rcc.ahbenr |= AO_ADC_RCC_AHBENR;
+
+#ifdef AO_ADC_PIN0_PORT
+       stm_moder_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN1_PORT
+       stm_moder_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN2_PORT
+       stm_moder_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN3_PORT
+       stm_moder_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN4_PORT
+       stm_moder_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN5_PORT
+       stm_moder_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN6_PORT
+       stm_moder_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN7_PORT
+       stm_moder_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_MODER_ANALOG);
+       stm_pupdr_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_PUPDR_NONE);
+#endif
+#ifdef AO_ADC_PIN24_PORT
+       #error "Too many ADC ports"
+#endif
+
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN);
+
+       chselr = 0;
+#if AO_NUM_ADC > 0
+       chselr |= (1 << AO_ADC_PIN0_CH);
+#endif
+#if AO_NUM_ADC > 1
+       chselr |= (1 << AO_ADC_PIN1_CH);
+#endif
+#if AO_NUM_ADC > 2
+       chselr |= (1 << AO_ADC_PIN2_CH);
+#endif
+#if AO_NUM_ADC > 3
+       chselr |= (1 << AO_ADC_PIN3_CH);
+#endif
+#if AO_NUM_ADC > 4
+       chselr |= (1 << AO_ADC_PIN4_CH);
+#endif
+#if AO_NUM_ADC > 5
+       chselr |= (1 << AO_ADC_PIN5_CH);
+#endif
+#if AO_NUM_ADC > 6
+       chselr |= (1 << AO_ADC_PIN6_CH);
+#endif
+#if AO_NUM_ADC > 7
+       chselr |= (1 << AO_ADC_PIN7_CH);
+#endif
+#if AO_NUM_ADC > 8
+#error Need more ADC defines
+#endif
+
+       /* Wait for ADC to be idle */
+       while (stm_adc.cr & ((1 << STM_ADC_CR_ADCAL) |
+                            (1 << STM_ADC_CR_ADDIS)))
+               ;
+
+       /* Disable */
+       if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) {
+               stm_adc.cr |= (1 << STM_ADC_CR_ADDIS);
+               while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS))
+                       ;
+       }
+
+       /* Turn off everything */
+       stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) |
+                       (1 << STM_ADC_CR_ADSTP) |
+                       (1 << STM_ADC_CR_ADSTART) |
+                       (1 << STM_ADC_CR_ADEN));
+
+       /* Configure */
+       stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) |                             /* analog watchdog channel 0 */
+                        (0 << STM_ADC_CFGR1_AWDEN) |                             /* Disable analog watchdog */
+                        (0 << STM_ADC_CFGR1_AWDSGL) |                            /* analog watchdog on all channels */
+                        (0 << STM_ADC_CFGR1_DISCEN) |                            /* Not discontinuous mode. All channels converted with one trigger */
+                        (0 << STM_ADC_CFGR1_AUTOOFF) |                           /* Leave ADC running */
+                        (1 << STM_ADC_CFGR1_WAIT) |                              /* Wait for data to be read before next conversion */
+                        (0 << STM_ADC_CFGR1_CONT) |                              /* only one set of conversions per trigger */
+                        (1 << STM_ADC_CFGR1_OVRMOD) |                            /* overwrite on overrun */
+                        (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) |   /* SW trigger */
+                        (0 << STM_ADC_CFGR1_ALIGN) |                             /* Align to LSB */
+                        (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) |            /* 12 bit resolution */
+                        (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) |    /* scan 0 .. n */
+                        (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */
+                        (1 << STM_ADC_CFGR1_DMAEN));                             /* enable DMA */
+
+       /* Set the clock */
+       stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE;
+
+       /* Shortest sample time */
+       stm_adc.smpr = STM_ADC_SMPR_SMP_71_5 << STM_ADC_SMPR_SMP;
+
+       stm_adc.chselr = chselr;
+
+       stm_adc.ccr = ((0 << STM_ADC_CCR_VBATEN) |
+                      (0 << STM_ADC_CCR_TSEN) |
+                      (0 << STM_ADC_CCR_VREFEN));
+
+       /* Calibrate */
+       stm_adc.cr |= (1 << STM_ADC_CR_ADCAL);
+       while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0)
+               ;
+
+       /* Enable */
+       stm_adc.cr |= (1 << STM_ADC_CR_ADEN);
+       while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0)
+               ;
+
+       /* Clear any stale status bits */
+       stm_adc.isr = 0;
+
+       /* Turn on syscfg */
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN);
+
+       /* Set ADC to use DMA channel 1 (option 1) */
+       stm_syscfg.cfgr1 &= ~(1 << STM_SYSCFG_CFGR1_ADC_DMA_RMP);
+
+       ao_dma_alloc(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1));
+
+       ao_cmd_register(&ao_adc_cmds[0]);
+
+       ao_adc_ready = 1;
+}
index a36482b6746af760c212741d278d5075a4a7bb5d..c5f451f59aff32d304a8640da9395c949b3df441 100644 (file)
@@ -144,10 +144,15 @@ ao_adc_init();
 /* ADC maximum reported value */
 #define AO_ADC_MAX                     4095
 
+#ifndef HAS_BOOT_LOADER
+#define HAS_BOOT_LOADER                        1
+#endif
+
+#if HAS_BOOT_LOADER
 #define AO_BOOT_APPLICATION_BASE       ((uint32_t *) 0x08001000)
 #define AO_BOOT_APPLICATION_BOUND      ((uint32_t *) (0x08000000 + stm_flash_size()))
 #define AO_BOOT_LOADER_BASE            ((uint32_t *) 0x08000000)
-#define HAS_BOOT_LOADER                        1
+#endif
 
 #endif /* _AO_ARCH_H_ */
 
index 0cb0e43d9c3c890b06c283e0e85e1cf131b267f2..c38ce41afbad0545f32be50ffcc55085d33a5d73 100644 (file)
@@ -314,7 +314,18 @@ struct ao_stm_usart {
        struct ao_fifo          rx_fifo;
        struct ao_fifo          tx_fifo;
        struct stm_usart        *reg;
-       uint8_t                 tx_started;
+       uint8_t                 tx_running;
+       uint8_t                 draining;
+#if HAS_SERIAL_SW_FLOW
+       /* RTS - 0 if we have FIFO space, 1 if not
+        * CTS - 0 if we can send, 0 if not
+        */
+       struct stm_gpio         *gpio_rts;
+       struct stm_gpio         *gpio_cts;
+       uint8_t                 pin_rts;
+       uint8_t                 pin_cts;
+       uint8_t                 rts;
+#endif
 };
 
 #if HAS_SERIAL_1
diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c
new file mode 100644 (file)
index 0000000..610f4a3
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+#ifndef BEEPER_CHANNEL
+#error BEEPER_CHANNEL undefined
+#endif
+
+#ifndef BEEPER_TIMER
+#define BEEPER_TIMER   1
+#endif
+
+#if BEEPER_TIMER == 1
+#define timer stm_tim1
+#define STM_RCC_TIMER STM_RCC_APB2ENR_TIM1EN
+#define stm_rcc_enr stm_rcc.apb2enr
+#endif
+
+#if BEEPER_TIMER == 2
+#define timer stm_tim2
+#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM2EN
+#define stm_rcc_enr stm_rcc.apb1enr
+#endif
+
+#if BEEPER_TIMER == 3
+#define timer stm_tim3
+#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM3EN
+#define stm_rcc_enr stm_rcc.apb1enr
+#endif
+
+#ifndef timer
+#error BEEPER_TIMER invalid
+#endif
+
+static inline void
+disable(void)
+{
+       timer.cr1 = 0;
+#if BEEPER_TIMER == 1
+       timer.bdtr = 0;
+#endif
+       stm_rcc_enr &= ~(1 << STM_RCC_TIMER);
+
+       /* Disconnect the timer from the pin */
+       stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_NONE);
+}
+
+void
+ao_beep(uint8_t beep)
+{
+       if (beep == 0) {
+               disable();
+       } else {
+               stm_rcc_enr |= (1 << STM_RCC_TIMER);
+
+#if BEEPER_TIMER == 1
+               /* Master output enable */
+               stm_tim1.bdtr = (1 << STM_TIM1_BDTR_MOE);
+
+               stm_tim1.cr2 = ((0 << STM_TIM1_CR2_TI1S) |
+                               (STM_TIM1_CR2_MMS_RESET << STM_TIM1_CR2_MMS) |
+                               (0 << STM_TIM1_CR2_CCDS));
+
+               /* Set prescaler to match cc1111 clocks
+                */
+               stm_tim1.psc = AO_TIM_CLK / 750000;
+
+               /* 1. Select the counter clock (internal, external, prescaler).
+                *
+                * Setting SMCR to zero means use the internal clock
+                */
+
+               stm_tim1.smcr = 0;
+
+               /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */
+               stm_tim1.arr = beep;
+               stm_tim1.ccr1 = beep;
+
+               /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a
+                * DMA request is to be generated.
+                */
+               /* don't want this */
+
+               /* 4. Select the output mode. For example, you must write
+                *  OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output
+                *  pin when CNT matches CCRx, CCRx preload is not used, OCx
+                *  is enabled and active high.
+                */
+
+#if BEEPER_CHANNEL == 1
+               stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) |
+                                 (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) |
+                                 (0 << STM_TIM1_CCMR1_OC2PE) |
+                                 (0 << STM_TIM1_CCMR1_OC2FE) |
+                                 (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) |
+
+                                 (0 << STM_TIM1_CCMR1_OC1CE) |
+                                 (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) |
+                                 (0 << STM_TIM1_CCMR1_OC1PE) |
+                                 (0 << STM_TIM1_CCMR1_OC1FE) |
+                                 (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S));
+
+               stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) |
+                                (0 << STM_TIM1_CCER_CC4E) |
+                                (0 << STM_TIM1_CCER_CC3NP) |
+                                (0 << STM_TIM1_CCER_CC3NE) |
+                                (0 << STM_TIM1_CCER_CC3P) |
+                                (0 << STM_TIM1_CCER_CC3E) |
+                                (0 << STM_TIM1_CCER_CC2NP) |
+                                (0 << STM_TIM1_CCER_CC2NE) |
+                                (0 << STM_TIM1_CCER_CC2P) |
+                                (0 << STM_TIM1_CCER_CC2E) |
+                                (0 << STM_TIM1_CCER_CC1NE) |
+                                (0 << STM_TIM1_CCER_CC1P) |
+                                (1 << STM_TIM1_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 2
+               stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) |
+                                 (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC2M) |
+                                 (0 << STM_TIM1_CCMR1_OC2PE) |
+                                 (0 << STM_TIM1_CCMR1_OC2FE) |
+                                 (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) |
+
+                                 (0 << STM_TIM1_CCMR1_OC1CE) |
+                                 (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC1M) |
+                                 (0 << STM_TIM1_CCMR1_OC1PE) |
+                                 (0 << STM_TIM1_CCMR1_OC1FE) |
+                                 (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S));
+
+               stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) |
+                                (0 << STM_TIM1_CCER_CC4E) |
+                                (0 << STM_TIM1_CCER_CC3NP) |
+                                (0 << STM_TIM1_CCER_CC3NE) |
+                                (0 << STM_TIM1_CCER_CC3P) |
+                                (0 << STM_TIM1_CCER_CC3E) |
+                                (0 << STM_TIM1_CCER_CC2NP) |
+                                (0 << STM_TIM1_CCER_CC2NE) |
+                                (0 << STM_TIM1_CCER_CC2P) |
+                                (1 << STM_TIM1_CCER_CC2E) |
+                                (0 << STM_TIM1_CCER_CC1NE) |
+                                (0 << STM_TIM1_CCER_CC1P) |
+                                (0 << STM_TIM1_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 3
+               stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) |
+                                 (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR2_OC4M) |
+                                 (0 << STM_TIM1_CCMR2_OC4PE) |
+                                 (0 << STM_TIM1_CCMR2_OC4FE) |
+                                 (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC4S) |
+
+                                 (0 << STM_TIM1_CCMR2_OC3CE) |
+                                 (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR2_OC3M) |
+                                 (0 << STM_TIM1_CCMR2_OC3PE) |
+                                 (0 << STM_TIM1_CCMR2_OC3FE) |
+                                 (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC3S));
+
+               stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) |
+                                (0 << STM_TIM1_CCER_CC4E) |
+                                (0 << STM_TIM1_CCER_CC3NP) |
+                                (0 << STM_TIM1_CCER_CC3NE) |
+                                (0 << STM_TIM1_CCER_CC3P) |
+                                (1 << STM_TIM1_CCER_CC3E) |
+                                (0 << STM_TIM1_CCER_CC2NP) |
+                                (0 << STM_TIM1_CCER_CC2NE) |
+                                (0 << STM_TIM1_CCER_CC2P) |
+                                (0 << STM_TIM1_CCER_CC2E) |
+                                (0 << STM_TIM1_CCER_CC1NE) |
+                                (0 << STM_TIM1_CCER_CC1P) |
+                                (0 << STM_TIM1_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 4
+               stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) |
+                                 (STM_TIM1_CCMR2_OC4M_TOGGLE << STM_TIM1_CCMR2_OC4M) |
+                                 (0 << STM_TIM1_CCMR2_OC4PE) |
+                                 (0 << STM_TIM1_CCMR2_OC4FE) |
+                                 (STM_TIM1_CCMR2_CC4S_OUTPUT << STM_TIM1_CCMR2_CC4S) |
+
+                                 (0 << STM_TIM1_CCMR2_OC3CE) |
+                                 (STM_TIM1_CCMR2_OC3M_FROZEN << STM_TIM1_CCMR2_OC3M) |
+                                 (0 << STM_TIM1_CCMR2_OC3PE) |
+                                 (0 << STM_TIM1_CCMR2_OC3FE) |
+                                 (STM_TIM1_CCMR2_CC3S_OUTPUT << STM_TIM1_CCMR2_CC3S));
+
+               stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4NP) |
+                                (0 << STM_TIM1_CCER_CC4P) |
+                                (1 << STM_TIM1_CCER_CC4E) |
+                                (0 << STM_TIM1_CCER_CC3NP) |
+                                (0 << STM_TIM1_CCER_CC3P) |
+                                (0 << STM_TIM1_CCER_CC3E) |
+                                (0 << STM_TIM1_CCER_CC2NP) |
+                                (0 << STM_TIM1_CCER_CC2P) |
+                                (0 << STM_TIM1_CCER_CC2E) |
+                                (0 << STM_TIM1_CCER_CC1NP) |
+                                (0 << STM_TIM1_CCER_CC1P) |
+                                (0 << STM_TIM1_CCER_CC1E));
+#endif
+               /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */
+
+               stm_tim1.cr1 = ((STM_TIM1_CR1_CKD_1 << STM_TIM1_CR1_CKD) |
+                               (0 << STM_TIM1_CR1_ARPE) |
+                               (STM_TIM1_CR1_CMS_EDGE << STM_TIM1_CR1_CMS) |
+                               (0 << STM_TIM1_CR1_DIR) |
+                               (0 << STM_TIM1_CR1_OPM) |
+                               (0 << STM_TIM1_CR1_URS) |
+                               (0 << STM_TIM1_CR1_UDIS) |
+                               (1 << STM_TIM1_CR1_CEN));
+
+               /* Update the values */
+               stm_tim1.egr = (1 << STM_TIM1_EGR_UG);
+#endif
+#if BEEPER_TIMER == 2 || BEEPER_TIMER == 3
+
+               timer.cr2 = ((0 << STM_TIM23_CR2_TI1S) |
+                            (STM_TIM23_CR2_MMS_RESET << STM_TIM23_CR2_MMS) |
+                            (0 << STM_TIM23_CR2_CCDS));
+
+               /* Set prescaler to match cc1111 clocks
+                */
+               timer.psc = AO_TIM_CLK / 750000;
+
+               /* 1. Select the counter clock (internal, external, prescaler).
+                *
+                * Setting SMCR to zero means use the internal clock
+                */
+
+               timer.smcr = 0;
+
+               /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */
+               timer.arr = beep;
+               timer.ccr1 = beep;
+
+               /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a
+                * DMA request is to be generated.
+                */
+               /* don't want this */
+
+               /* 4. Select the output mode. For example, you must write
+                *  OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output
+                *  pin when CNT matches CCRx, CCRx preload is not used, OCx
+                *  is enabled and active high.
+                */
+
+#if BEEPER_CHANNEL == 1
+               timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) |
+                              (STM_TIM23_CCMR1_OC2M_FROZEN << STM_TIM23_CCMR1_OC2M) |
+                              (0 << STM_TIM23_CCMR1_OC2PE) |
+                              (0 << STM_TIM23_CCMR1_OC2FE) |
+                              (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) |
+
+                              (0 << STM_TIM23_CCMR1_OC1CE) |
+                              (STM_TIM23_CCMR1_OC1M_TOGGLE << STM_TIM23_CCMR1_OC1M) |
+                              (0 << STM_TIM23_CCMR1_OC1PE) |
+                              (0 << STM_TIM23_CCMR1_OC1FE) |
+                              (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S));
+
+               timer.ccer = ((0 << STM_TIM23_CCER_CC4P) |
+                             (0 << STM_TIM23_CCER_CC4E) |
+                             (0 << STM_TIM23_CCER_CC3NP) |
+                             (0 << STM_TIM23_CCER_CC3P) |
+                             (0 << STM_TIM23_CCER_CC3E) |
+                             (0 << STM_TIM23_CCER_CC2NP) |
+                             (0 << STM_TIM23_CCER_CC2P) |
+                             (0 << STM_TIM23_CCER_CC2E) |
+                             (0 << STM_TIM23_CCER_CC1P) |
+                             (1 << STM_TIM23_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 2
+               timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) |
+                              (STM_TIM23_CCMR1_OC2M_TOGGLE << STM_TIM23_CCMR1_OC2M) |
+                              (0 << STM_TIM23_CCMR1_OC2PE) |
+                              (0 << STM_TIM23_CCMR1_OC2FE) |
+                              (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) |
+
+                              (0 << STM_TIM23_CCMR1_OC1CE) |
+                              (STM_TIM23_CCMR1_OC1M_FROZEN << STM_TIM23_CCMR1_OC1M) |
+                              (0 << STM_TIM23_CCMR1_OC1PE) |
+                              (0 << STM_TIM23_CCMR1_OC1FE) |
+                              (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S));
+
+               timer.ccer = ((0 << STM_TIM23_CCER_CC4P) |
+                             (0 << STM_TIM23_CCER_CC4E) |
+                             (0 << STM_TIM23_CCER_CC3NP) |
+                             (0 << STM_TIM23_CCER_CC3P) |
+                             (0 << STM_TIM23_CCER_CC3E) |
+                             (0 << STM_TIM23_CCER_CC2NP) |
+                             (0 << STM_TIM23_CCER_CC2P) |
+                             (1 << STM_TIM23_CCER_CC2E) |
+                             (0 << STM_TIM23_CCER_CC1P) |
+                             (0 << STM_TIM23_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 3
+               timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) |
+                              (STM_TIM23_CCMR2_OC4M_FROZEN << STM_TIM23_CCMR2_OC4M) |
+                              (0 << STM_TIM23_CCMR2_OC4PE) |
+                              (0 << STM_TIM23_CCMR2_OC4FE) |
+                              (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) |
+
+                              (0 << STM_TIM23_CCMR2_OC3CE) |
+                              (STM_TIM23_CCMR2_OC3M_TOGGLE << STM_TIM23_CCMR2_OC3M) |
+                              (0 << STM_TIM23_CCMR2_OC3PE) |
+                              (0 << STM_TIM23_CCMR2_OC3FE) |
+                              (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S));
+
+               timer.ccer = ((0 << STM_TIM23_CCER_CC4P) |
+                             (0 << STM_TIM23_CCER_CC4E) |
+                             (0 << STM_TIM23_CCER_CC3NP) |
+                             (0 << STM_TIM23_CCER_CC3P) |
+                             (1 << STM_TIM23_CCER_CC3E) |
+                             (0 << STM_TIM23_CCER_CC2NP) |
+                             (0 << STM_TIM23_CCER_CC2P) |
+                             (0 << STM_TIM23_CCER_CC2E) |
+                             (0 << STM_TIM23_CCER_CC1P) |
+                             (0 << STM_TIM23_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 4
+               timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) |
+                              (STM_TIM23_CCMR2_OC4M_TOGGLE << STM_TIM23_CCMR2_OC4M) |
+                              (0 << STM_TIM23_CCMR2_OC4PE) |
+                              (0 << STM_TIM23_CCMR2_OC4FE) |
+                              (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) |
+
+                              (0 << STM_TIM23_CCMR2_OC3CE) |
+                              (STM_TIM23_CCMR2_OC3M_FROZEN << STM_TIM23_CCMR2_OC3M) |
+                              (0 << STM_TIM23_CCMR2_OC3PE) |
+                              (0 << STM_TIM23_CCMR2_OC3FE) |
+                              (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S));
+
+               timer.ccer = ((0 << STM_TIM23_CCER_CC4P) |
+                             (1 << STM_TIM23_CCER_CC4E) |
+                             (0 << STM_TIM23_CCER_CC3NP) |
+                             (0 << STM_TIM23_CCER_CC3P) |
+                             (0 << STM_TIM23_CCER_CC3E) |
+                             (0 << STM_TIM23_CCER_CC2NP) |
+                             (0 << STM_TIM23_CCER_CC2P) |
+                             (0 << STM_TIM23_CCER_CC2E) |
+                             (0 << STM_TIM23_CCER_CC1P) |
+                             (0 << STM_TIM23_CCER_CC1E));
+#endif
+               /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */
+
+               timer.cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) |
+                            (0 << STM_TIM23_CR1_ARPE) |
+                            (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) |
+                            (0 << STM_TIM23_CR1_DIR) |
+                            (0 << STM_TIM23_CR1_OPM) |
+                            (0 << STM_TIM23_CR1_URS) |
+                            (0 << STM_TIM23_CR1_UDIS) |
+                            (1 << STM_TIM23_CR1_CEN));
+
+               /* Update the values */
+               timer.egr = (1 << STM_TIM23_EGR_UG);
+
+               /* Hook the timer up to the beeper pin */
+               stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2);
+#endif
+       }
+}
+
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
+{
+       ao_beep(beep);
+       ao_delay(ticks);
+       ao_beep(0);
+}
+
+void
+ao_beep_init(void)
+{
+       ao_enable_output(BEEPER_PORT, BEEPER_PIN, BEEPER, 0);
+
+       /* Leave the timer off until requested */
+       stm_rcc_enr &= ~(1 << STM_RCC_TIMER);
+}
index 7acc6f9c0e33df5cb610271d73f3669ffbe982c5..b6d91023bde46e4fa8ba37df4a1647f850973d47 100644 (file)
@@ -35,7 +35,8 @@
 static inline uint16_t
 ao_crc_in_32_out_16(uint32_t v) {
        stm_crc.dr.u32 = v;
-       return stm_crc.dr.u16;
+       v = stm_crc.dr.u32;
+       return v ^ (v >> 16);
 }
 
 static inline uint16_t
index 2aeff3880fce13f3a91ec545276d8e9ab797538c..2d57eea72701eefeae6e61ad0a6fc0395cf2dac7 100644 (file)
 #include <ao.h>
 #include <ao_flash.h>
 
+/* Note that the HSI clock must be running for this code to work.
+ * Also, special care must be taken with the linker to ensure that the
+ * functions marked 'ramtext' land in ram and not rom. An example of that
+ * can be found in altos-loader.ld
+ */
+
 static uint8_t
 ao_flash_is_locked(void)
 {
@@ -44,12 +50,7 @@ ao_flash_lock(void)
        stm_flash.cr |= (1 << STM_FLASH_CR_LOCK);
 }
 
-static void
-ao_flash_wait_bsy(void)
-{
-       while (stm_flash.sr & (1 << STM_FLASH_SR_BSY))
-               ;
-}
+#define ao_flash_wait_bsy() do { while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)); } while (0)
 
 static void __attribute__ ((section(".ramtext"),noinline))
 _ao_flash_erase_page(uint32_t *page)
index 794124834b13c7e74777f33f5aa47c5df8396f35..fcd330f1b5aafc6620075ecfad98ad40a3be6aa6 100644 (file)
 #define IS_FLASH_LOADER        0
 #endif
 
+#ifndef RELOCATE_INTERRUPT
 #if !IS_FLASH_LOADER
 #define RELOCATE_INTERRUPT     1
 #endif
+#endif
 
 extern void main(void);
 extern char __stack__;
diff --git a/src/stmf0/ao_serial_stm.c b/src/stmf0/ao_serial_stm.c
new file mode 100644 (file)
index 0000000..30b0dbd
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * 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_exti.h>
+
+void
+ao_debug_out(char c)
+{
+       if (c == '\n')
+               ao_debug_out('\r');
+       while (!(stm_usart1.isr & (1 << STM_USART_ISR_TXE)));
+       stm_usart1.tdr = c;
+}
+
+static int
+_ao_usart_tx_start(struct ao_stm_usart *usart)
+{
+       if (!ao_fifo_empty(usart->tx_fifo)) {
+#if HAS_SERIAL_SW_FLOW
+               if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts, foo) == 1) {
+                       ao_exti_enable(usart->gpio_cts, usart->pin_cts);
+                       return 0;
+               }
+#endif
+               if (usart->reg->isr & (1 << STM_USART_ISR_TXE))
+               {
+                       usart->tx_running = 1;
+                       usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE);
+                       ao_fifo_remove(usart->tx_fifo, usart->reg->tdr);
+                       ao_wakeup(&usart->tx_fifo);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+#if HAS_SERIAL_SW_FLOW
+static void
+_ao_usart_cts(struct ao_stm_usart *usart)
+{
+       if (_ao_usart_tx_start(usart))
+               ao_exti_disable(usart->gpio_cts, usart->pin_cts);
+}
+#endif
+
+static void
+_ao_usart_rx(struct ao_stm_usart *usart, int stdin)
+{
+       if (usart->reg->isr & (1 << STM_USART_ISR_RXNE)) {
+               usart->reg->icr = (1 << STM_USART_ICR_ORECF);
+               if (!ao_fifo_full(usart->rx_fifo)) {
+                       ao_fifo_insert(usart->rx_fifo, usart->reg->rdr);
+                       ao_wakeup(&usart->rx_fifo);
+                       if (stdin)
+                               ao_wakeup(&ao_stdin_ready);
+#if HAS_SERIAL_SW_FLOW
+                       /* If the fifo is nearly full, turn off RTS and wait
+                        * for it to drain a bunch
+                        */
+                       if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) {
+                               ao_gpio_set(usart->gpio_rts, usart->pin_rts, usart->pin_rts, 1);
+                               usart->rts = 0;
+                       }
+#endif
+               } else {
+                       usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE);
+               }
+       }
+}
+
+static void
+ao_usart_isr(struct ao_stm_usart *usart, int stdin)
+{
+       _ao_usart_rx(usart, stdin);
+
+       if (!_ao_usart_tx_start(usart))
+               usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE);
+
+       if (usart->reg->isr & (1 << STM_USART_ISR_TC)) {
+               usart->tx_running = 0;
+               usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE);
+               if (usart->draining) {
+                       usart->draining = 0;
+                       ao_wakeup(&usart->tx_fifo);
+               }
+       }
+}
+
+static int
+_ao_usart_pollchar(struct ao_stm_usart *usart)
+{
+       int     c;
+
+       if (ao_fifo_empty(usart->rx_fifo))
+               c = AO_READ_AGAIN;
+       else {
+               uint8_t u;
+               ao_fifo_remove(usart->rx_fifo,u);
+               if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) {
+                       if (ao_fifo_barely(usart->rx_fifo))
+                               usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE);
+               }
+#if HAS_SERIAL_SW_FLOW
+               /* If we've cleared RTS, check if there's space now and turn it back on */
+               if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) {
+                       ao_gpio_set(usart->gpio_rts, usart->pin_rts, foo, 0);
+                       usart->rts = 1;
+               }
+#endif
+               c = u;
+       }
+       return c;
+}
+
+static char
+ao_usart_getchar(struct ao_stm_usart *usart)
+{
+       int c;
+       ao_arch_block_interrupts();
+       while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN)
+               ao_sleep(&usart->rx_fifo);
+       ao_arch_release_interrupts();
+       return (char) c;
+}
+
+static inline uint8_t
+_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout)
+{
+       return ao_sleep_for(&usart->rx_fifo, timeout);
+}
+
+static void
+ao_usart_putchar(struct ao_stm_usart *usart, char c)
+{
+       ao_arch_block_interrupts();
+       while (ao_fifo_full(usart->tx_fifo))
+               ao_sleep(&usart->tx_fifo);
+       ao_fifo_insert(usart->tx_fifo, c);
+       _ao_usart_tx_start(usart);
+       ao_arch_release_interrupts();
+}
+
+static void
+ao_usart_drain(struct ao_stm_usart *usart)
+{
+       ao_arch_block_interrupts();
+       while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) {
+               usart->draining = 1;
+               ao_sleep(&usart->tx_fifo);
+       }
+       ao_arch_release_interrupts();
+}
+
+static const struct {
+       uint32_t brr;
+} ao_usart_speeds[] = {
+       [AO_SERIAL_SPEED_4800] = {
+               AO_PCLK / 4800
+       },
+       [AO_SERIAL_SPEED_9600] = {
+               AO_PCLK / 9600
+       },
+       [AO_SERIAL_SPEED_19200] = {
+               AO_PCLK / 19200
+       },
+       [AO_SERIAL_SPEED_57600] = {
+               AO_PCLK / 57600
+       },
+       [AO_SERIAL_SPEED_115200] = {
+               AO_PCLK / 115200
+       },
+};
+
+static void
+ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed)
+{
+       if (speed > AO_SERIAL_SPEED_115200)
+               return;
+       usart->reg->brr = ao_usart_speeds[speed].brr;
+}
+
+static void
+ao_usart_init(struct ao_stm_usart *usart)
+{
+       usart->reg->cr1 = ((0 << STM_USART_CR1_M1) |
+                          (0 << STM_USART_CR1_EOBIE) |
+                          (0 << STM_USART_CR1_RTOIE) |
+                          (0 << STM_USART_CR1_DEAT) |
+                          (0 << STM_USART_CR1_DEDT) |
+                          (0 << STM_USART_CR1_OVER8) |
+                          (0 << STM_USART_CR1_CMIE) |
+                          (0 << STM_USART_CR1_MME) |
+                          (0 << STM_USART_CR1_M0) |
+                          (0 << STM_USART_CR1_WAKE) |
+                          (0 << STM_USART_CR1_PCE) |
+                          (0 << STM_USART_CR1_PS) |
+                          (0 << STM_USART_CR1_PEIE) |
+                          (0 << STM_USART_CR1_TXEIE) |
+                          (0 << STM_USART_CR1_TCIE) |
+                          (1 << STM_USART_CR1_RXNEIE) |
+                          (0 << STM_USART_CR1_IDLEIE) |
+                          (1 << STM_USART_CR1_TE) |
+                          (1 << STM_USART_CR1_RE) |
+                          (0 << STM_USART_CR1_UESM) |
+                          (0 << STM_USART_CR1_UE));
+
+       usart->reg->cr2 = ((0 << STM_USART_CR2_ADD) |
+                          (0 << STM_USART_CR2_RTOEN) |
+                          (0 << STM_USART_CR2_ABRMOD) |
+                          (0 << STM_USART_CR2_ABREN) |
+                          (0 << STM_USART_CR2_MSBFIRST) |
+                          (0 << STM_USART_CR2_DATAINV) |
+                          (0 << STM_USART_CR2_TXINV) |
+                          (0 << STM_USART_CR2_RXINV) |
+                          (0 << STM_USART_CR2_SWAP) |
+                          (0 << STM_USART_CR2_LINEN) |
+                          (0 << STM_USART_CR2_STOP) |
+                          (0 << STM_USART_CR2_CLKEN) |
+                          (0 << STM_USART_CR2_CPOL) |
+                          (0 << STM_USART_CR2_CHPA) |
+                          (0 << STM_USART_CR2_LBCL) |
+                          (0 << STM_USART_CR2_LBDIE) |
+                          (0 << STM_USART_CR2_LBDL) |
+                          (0 << STM_USART_CR2_ADDM7));
+
+       usart->reg->cr3 = ((0 << STM_USART_CR3_WUFIE) |
+                          (0 << STM_USART_CR3_WUS) |
+                          (0 << STM_USART_CR3_SCARCNT) |
+                          (0 << STM_USART_CR3_DEP) |
+                          (0 << STM_USART_CR3_DEM) |
+                          (0 << STM_USART_CR3_DDRE) |
+                          (0 << STM_USART_CR3_OVRDIS) |
+                          (0 << STM_USART_CR3_ONEBIT) |
+                          (0 << STM_USART_CR3_CTIIE) |
+                          (0 << STM_USART_CR3_CTSE) |
+                          (0 << STM_USART_CR3_RTSE) |
+                          (0 << STM_USART_CR3_DMAT) |
+                          (0 << STM_USART_CR3_DMAR) |
+                          (0 << STM_USART_CR3_SCEN) |
+                          (0 << STM_USART_CR3_NACK) |
+                          (0 << STM_USART_CR3_HDSEL) |
+                          (0 << STM_USART_CR3_IRLP) |
+                          (0 << STM_USART_CR3_IREN) |
+                          (0 << STM_USART_CR3_EIE));
+
+
+       /* Pick a 9600 baud rate */
+       ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600);
+
+       /* Enable the usart */
+       usart->reg->cr1 |= (1 << STM_USART_CR1_UE);
+
+}
+
+#if HAS_SERIAL_HW_FLOW
+static void
+ao_usart_set_flow(struct ao_stm_usart *usart)
+{
+       usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) |
+                           (1 << STM_USART_CR3_RTSE));
+}
+#endif
+
+#if HAS_SERIAL_1
+
+struct ao_stm_usart ao_stm_usart1;
+
+void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); }
+
+char
+ao_serial1_getchar(void)
+{
+       return ao_usart_getchar(&ao_stm_usart1);
+}
+
+void
+ao_serial1_putchar(char c)
+{
+       ao_usart_putchar(&ao_stm_usart1, c);
+}
+
+int
+_ao_serial1_pollchar(void)
+{
+       return _ao_usart_pollchar(&ao_stm_usart1);
+}
+
+uint8_t
+_ao_serial1_sleep_for(uint16_t timeout)
+{
+       return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
+}
+
+void
+ao_serial1_drain(void)
+{
+       ao_usart_drain(&ao_stm_usart1);
+}
+
+void
+ao_serial1_set_speed(uint8_t speed)
+{
+       ao_usart_drain(&ao_stm_usart1);
+       ao_usart_set_speed(&ao_stm_usart1, speed);
+}
+#endif /* HAS_SERIAL_1 */
+
+#if HAS_SERIAL_2
+
+struct ao_stm_usart ao_stm_usart2;
+
+void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); }
+
+char
+ao_serial2_getchar(void)
+{
+       return ao_usart_getchar(&ao_stm_usart2);
+}
+
+void
+ao_serial2_putchar(char c)
+{
+       ao_usart_putchar(&ao_stm_usart2, c);
+}
+
+int
+_ao_serial2_pollchar(void)
+{
+       return _ao_usart_pollchar(&ao_stm_usart2);
+}
+
+uint8_t
+_ao_serial2_sleep_for(uint16_t timeout)
+{
+       return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
+}
+
+void
+ao_serial2_drain(void)
+{
+       ao_usart_drain(&ao_stm_usart2);
+}
+
+void
+ao_serial2_set_speed(uint8_t speed)
+{
+       ao_usart_drain(&ao_stm_usart2);
+       ao_usart_set_speed(&ao_stm_usart2, speed);
+}
+
+#if HAS_SERIAL_SW_FLOW
+void
+ao_serial2_cts(void)
+{
+       _ao_usart_cts(&ao_stm_usart2);
+}
+#endif
+
+#endif /* HAS_SERIAL_2 */
+
+#if HAS_SERIAL_SW_FLOW
+static void
+ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart,
+                        void (*isr)(void),
+                        struct stm_gpio *port_rts,
+                        int pin_rts,
+                        struct stm_gpio *port_cts,
+                        int pin_cts)
+{
+       /* Pull RTS low to note that there's space in the FIFO
+        */
+       ao_enable_output(port_rts, pin_rts, foo, 0);
+       usart->gpio_rts = port_rts;
+       usart->pin_rts = pin_rts;
+       usart->rts = 1;
+
+       ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr);
+       usart->gpio_cts = port_cts;
+       usart->pin_cts = pin_cts;
+}
+#endif
+
+void
+ao_serial_init(void)
+{
+#if HAS_SERIAL_1
+       /*
+        *      TX      RX
+        *      PA9     PA10
+        *      PB6     PB7
+        */
+
+#if SERIAL_1_PA9_PA10
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+
+       stm_afr_set(&stm_gpioa, 9, STM_AFR_AF1);
+       stm_afr_set(&stm_gpioa, 10, STM_AFR_AF1);
+#else
+#if SERIAL_1_PB6_PB7
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
+
+       stm_afr_set(&stm_gpiob, 6, STM_AFR_AF0);
+       stm_afr_set(&stm_gpiob, 7, STM_AFR_AF0);
+#else
+#error "No SERIAL_1 port configuration specified"
+#endif
+#endif
+       /* Enable USART */
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
+
+       ao_stm_usart1.reg = &stm_usart1;
+       ao_usart_init(&ao_stm_usart1);
+
+       stm_nvic_set_enable(STM_ISR_USART1_POS);
+       stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
+#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
+       ao_add_stdio(_ao_serial1_pollchar,
+                    ao_serial1_putchar,
+                    NULL);
+#endif
+#endif
+
+#if HAS_SERIAL_2
+       /*
+        *      TX      RX
+        *      PA2     PA3
+        *      PA14    PA15
+        */
+
+# if SERIAL_2_PA2_PA3
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+
+       stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1);
+       stm_afr_set(&stm_gpioa, 3, STM_AFR_AF1);
+#  if USE_SERIAL_2_FLOW
+#   if USE_SERIAL_2_SW_FLOW
+       ao_serial_set_sw_rts_cts(&ao_stm_usart2,
+                                ao_serial2_cts,
+                                SERIAL_2_PORT_RTS,
+                                SERIAL_2_PIN_RTS,
+                                SERIAL_2_PORT_CTS,
+                                SERIAL_2_PIN_CTS);
+#   else
+       stm_afr_set(&stm_gpioa, 0, STM_AFR_AF1);
+       stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1);
+#   endif
+#  endif
+# else
+#  if SERIAL_2_PA14_PA15
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+
+       stm_afr_set(&stm_gpioa, 14, STM_AFR_AF1);
+       stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1);
+#   if USE_SERIAL_2_FLOW
+#    error "Don't know how to set flowcontrol for serial 2 on PA14"
+#   endif
+#  else
+#   if SERIAL_2_PA2_PA15
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+
+       stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1);
+       stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1);
+#    if USE_SERIAL_2_FLOW
+#     error "Don't know how to set flowcontrol for serial 2 on PA2_PA15"
+#    endif
+#   else
+#    error "No SERIAL_2 port configuration specified"
+#   endif
+#  endif
+# endif
+       /* Enable USART */
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);
+
+       ao_stm_usart2.reg = &stm_usart2;
+       ao_usart_init(&ao_stm_usart2);
+# if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW
+       ao_usart_set_flow(&ao_stm_usart2);
+# endif
+
+       stm_nvic_set_enable(STM_ISR_USART2_POS);
+       stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
+# if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
+       ao_add_stdio(_ao_serial2_pollchar,
+                    ao_serial2_putchar,
+                    NULL);
+# endif
+#endif
+}
index 0448ad8c375407167b1eeff93e04597a6dd07f75..5e76d6c3946c31ff534a6006b76d3987d7908bbf 100644 (file)
@@ -536,12 +536,18 @@ void
 ao_spi_init(void)
 {
 #if HAS_SPI_1
+#ifndef SPI_1_PA5_PA6_PA7
+#error SPI_1_PA5_PA6_PA7 undefined
+#endif
 # if SPI_1_PA5_PA6_PA7
        stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
        stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
        stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
        stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
 # endif
+# ifndef SPI_1_PB3_PB4_PB5
+# error SPI_1_PB3_PB4_PB5 undefined
+# endif
 # if SPI_1_PB3_PB4_PB5
        stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
        stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
diff --git a/src/stmf0/ao_spi_stm_slave.c b/src/stmf0/ao_spi_stm_slave.c
new file mode 100644 (file)
index 0000000..962ff2c
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+struct ao_spi_stm_slave_info {
+       uint8_t miso_dma_index;
+       uint8_t mosi_dma_index;
+       struct stm_spi *stm_spi;
+};
+
+static uint8_t         ao_spi_slave_mutex[STM_NUM_SPI];
+static uint8_t         ao_spi_slave_index[STM_NUM_SPI];
+
+static const struct ao_spi_stm_slave_info ao_spi_stm_slave_info[STM_NUM_SPI] = {
+       {
+               .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
+               .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
+               &stm_spi1
+       },
+       {
+               .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
+               .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
+               &stm_spi2
+       }
+};
+
+static uint8_t spi_dev_null;
+
+void
+ao_spi_slave_send(void *block, uint16_t len)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index;
+
+       /* Set up the transmit DMA to deliver data */
+       ao_dma_set_transfer(mosi_dma_index,
+                           &stm_spi->dr,
+                           block,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (1 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       /* Set up the receive DMA -- when this is done, we know the SPI unit
+        * is idle. Without this, we'd have to poll waiting for the BSY bit to
+        * be cleared
+        */
+       ao_dma_set_transfer(miso_dma_index,
+                           &stm_spi->dr,
+                           &spi_dev_null,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (0 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (1 << STM_SPI_CR2_TXDMAEN) |
+                       (1 << STM_SPI_CR2_RXDMAEN));
+       ao_dma_start(miso_dma_index);
+       ao_dma_start(mosi_dma_index);
+       ao_arch_critical(
+               while (!ao_dma_done[miso_dma_index])
+                       ao_sleep(&ao_dma_done[miso_dma_index]);
+               );
+       ao_dma_done_transfer(mosi_dma_index);
+       ao_dma_done_transfer(miso_dma_index);
+}
+
+uint8_t
+ao_spi_slave_recv(void *block, uint16_t len)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index;
+
+       /* Set up transmit DMA to make the SPI hardware actually run */
+       ao_dma_set_transfer(mosi_dma_index,
+                           &stm_spi->dr,
+                           &spi_dev_null,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (0 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       /* Set up the receive DMA to capture data */
+       ao_dma_set_transfer(miso_dma_index,
+                           &stm_spi->dr,
+                           block,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (1 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (1 << STM_SPI_CR2_TXDMAEN) |
+                       (1 << STM_SPI_CR2_RXDMAEN));
+       ao_dma_start(miso_dma_index);
+       ao_dma_start(mosi_dma_index);
+
+       /* Wait until the SPI unit is done */
+       ao_arch_critical(
+               while (!ao_dma_done[miso_dma_index])
+                       ao_sleep(&ao_dma_done[miso_dma_index]);
+               );
+
+       ao_dma_done_transfer(mosi_dma_index);
+       ao_dma_done_transfer(miso_dma_index);
+       return 1;
+}
+
+static void
+ao_spi_slave_disable_index(uint8_t spi_index)
+{
+       /* Disable current config
+        */
+       switch (AO_SPI_INDEX(spi_index)) {
+       case STM_SPI_INDEX(1):
+               switch (spi_index) {
+               case AO_SPI_1_PA5_PA6_PA7:
+                       stm_gpio_set(&stm_gpioa, 5, 1);
+                       stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
+                       break;
+               case AO_SPI_1_PB3_PB4_PB5:
+                       stm_gpio_set(&stm_gpiob, 3, 1);
+                       stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
+                       break;
+               case AO_SPI_1_PE13_PE14_PE15:
+                       stm_gpio_set(&stm_gpioe, 13, 1);
+                       stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
+                       break;
+               }
+               break;
+       case STM_SPI_INDEX(2):
+               switch (spi_index) {
+               case AO_SPI_2_PB13_PB14_PB15:
+                       stm_gpio_set(&stm_gpiob, 13, 1);
+                       stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
+                       break;
+               case AO_SPI_2_PD1_PD3_PD4:
+                       stm_gpio_set(&stm_gpiod, 1, 1);
+                       stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
+                       break;
+               }
+               break;
+       }
+}
+
+static void
+ao_spi_slave_enable_index(uint8_t spi_index)
+{
+       switch (AO_SPI_INDEX(spi_index)) {
+       case STM_SPI_INDEX(1):
+               switch (spi_index) {
+               case AO_SPI_1_PA5_PA6_PA7:
+                       stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
+                       break;
+               case AO_SPI_1_PB3_PB4_PB5:
+                       stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
+                       break;
+               case AO_SPI_1_PE13_PE14_PE15:
+                       stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
+                       break;
+               }
+               break;
+       case STM_SPI_INDEX(2):
+               switch (spi_index) {
+               case AO_SPI_2_PB13_PB14_PB15:
+                       stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
+                       break;
+               case AO_SPI_2_PD1_PD3_PD4:
+                       stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
+                       stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
+                       break;
+               }
+               break;
+       }
+}
+
+void
+ao_spi_slave_get(uint8_t spi_index, uint32_t speed)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
+
+       ao_mutex_get(&ao_spi_slave_mutex[id]);
+       stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
+                       (0 << STM_SPI_CR1_BIDIOE) |
+                       (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
+                       (0 << STM_SPI_CR1_CRCNEXT) |
+                       (0 << STM_SPI_CR1_DFF) |
+                       (0 << STM_SPI_CR1_RXONLY) |
+                       (1 << STM_SPI_CR1_SSM) |                        /* Software SS handling */
+                       (1 << STM_SPI_CR1_SSI) |                        /*  ... */
+                       (0 << STM_SPI_CR1_LSBFIRST) |                   /* Big endian */
+                       (1 << STM_SPI_CR1_SPE) |                        /* Enable SPI unit */
+                       (speed << STM_SPI_CR1_BR) |     /* baud rate to pclk/4 */
+                       (1 << STM_SPI_CR1_MSTR) |
+                       (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
+                       (0 << STM_SPI_CR1_CPHA));
+       if (spi_index != ao_spi_slave_index[id]) {
+               
+               /* Disable old config
+                */
+               ao_spi_slave_disable_index(ao_spi_slave_index[id]);
+
+               /* Enable new config
+                */
+               ao_spi_slave_enable_index(spi_index);
+               
+               /* Remember current config
+                */
+               ao_spi_slave_index[id] = spi_index;
+       }
+}
+
+void
+ao_spi_slave_put(uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
+
+       stm_spi->cr1 = 0;
+       ao_mutex_put(&ao_spi_slave_mutex[id]);
+}
+
+static void
+ao_spi_channel_init(uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
+
+       ao_spi_slave_disable_index(spi_index);
+
+       stm_spi->cr1 = 0;
+       (void) stm_spi->sr;
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (0 << STM_SPI_CR2_TXDMAEN) |
+                       (0 << STM_SPI_CR2_RXDMAEN));
+}
+
+void
+ao_spi_slave_init(void)
+{
+#if HAS_SPI_SLAVE_1
+# if SPI_1_PA5_PA6_PA7
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+# endif
+# if SPI_1_PB3_PB4_PB5
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+# endif
+# if SPI_1_PE13_PE14_PE15
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
+# endif
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+       ao_spi_slave_index[0] = AO_SPI_CONFIG_NONE;
+       ao_spi_channel_init(0);
+#endif
+
+#if HAS_SPI_SLAVE_2
+# if SPI_2_PB13_PB14_PB15
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+# endif
+# if SPI_2_PD1_PD3_PD4
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
+# endif
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+       ao_spi_slave_index[1] = AO_SPI_CONFIG_NONE;
+       ao_spi_channel_init(1);
+#endif
+}
index bafa763a10feedfaa3953db067bda9faf425a6da..e53a5dfde770b560d0978346f5c33474315647a1 100644 (file)
@@ -1812,15 +1812,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3;
 
 #define STM_TIM23_CCMR2_OC4CE  15
 #define STM_TIM23_CCMR2_OC4M   12
-#define  STM_TIM23_CCMR2_OCM_FROZEN                    0
-#define  STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH 1
-#define  STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH          2
-#define  STM_TIM23_CCMR2_OCM_TOGGLE                    3
-#define  STM_TIM23_CCMR2_OCM_FORCE_LOW                 4
-#define  STM_TIM23_CCMR2_OCM_FORCE_HIGH                        5
-#define  STM_TIM23_CCMR2_OCM_PWM_MODE_1                        6
-#define  STM_TIM23_CCMR2_OCM_PWM_MODE_2                        7
-#define  STM_TIM23_CCMR2_OCM_MASK                      7
+#define  STM_TIM23_CCMR2_OC4M_FROZEN                   0
+#define  STM_TIM23_CCMR2_OC4M_SET_HIGH_ON_MATCH        1
+#define  STM_TIM23_CCMR2_OC4M_SET_LOW_ON_MATCH         2
+#define  STM_TIM23_CCMR2_OC4M_TOGGLE                   3
+#define  STM_TIM23_CCMR2_OC4M_FORCE_LOW                        4
+#define  STM_TIM23_CCMR2_OC4M_FORCE_HIGH               5
+#define  STM_TIM23_CCMR2_OC4M_PWM_MODE_1               6
+#define  STM_TIM23_CCMR2_OC4M_PWM_MODE_2               7
+#define  STM_TIM23_CCMR2_OC4M_MASK                     7
 #define STM_TIM23_CCMR2_OC4PE  11
 #define STM_TIM23_CCMR2_OC4FE  10
 #define STM_TIM23_CCMR2_CC4S   8
@@ -1832,15 +1832,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3;
 
 #define STM_TIM23_CCMR2_OC3CE  7
 #define STM_TIM23_CCMR2_OC3M   4
-#define  STM_TIM23_CCMR2_OCM_FROZEN                    0
-#define  STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH         1
-#define  STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH          2
-#define  STM_TIM23_CCMR2_OCM_TOGGLE                    3
-#define  STM_TIM23_CCMR2_OCM_FORCE_LOW                 4
-#define  STM_TIM23_CCMR2_OCM_FORCE_HIGH                        5
+#define  STM_TIM23_CCMR2_OC3M_FROZEN                   0
+#define  STM_TIM23_CCMR2_OC3M_SET_HIGH_ON_MATCH                1
+#define  STM_TIM23_CCMR2_OC3M_SET_LOW_ON_MATCH         2
+#define  STM_TIM23_CCMR2_OC3M_TOGGLE                   3
+#define  STM_TIM23_CCMR2_OC3M_FORCE_LOW                        4
+#define  STM_TIM23_CCMR2_OC3M_FORCE_HIGH               5
 #define  STM_TIM23_CCMR2_OC3M_PWM_MODE_1               6
-#define  STM_TIM23_CCMR2_OCM_PWM_MODE_2                        7
-#define  STM_TIM23_CCMR2_OCM_MASK                      7
+#define  STM_TIM23_CCMR2_OC3M_PWM_MODE_2               7
+#define  STM_TIM23_CCMR2_OC3M_MASK                     7
 #define STM_TIM23_CCMR2_OC3PE  11
 #define STM_TIM23_CCMR2_OC3FE  2
 #define STM_TIM23_CCMR2_CC3S   0
@@ -2010,4 +2010,129 @@ struct stm_exti {
 
 extern struct stm_exti stm_exti;
 
+struct stm_usart {
+       vuint32_t       cr1;    /* control register 1 */
+       vuint32_t       cr2;    /* control register 2 */
+       vuint32_t       cr3;    /* control register 3 */
+       vuint32_t       brr;    /* baud rate register */
+
+       vuint32_t       gtpr;   /* guard time and prescaler */
+       vuint32_t       rtor;   /* receiver timeout register */
+       vuint32_t       rqr;    /* request register */
+       vuint32_t       isr;    /* interrupt and status register */
+
+       vuint32_t       icr;    /* interrupt flag clear register */
+       vuint32_t       rdr;    /* receive data register */
+       vuint32_t       tdr;    /* transmit data register */
+};
+
+#define STM_USART_CR1_M1       28
+#define STM_USART_CR1_EOBIE    27
+#define STM_USART_CR1_RTOIE    26
+#define STM_USART_CR1_DEAT     21
+#define STM_USART_CR1_DEDT     16
+#define STM_USART_CR1_OVER8    15
+#define STM_USART_CR1_CMIE     14
+#define STM_USART_CR1_MME      13
+#define STM_USART_CR1_M0       12
+#define STM_USART_CR1_WAKE     11
+#define STM_USART_CR1_PCE      10
+#define STM_USART_CR1_PS       9
+#define STM_USART_CR1_PEIE     8
+#define STM_USART_CR1_TXEIE    7
+#define STM_USART_CR1_TCIE     6
+#define STM_USART_CR1_RXNEIE   5
+#define STM_USART_CR1_IDLEIE   4
+#define STM_USART_CR1_TE       3
+#define STM_USART_CR1_RE       2
+#define STM_USART_CR1_UESM     1
+#define STM_USART_CR1_UE       0
+
+#define STM_USART_CR2_ADD      24
+#define STM_USART_CR2_RTOEN    23
+#define STM_USART_CR2_ABRMOD   21
+#define STM_USART_CR2_ABREN    20
+#define STM_USART_CR2_MSBFIRST 19
+#define STM_USART_CR2_DATAINV  18
+#define STM_USART_CR2_TXINV    17
+#define STM_USART_CR2_RXINV    16
+#define STM_USART_CR2_SWAP     15
+#define STM_USART_CR2_LINEN    14
+#define STM_USART_CR2_STOP     12
+#define STM_USART_CR2_CLKEN    11
+#define STM_USART_CR2_CPOL     10
+#define STM_USART_CR2_CHPA     9
+#define STM_USART_CR2_LBCL     8
+#define STM_USART_CR2_LBDIE    6
+#define STM_USART_CR2_LBDL     5
+#define STM_USART_CR2_ADDM7    4
+
+#define STM_USART_CR3_WUFIE    22
+#define STM_USART_CR3_WUS      20
+#define STM_USART_CR3_SCARCNT  17
+#define STM_USART_CR3_DEP      15
+#define STM_USART_CR3_DEM      14
+#define STM_USART_CR3_DDRE     13
+#define STM_USART_CR3_OVRDIS   12
+#define STM_USART_CR3_ONEBIT   11
+#define STM_USART_CR3_CTIIE    10
+#define STM_USART_CR3_CTSE     9
+#define STM_USART_CR3_RTSE     8
+#define STM_USART_CR3_DMAT     7
+#define STM_USART_CR3_DMAR     6
+#define STM_USART_CR3_SCEN     5
+#define STM_USART_CR3_NACK     4
+#define STM_USART_CR3_HDSEL    3
+#define STM_USART_CR3_IRLP     2
+#define STM_USART_CR3_IREN     1
+#define STM_USART_CR3_EIE      0
+
+#define STM_USART_GTPR_GT      8
+#define STM_USART_GTPR_PSC     0
+
+#define STM_USART_RQR_TXFRQ    4
+#define STM_USART_RQR_RXFRQ    3
+#define STM_USART_RQR_MMRQ     2
+#define STM_USART_RQR_SBKRQ    1
+#define STM_USART_RQR_ABRRQ    0
+
+#define STM_USART_ISR_REACK    22
+#define STM_USART_ISR_TEACK    21
+#define STM_USART_ISR_WUF      20
+#define STM_USART_ISR_RWU      19
+#define STM_USART_ISR_SBKF     18
+#define STM_USART_ISR_CMF      17
+#define STM_USART_ISR_BUSY     16
+#define STM_USART_ISR_ABRF     15
+#define STM_USART_ISR_ABRE     14
+#define STM_USART_ISR_EOBF     12
+#define STM_USART_ISR_RTOF     11
+#define STM_USART_ISR_CTS      10
+#define STM_USART_ISR_CTSIF    9
+#define STM_USART_ISR_LBDF     8
+#define STM_USART_ISR_TXE      7
+#define STM_USART_ISR_TC       6
+#define STM_USART_ISR_RXNE     5
+#define STM_USART_ISR_IDLE     4
+#define STM_USART_ISR_ORE      3
+#define STM_USART_ISR_NF       2
+#define STM_USART_ISR_FE       1
+#define STM_USART_ISR_PE       0
+
+#define STM_USART_ICR_WUCF     20
+#define STM_USART_ICR_CMCF     17
+#define STM_USART_ICR_EOBCF    12
+#define STM_USART_ICR_RTOCF    11
+#define STM_USART_ICR_CTSCF    9
+#define STM_USART_ICR_LBDCF    8
+#define STM_USART_ICR_TCCF     6
+#define STM_USART_ICR_IDLECF   4
+#define STM_USART_ICR_ORECF    3
+#define STM_USART_ICR_NCF      2
+#define STM_USART_ICR_FECF     1
+#define STM_USART_ICR_PECF     0
+
+extern struct stm_usart        stm_usart1;
+extern struct stm_usart stm_usart2;
+
 #endif /* _STM32F0_H_ */
index a7ef4d64bef9e5e9f4b8843870ae0e603246c9ff..40d1f6e472dc9bf2958f42948a56b0d98ec635dc 100644 (file)
@@ -58,7 +58,12 @@ ALTOS_SRC = \
        ao_monitor.c \
        $(PROFILE) \
        $(SAMPLE_PROFILE) \
-       $(STACK_GUARD)
+       $(STACK_GUARD) \
+       ao_lco_func.c \
+       ao_radio_cmac.c \
+       ao_aes.c \
+       ao_aes_tables.c \
+       ao_lco_cmd.c
 
 PRODUCT=TeleBT-v3.0
 PRODUCT_DEF=-DTELEBT_V_3_0
index 61cbe9bba62fa2a9ffea5b0844fd52b4a3e1907a..62dddf2a2f8fa7da5ab1acfe9716aaa48196f97a 100644 (file)
@@ -80,6 +80,7 @@
 #define HAS_TELEMETRY          0
 #define HAS_APRS               0
 #define HAS_ACCEL              0
+#define HAS_AES                        1
 
 #define HAS_SPI_1              1
 #define SPI_1_PA5_PA6_PA7      1       /* CC1200 */
@@ -197,6 +198,7 @@ struct ao_adc {
 #define AO_CC1200_SPI_CS_PIN   10
 #define AO_CC1200_SPI_BUS      AO_SPI_1_PA5_PA6_PA7
 #define AO_CC1200_SPI          stm_spi1
+#define AO_CC1200_SPI_SPEED    AO_SPI_SPEED_FAST
 
 #define AO_CC1200_INT_PORT             (&stm_gpiob)
 #define AO_CC1200_INT_PIN              (11)
index 9117863bfa4f86772218c639374de451ea4dc60b..8775d99380312ea92e779bcfd61cbb15ff0c8613 100644 (file)
@@ -22,6 +22,7 @@
 #include <ao_eeprom.h>
 #include <ao_profile.h>
 #include <ao_btm.h>
+#include <ao_lco_cmd.h>
 #if HAS_SAMPLE_PROFILE
 #include <ao_sample_profile.h>
 #endif
@@ -44,6 +45,8 @@ main(void)
        ao_btm_init();
        ao_cmd_init();
 
+       ao_lco_cmd_init();
+
        ao_eeprom_init();
 
        ao_usb_init();
index effc2322028e23733c806ba545abcb6b6157c837..be710aef3ca17a10458822e30ce8ddac68a11dfe 100644 (file)
@@ -96,6 +96,7 @@
 #define AO_CC1200_SPI_CS_PIN   3
 #define AO_CC1200_SPI_BUS      0
 #define AO_CC1200_SPI          0
+#define AO_CC1200_SPI_SPEED    AO_SPI_SPEED_8MHz
 
 #define AO_CC1200_INT_PORT     0
 #define AO_CC1200_INT_PIN      2
index f56061b2d2fa5bac7b93d68e328aa1c535b6dcf3..1e5c0d09bac5c943979c0341b37431e32532faa2 100644 (file)
 #define AO_CC1200_SPI_CS_PIN   7
 #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_gpiob)
 #define AO_CC1200_INT_PIN              (11)
index 70af5dd198976beac23b3353b3caf7d67ce4b031..469e9937b89d9214631e5393abde407b6bf734b1 100644 (file)
 #define AO_CC1200_SPI_CS_PIN   7
 #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_gpiob)
 #define AO_CC1200_INT_PIN              (11)
diff --git a/src/telefiretwo-v1.0/Makefile b/src/telefiretwo-v1.0/Makefile
new file mode 100644 (file)
index 0000000..87d5d47
--- /dev/null
@@ -0,0 +1,95 @@
+#
+# TeleFire build file
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_pins.h \
+       ao_log.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pad.h \
+       ao_product.h \
+       ao_radio_spi.h \
+       ao_radio_cmac.h \
+       ao_cc1200_CC1200.h \
+       ao_cc1200.h \
+       stm32l.h
+#
+# Common AltOS sources
+#
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+ALTOS_SRC = \
+       ao_boot_chain.c \
+       ao_interrupt.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_adc_stm.c \
+       ao_data.c \
+       ao_config.c \
+       ao_task.c \
+       ao_led.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c \
+       ao_beep_stm.c \
+       ao_eeprom_stm.c \
+       ao_storage.c \
+       ao_m25.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       ao_cc1200.c \
+       ao_radio_cmac.c \
+       ao_aes.c \
+       ao_aes_tables.c \
+       ao_pad.c \
+       ao_radio_cmac_cmd.c \
+       ao_log.c \
+       ao_log_firetwo.c
+
+PRODUCT_SRC = \
+       ao_telefiretwo.c
+
+PRODUCT=TeleFireTwo-v1.0
+PRODUCT_DEF=-DTELEFIRETWO_V_1_0
+IDPRODUCT=0x000f
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+
+PROGNAME = telefiretwo-v1.0
+PROG = $(PROGNAME)-$(VERSION).elf
+HEX = $(PROGNAME)-$(VERSION).ihx
+
+SRC = $(ALTOS_SRC) $(PRODUCT_SRC)
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(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/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h
new file mode 100644 (file)
index 0000000..b2f5a5a
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright © 2010 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_RADIO              1
+#define HAS_RADIO_RATE         1
+#define HAS_TELEMETRY          0
+
+#define HAS_FLIGHT             0
+#define HAS_USB                        1
+#define HAS_BEEP               1
+#define BEEPER_CHANNEL         4
+#define HAS_GPS                        0
+#define HAS_SERIAL_1           0
+#define HAS_ADC                        1
+#define HAS_DBG                        0
+#define HAS_EEPROM             1
+#define HAS_LOG                        1
+#define HAS_PAD                        1
+#define USE_INTERNAL_FLASH     0
+#define IGNITE_ON_P0           0
+#define PACKET_HAS_MASTER      0
+#define PACKET_HAS_SLAVE       0
+#define AO_DATA_RING           32
+#define HAS_FIXED_PAD_BOX      1
+
+#define LOG_ERASE_MARK         0x55
+
+/* 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)
+
+#define AO_CC1200_FOSC         40000000
+
+/* 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_EEPROM             1
+#define USE_EEPROM_CONFIG      1
+#define USE_STORAGE_CONFIG     0
+#define HAS_USB                        1
+#define HAS_RADIO              1
+#define HAS_RADIO_RATE         1
+#define HAS_TELEMETRY          0
+#define HAS_AES                        1
+
+#define HAS_SPI_1              0
+#define SPI_1_PA5_PA6_PA7      0
+#define SPI_1_PB3_PB4_PB5      0
+#define SPI_1_PE13_PE14_PE15   0
+
+#define HAS_SPI_2              1       /* CC1200 */
+#define SPI_2_PB13_PB14_PB15   1
+#define SPI_2_PD1_PD3_PD4      0
+#define SPI_2_GPIO             (&stm_gpiob)
+#define SPI_2_SCK              13
+#define SPI_2_MISO             14
+#define SPI_2_MOSI             15
+#define SPI_2_OSPEEDR          STM_OSPEEDR_10MHz
+
+#define HAS_I2C_1              0
+
+#define HAS_I2C_2              0
+
+#define PACKET_HAS_SLAVE       0
+#define PACKET_HAS_MASTER      0
+
+#define FAST_TIMER_FREQ                10000   /* .1ms for debouncing */
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS           1
+#define AO_M25_SPI_CS_PORT      (&stm_gpioa)
+#define AO_M25_SPI_CS_MASK      (1 << 15)
+#define AO_M25_SPI_BUS          AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio is a cc1200 connected via SPI
+ */
+
+#define AO_RADIO_CAL_DEFAULT   5695733
+
+#define AO_FEC_DEBUG           0
+#define AO_CC1200_SPI_CS_PORT  (&stm_gpioa)
+#define AO_CC1200_SPI_CS_PIN   7
+#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_gpiob)
+#define AO_CC1200_INT_PIN              (11)
+
+#define AO_CC1200_INT_GPIO     2
+#define AO_CC1200_INT_GPIO_IOCFG       CC1200_IOCFG2
+
+#define LED_PORT_0             (&stm_gpioa)
+#define LED_PORT_1             (&stm_gpiob)
+
+#define LED_PORT_0_ENABLE      STM_RCC_AHBENR_GPIOAEN
+#define LED_PORT_1_ENABLE      STM_RCC_AHBENR_GPIOBEN
+
+/* Port A, pins 4-6 */
+#define LED_PORT_0_SHIFT       4
+#define LED_PORT_0_MASK                0x7
+#define LED_PIN_GREEN          0
+#define LED_PIN_AMBER          1
+#define LED_PIN_RED            2
+#define AO_LED_RED             (1 << LED_PIN_RED)
+#define AO_LED_AMBER           (1 << LED_PIN_AMBER)
+#define AO_LED_GREEN           (1 << LED_PIN_GREEN)
+
+/* Port B, pins 4-5 */
+#define LED_PORT_1_SHIFT       0
+#define LED_PORT_1_MASK                (0x3 << 4)
+#define LED_PIN_CONT_0         4
+#define LED_PIN_ARMED          5
+
+#define AO_LED_ARMED           (1 << LED_PIN_ARMED)
+#define AO_LED_CONTINUITY(c)   (1 << (4 - (c)))
+#define AO_LED_CONTINUITY_MASK (0x1 << 4)
+
+#define LEDS_AVAILABLE         (LED_PORT_0_MASK|LED_PORT_1_MASK)
+
+/* Alarm A */
+#define AO_SIREN
+#define AO_SIREN_PORT          (&stm_gpiob)
+#define AO_SIREN_PIN           8
+
+/* Alarm B */
+#define AO_STROBE
+#define AO_STROBE_PORT         (&stm_gpiob)
+#define AO_STROBE_PIN          9
+
+#define SPI_CONST      0x00
+
+#define AO_PAD_NUM             1
+#define        AO_PAD_PORT             (&stm_gpioa)
+
+#define AO_PAD_PIN_0           1
+#define AO_PAD_ADC_0           0
+
+#define AO_PAD_ALL_PINS                ((1 << AO_PAD_PIN_0))
+#define AO_PAD_ALL_CHANNELS    ((1 << 0))
+
+/* test these values with real igniters */
+#define AO_PAD_RELAY_CLOSED    3524
+#define AO_PAD_NO_IGNITER      16904
+#define AO_PAD_GOOD_IGNITER    22514
+
+#define AO_PAD_ADC_PYRO                2
+#define AO_PAD_ADC_BATT                8
+
+#define AO_PAD_ADC_THRUST      3
+#define AO_PAD_ADC_PRESSURE    18
+
+#define AO_ADC_FIRST_PIN       0
+
+#define AO_NUM_ADC             5
+
+#define AO_ADC_SQ1             AO_PAD_ADC_0
+#define AO_ADC_SQ2             AO_PAD_ADC_PYRO
+#define AO_ADC_SQ3             AO_PAD_ADC_BATT
+#define AO_ADC_SQ4             AO_PAD_ADC_THRUST
+#define AO_ADC_SQ5             AO_PAD_ADC_PRESSURE
+
+#define AO_PYRO_R_PYRO_SENSE   200
+#define AO_PYRO_R_SENSE_GND    22
+
+#define AO_FIRE_R_POWER_FET    0
+#define AO_FIRE_R_FET_SENSE    200
+#define AO_FIRE_R_SENSE_GND    22
+
+#define HAS_ADC_TEMP           0
+
+struct ao_adc {
+       int16_t         sense[AO_PAD_NUM];
+       int16_t         pyro;
+       int16_t         batt;
+       int16_t         thrust;
+       int16_t         pressure;
+};
+
+#define AO_ADC_DUMP(p)                                                 \
+       printf ("tick: %5u 0: %5d pyro: %5d batt %5d thrust %5d pressure %5d\n", \
+               (p)->tick,                                              \
+               (p)->adc.sense[0],                                      \
+               (p)->adc.pyro,                                          \
+               (p)->adc.batt,                                          \
+               (p)->adc.thrust,                                        \
+               (p)->adc.pressure)
+
+#define AO_ADC_PINS    ((1 << AO_PAD_ADC_0) | \
+                        (1 << AO_PAD_ADC_PYRO) | \
+                        (1 << AO_PAD_ADC_BATT) | \
+                        (1 << AO_PAD_ADC_THRUST) | \
+                        (1 << AO_PAD_ADC_PRESSURE))
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telefiretwo-v1.0/ao_telefiretwo.c b/src/telefiretwo-v1.0/ao_telefiretwo.c
new file mode 100644 (file)
index 0000000..115b3e9
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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_log.h>
+#include <ao_pad.h>
+#include <ao_exti.h>
+#include <ao_radio_cmac_cmd.h>
+#include <ao_eeprom.h>
+
+static void
+set_logging(void)
+{
+       ao_cmd_hex();
+       ao_log_running = ao_cmd_lex_i;
+       ao_wakeup(&ao_log_running);
+}
+
+__code struct ao_cmds ao_firetwo_cmds[] = {
+        { set_logging,  "L <0 off, 1 on>\0Log sensors to flash" },
+        { 0,    NULL },
+};
+
+void
+main(void)
+{
+       ao_clock_init();
+
+       ao_led_init(LEDS_AVAILABLE);
+
+       ao_task_init();
+
+       ao_timer_init();
+       ao_spi_init();
+       ao_dma_init();
+       ao_exti_init();
+
+       ao_cmd_register(&ao_firetwo_cmds[0]);
+       ao_cmd_init();
+
+       ao_adc_init();
+
+       ao_eeprom_init();
+       ao_storage_init();
+       ao_log_init();
+
+       ao_radio_init();
+
+       ao_usb_init();
+
+       ao_config_init();
+
+       ao_pad_init();
+
+//     ao_radio_cmac_cmd_init();
+
+       ao_start_scheduler();
+}
diff --git a/src/telefiretwo-v1.0/flash-loader/.gitignore b/src/telefiretwo-v1.0/flash-loader/.gitignore
new file mode 100644 (file)
index 0000000..65fe7ea
--- /dev/null
@@ -0,0 +1,2 @@
+*.elf
+*.ihx
diff --git a/src/telefiretwo-v1.0/flash-loader/Makefile b/src/telefiretwo-v1.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..d429dcc
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telefiretwo-v1.0
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/telefiretwo-v1.0/flash-loader/ao_pins.h b/src/telefiretwo-v1.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..ded45a4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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_
+
+/* External crystal at 8MHz */
+#define AO_HSE         8000000
+
+#include <ao_flash_stm_pins.h>
+
+#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 96e8cfd7d1d5f4d00a2f0d152d5d9cc6d313df5c..5afc9498c7d22bcdd01d1032ba85e86a5cf602b1 100644 (file)
 #define AO_CC115L_SPI_CS_PIN   12
 #define AO_CC115L_SPI_BUS      AO_SPI_2_PB13_PB14_PB15
 #define AO_CC115L_SPI          stm_spi2
+#define AO_CC115L_SPI_SPEED    AO_SPI_SPEED_4MHz
 
 #define AO_CC115L_FIFO_INT_GPIO_IOCFG  CC115L_IOCFG2
 #define AO_CC115L_FIFO_INT_PORT                (&stm_gpioa)
 #define AO_SDCARD_SPI_CS_PIN   4
 #define AO_SDCARD_SPI          stm_spi1
 
+#define SDCARD_DEBUG           1
+#define SDCARD_WARN            1
+#define SDCARD_TRACE           1
+
 #endif /* _AO_PINS_H_ */
index eb8ab72d0d6d7f0d040b518c5b856bf8dd7da72f..f734d90fcde863cf9f0a8fde361a50730bc5a50a 100644 (file)
@@ -49,16 +49,16 @@ main(void)
        ao_cmd_init();
 
        ao_usb_init();
-       ao_radio_init();
+//     ao_radio_init();
 
        ao_fat_init();
 
-       ao_gps_init();
-       ao_gps_report_mega_init();
+//     ao_gps_init();
+//     ao_gps_report_mega_init();
 
-       ao_telemetry_init();
-       ao_telemetry_set_interval(AO_SEC_TO_TICKS(1));
-       ao_rdf_set(1);
+//     ao_telemetry_init();
+//     ao_telemetry_set_interval(AO_SEC_TO_TICKS(1));
+//     ao_rdf_set(1);
 
 #if HAS_SAMPLE_PROFILE
        ao_sample_profile_init();
index 9c650cc42441f1b646ab9de036fa887fd46a6202..28ae30a47da0d0501e2ddc787272da3dcf3d8d54 100644 (file)
@@ -95,6 +95,7 @@
 #define AO_CC115L_SPI_CS_PORT  0
 #define AO_CC115L_SPI_CS_PIN   3
 #define AO_CC115L_SPI_BUS      0
+#define AO_CC115L_SPI_SPEED    AO_SPI_SPEED_6MHz
 
 #define AO_CC115L_FIFO_INT_GPIO_IOCFG  CC115L_IOCFG2
 #define AO_CC115L_FIFO_INT_PORT                0
index 19774f63cc703e514902e38934b890864e1811c7..9672ab037dbd8005b2c2efe2c9c78e2f8080f684 100644 (file)
@@ -97,6 +97,7 @@
 #define AO_CC115L_SPI_CS_PORT  0
 #define AO_CC115L_SPI_CS_PIN   3
 #define AO_CC115L_SPI_BUS      0
+#define AO_CC115L_SPI_SPEED    AO_SPI_SPEED_6MHz
 
 #define AO_CC115L_FIFO_INT_GPIO_IOCFG  CC115L_IOCFG2
 #define AO_CC115L_FIFO_INT_PORT                0
diff --git a/src/telegps-v2.0/Makefile b/src/telegps-v2.0/Makefile
new file mode 100644 (file)
index 0000000..19d088d
--- /dev/null
@@ -0,0 +1,89 @@
+#
+# AltOS build
+#
+#
+
+include ../stmf0/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_tracker.h \
+       ao_task.h \
+       ao_cc1200.h \
+       ao_fec.h \
+       stm32f0.h \
+       Makefile
+
+
+ALTOS_SRC = \
+       ao_adc_stm.c \
+       ao_led.c \
+       ao_interrupt.c \
+       ao_boot_chain.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_task.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       ao_serial_stm.c \
+       ao_gps_ublox.c \
+       ao_gps_show.c \
+       ao_cc1200.c \
+       ao_aprs.c \
+       ao_tracker.c \
+       ao_telemetry.c \
+       ao_storage.c \
+       ao_m25.c \
+       ao_log.c \
+       ao_log_gps.c \
+       ao_distance.c \
+       ao_sqrt.c \
+       ao_data.c \
+       ao_convert_volt.c \
+       $(SAMPLE_PROFILE)
+
+PRODUCT=TeleGPS-v2.0
+PRODUCT_DEF=-DTELEGPS
+IDPRODUCT=0x0025
+
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) $(PROFILE_DEF) -g -Os
+
+PROGNAME=telegps-v2.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telegps.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+       $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(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 ao_serial_stm.h $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/telegps-v2.0/ao_pins.h b/src/telegps-v2.0/ao_pins.h
new file mode 100644 (file)
index 0000000..c51f0af
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright © 2017 Bdale Garbee <bdale@gag.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 LED_PORT_ENABLE STM_RCC_AHBENR_IOPBEN
+#define LED_PORT        (&stm_gpiob)
+#define LED_PIN_RED     5
+#define AO_LED_RED      (1 << LED_PIN_RED)
+
+#define LEDS_AVAILABLE  (AO_LED_RED)
+
+#define IS_FLASH_LOADER                0
+#define HAS_BEEP              0
+
+#define AO_HSE                  32000000
+#define AO_RCC_CFGR_PLLMUL      STM_RCC_CFGR_PLLMUL_3
+#define AO_PLLMUL               3
+#define AO_PLLDIV               1
+
+/* HCLK = 48MHz */
+#define AO_AHB_PRESCALER        1
+#define AO_RCC_CFGR_HPRE_DIV    STM_RCC_CFGR_HPRE_DIV_1
+
+/* APB = 48MHz */
+#define AO_APB_PRESCALER        1
+#define AO_RCC_CFGR_PPRE_DIV    STM_RCC_CFGR_PPRE_DIV_1
+
+#define AO_RCC_CFGR2_PLLDIV    STM_RCC_CFGR2_PREDIV_1
+
+#define HAS_USB                         1
+#define AO_USB_DIRECTIO                 0
+#define AO_PA11_PA12_RMP                1
+
+#define IS_FLASH_LOADER 0
+
+/* ADC */
+
+#define HAS_ADC                        1
+#define AO_ADC_PIN0_PORT        (&stm_gpioa)
+#define AO_ADC_PIN0_PIN         0
+#define AO_ADC_PIN0_CH          0
+
+#define AO_ADC_RCC_AHBENR       ((1 << STM_RCC_AHBENR_IOPAEN))
+
+#define AO_NUM_ADC              1
+
+#define AO_DATA_RING           4
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    56      /* 5.6k */
+#define AO_BATTERY_DIV_MINUS   100     /* 10k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV    33
+
+struct ao_adc {
+        int16_t                 v_batt;
+};
+
+#define AO_ADC_DUMP(p) \
+        printf("tick: %5u batt: %5d\n", \
+               (p)->tick, \
+               (p)->adc.v_batt)
+
+/* SPI */
+#define HAS_SPI_1               1
+#define HAS_SPI_2               0
+#define SPI_1_PA5_PA6_PA7       1
+#define SPI_1_PB3_PB4_PB5       0
+#define SPI_1_OSPEEDR           STM_OSPEEDR_HIGH
+
+#define HAS_MS5607              0
+
+/* Flash */
+
+#define M25_MAX_CHIPS           1
+#define AO_M25_SPI_CS_PORT      (&stm_gpiob)
+#define AO_M25_SPI_CS_MASK      (1 << 0)
+#define AO_M25_SPI_BUS          AO_SPI_1_PA5_PA6_PA7
+
+#define HAS_SERIAL_1           1
+#define SERIAL_1_PB6_PB7       1
+#define USE_SERIAL_1_STDIN     0
+
+#define ao_gps_getchar         ao_serial1_getchar
+#define ao_gps_putchar         ao_serial1_putchar
+#define ao_gps_set_speed       ao_serial1_set_speed
+#define ao_gps_fifo            (ao_usart_rx_fifo)
+
+#define HAS_EEPROM             1
+#define USE_INTERNAL_FLASH     0
+#define HAS_RADIO              1
+#define HAS_TELEMETRY          1
+#define HAS_RDF                        1
+#define HAS_APRS               1
+#define HAS_RADIO_RECV         0
+
+#define HAS_GPS                        1
+#define HAS_FLIGHT             0
+#define HAS_LOG                        1
+#define FLIGHT_LOG_APPEND      1
+#define HAS_TRACKER            1
+#define LOG_ADC                        0
+
+#define AO_CONFIG_DEFAULT_APRS_INTERVAL                0
+#define AO_CONFIG_DEFAULT_RADIO_POWER          0xc0
+
+/*
+ * GPS
+ */
+
+#define AO_SERIAL_SPEED_UBLOX  AO_SERIAL_SPEED_9600
+
+
+/*
+ * 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_gpioa)
+#define AO_CC1200_SPI_CS_PIN    5
+#define AO_CC1200_SPI_BUS       AO_SPI_1_PA5_PA6_PA7
+#define AO_CC1200_SPI           stm_spi1
+#define AO_CC1200_SPI_SPEED     AO_SPI_SPEED_FAST
+
+#define AO_CC1200_INT_PORT              (&stm_gpioa)
+#define AO_CC1200_INT_PIN               4
+#define AO_CC1200_MCU_WAKEUP_PORT       (&stm_gpioa)
+#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
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telegps-v2.0/ao_telegps.c b/src/telegps-v2.0/ao_telegps.c
new file mode 100644 (file)
index 0000000..7a923d1
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_tracker.h>
+
+int
+main(void)
+{
+       ao_clock_init();
+
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+
+       ao_task_init();
+       ao_timer_init();
+
+       ao_spi_init();
+       ao_exti_init();
+
+       ao_storage_init();
+
+       ao_serial_init();
+
+       ao_cmd_init();
+
+       ao_usb_init();
+       ao_radio_init();
+
+#if HAS_ADC
+       ao_adc_init();
+#endif
+
+       ao_gps_init();
+#if HAS_LOG
+       ao_log_init();
+#endif
+
+       ao_tracker_init();
+
+       ao_telemetry_init();
+
+#if HAS_SAMPLE_PROFILE
+       ao_sample_profile_init();
+#endif
+       ao_config_init();
+
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/telegps-v2.0/flash-loader/Makefile b/src/telegps-v2.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..c065969
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telegps-v2.0
+include $(TOPDIR)/stmf0/Makefile-flash.defs
diff --git a/src/telegps-v2.0/flash-loader/ao_pins.h b/src/telegps-v2.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..a83dbaa
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2017 Bdale Garbee <bdale@gag.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_
+
+#include <ao_flash_stm_pins.h>
+
+/* Pin 5 on debug connector */
+
+#define AO_BOOT_PIN            1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioa
+#define AO_BOOT_APPLICATION_PIN                15
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#define HAS_USB                        1
+#define AO_USB_DIRECTIO                0
+#define AO_PA11_PA12_RMP       1
+
+#endif /* _AO_PINS_H_ */
index d874a19b6646c0ee5be12e85e713c6e261ce4e31..dd4aaafbbdd8b3b7c8ee4101f38d9841ce062789 100644 (file)
@@ -89,6 +89,7 @@
 #define AO_CC1200_SPI_CS_PIN   0
 #define AO_CC1200_SPI_BUS      AO_SPI_2_PD1_PD3_PD4
 #define AO_CC1200_SPI          stm_spi2
+#define AO_CC1200_SPI_SPEED    AO_SPI_SPEED_FAST
 
 #define AO_CC1200_INT_PORT             (&stm_gpioc)
 #define AO_CC1200_INT_PIN              (15)
index 714a5c3a02c40d0c5c2fc206bbd33bb01a14a8c8..60e94c67eac90136988365ccc4bdd7c15c3cc4b4 100644 (file)
@@ -91,6 +91,7 @@
 #define AO_CC1200_SPI_CS_PIN   7
 #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_gpiob)
 #define AO_CC1200_INT_PIN              (11)
index b1c472da822520a62a4010fd3fc4f91df1a89280..c7c8ad1931610aa11a265cd16536f4ed95e65b03 100644 (file)
@@ -309,6 +309,7 @@ struct ao_adc {
 #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
index ccf2f18f9f4b227b20c447a3db97040203e6e7bc..b937b4222f3c8f4e482910613540adf3ba9b606c 100644 (file)
@@ -259,6 +259,7 @@ struct ao_adc {
 #define AO_CC1200_SPI_CS_PIN   2
 #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_gpioa)
 #define AO_CC1200_INT_PIN              (3)
index 4f1d36dfd2a41f8520af03e75982a97effc534a5..d2aa4c2d75e494836acf0b0396a8b5a47f8cef0b 100644 (file)
 #define AO_IGNITER_FIRE_TIME   AO_MS_TO_TICKS(50)
 #define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
 
-#define AO_SEND_MINI
-#define AO_LOG_FORMAT          AO_LOG_FORMAT_TELEMINI
+#define AO_SEND_MINI           AO_TELEMETRY_MINI2
+#define AO_LOG_FORMAT          AO_LOG_FORMAT_TELEMINI2
 
 /*
  * ADC
diff --git a/src/telemini-v3.0/Makefile b/src/telemini-v3.0/Makefile
new file mode 100644 (file)
index 0000000..4713b3a
--- /dev/null
@@ -0,0 +1,93 @@
+#
+# AltOS build
+#
+#
+
+include ../stmf0/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_cc1200.h \
+       ao_cc1200_CC1200.h \
+       stm32f0.h
+
+#
+# Common AltOS sources
+#
+
+ALTOS_SRC = \
+       ao_interrupt.c \
+       ao_boot_chain.c \
+       ao_romconfig.c \
+       ao_product.c \
+       ao_mutex.c \
+       ao_panic.c \
+       ao_stdio.c \
+       ao_storage.c \
+       ao_report.c \
+       ao_ignite.c \
+       ao_flight.c \
+       ao_kalman.c \
+       ao_sample.c \
+       ao_data.c \
+       ao_convert_pa.c \
+       ao_convert_volt.c \
+       ao_task.c \
+       ao_log.c \
+       ao_log_mini.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_timer.c \
+       ao_exti_stm.c \
+       ao_spi_stm.c \
+       ao_adc_stm.c \
+       ao_usb_stm.c \
+       ao_m25.c \
+       ao_ms5607.c \
+       ao_cc1200.c \
+       ao_telemetry.c \
+       ao_packet_slave.c \
+       ao_beep_stm.c \
+       ao_packet.c
+
+PRODUCT=TeleMini-v3.0
+PRODUCT_DEF=-DTELEMINI_V_3_0
+IDPRODUCT=0x0027
+
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+
+PROGNAME=telemini-v3.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telemini.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ)
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+$(OBJ): $(INC)
+
+load: $(PROG)
+       lpc-load $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h
new file mode 100644 (file)
index 0000000..351d28d
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define HAS_BEEP               1
+#define HAS_SERIAL_1           0
+#define HAS_BATTERY_REPORT     1
+
+#define AO_STACK_SIZE  448
+
+#define IS_FLASH_LOADER        0
+
+/* 48MHz clock based on 16MHz reference */
+//#define AO_HSI48     1
+#define AO_HSE                 16000000
+#define AO_RCC_CFGR_PLLMUL     STM_RCC_CFGR_PLLMUL_3
+#define AO_RCC_CFGR2_PLLDIV    STM_RCC_CFGR2_PREDIV_1
+#define AO_PLLMUL              3
+#define AO_PLLDIV              1
+
+/* HCLK = 48MHz */
+#define AO_AHB_PRESCALER       1
+#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
+
+/* APB = 40MHz */
+#define AO_APB_PRESCALER       1
+#define AO_RCC_CFGR_PPRE_DIV   STM_RCC_CFGR_PPRE_DIV_1
+
+#define HAS_USB                        1
+#define AO_USB_DIRECTIO                0
+#define AO_PA11_PA12_RMP       1
+#define AO_USB_FORCE_IDLE      1
+
+#define PACKET_HAS_SLAVE       1
+
+#define AO_LOG_FORMAT          AO_LOG_FORMAT_TELEMINI3
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       ((uint32_t) 112 * (uint32_t) 1024)
+
+#define HAS_BOOT_RADIO         0
+
+#define HAS_ACCEL              0
+#define HAS_GPS                        0
+#define HAS_RADIO              1
+#define HAS_RADIO_RATE         1
+#define HAS_FLIGHT             1
+#define HAS_EEPROM             1
+#define HAS_TELEMETRY          1
+#define AO_SEND_MINI           AO_TELEMETRY_MINI3
+#define HAS_APRS               0
+#define HAS_LOG                        1
+#define USE_INTERNAL_FLASH     0
+#define HAS_IGNITE             1
+#define HAS_IGNITE_REPORT      1
+#define AO_SMALL_ALTITUDE_TABLE        1
+
+/* Beeper is on Tim1 CH3 */
+#define BEEPER_CHANNEL         4
+#define BEEPER_TIMER           2
+#define BEEPER_PORT            (&stm_gpioa)
+#define BEEPER_PIN             3
+
+/* SPI */
+
+#define HAS_SPI_1              1
+#define SPI_1_PA5_PA6_PA7      1
+#define SPI_1_PB3_PB4_PB5      1
+#define SPI_1_OSPEEDR          STM_OSPEEDR_MEDIUM
+
+/* M25 */
+
+#define M25_MAX_CHIPS          1
+#define AO_M25_SPI_CS_PORT     (&stm_gpioa)
+#define AO_M25_SPI_CS_MASK     (1 << 4)
+#define AO_M25_SPI_BUS         AO_SPI_1_PA5_PA6_PA7
+
+/* MS5607 */
+
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT      (&stm_gpioa)
+#define AO_MS5607_CS_PIN       15
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT    (&stm_gpiob)
+#define AO_MS5607_MISO_PIN     4
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO_PIN)
+#define AO_MS5607_SPI_INDEX    AO_SPI_1_PB3_PB4_PB5
+#define AO_MS5607_SPI_SPEED    AO_SPI_SPEED_12MHz
+
+/* CC1200 */
+
+// #define AO_RADIO_CAL_DEFAULT        5695733
+#define AO_RADIO_CAL_DEFAULT   5695717
+
+#define AO_FEC_DEBUG           0
+#define CC1200_DEBUG           0
+#define AO_CC1200_SPI_CS_PORT  (&stm_gpiob)
+#define AO_CC1200_SPI_CS_PIN   0
+#define AO_CC1200_SPI_BUS      AO_SPI_1_PA5_PA6_PA7
+#define AO_CC1200_SPI          stm_spi1
+#define AO_CC1200_SPI_SPEED    AO_SPI_SPEED_12MHz
+
+#define AO_CC1200_INT_PORT             (&stm_gpiob)
+#define AO_CC1200_INT_PIN              1
+
+#define AO_CC1200_INT_GPIO     2
+#define AO_CC1200_INT_GPIO_IOCFG       CC1200_IOCFG2
+
+
+#define AO_DATA_RING           16
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC                        1
+
+#define AO_ADC_PIN0_PORT       (&stm_gpioa)    /* sense_m */
+#define AO_ADC_PIN0_PIN                0
+#define AO_ADC_PIN0_CH         0
+#define AO_ADC_PIN1_PORT       (&stm_gpioa)    /* sense_a */
+#define AO_ADC_PIN1_PIN                1
+#define AO_ADC_PIN1_CH         1
+#define AO_ADC_PIN2_PORT       (&stm_gpioa)    /* v_batt */
+#define AO_ADC_PIN2_PIN                2
+#define AO_ADC_PIN2_CH         2
+
+#define AO_ADC_RCC_AHBENR      ((1 << STM_RCC_AHBENR_IOPAEN))
+
+#define AO_NUM_ADC             3
+
+struct ao_adc {
+       int16_t         sense_m;
+       int16_t         sense_a;
+       int16_t         v_batt;
+};
+
+/*
+ * Igniter
+ */
+
+#define AO_IGNITER_CLOSED      400
+#define AO_IGNITER_OPEN                60
+
+#define AO_IGNITER_DROGUE_PORT (&stm_gpiob)
+#define AO_IGNITER_DROGUE_PIN  7
+#define AO_IGNITER_SET_DROGUE(v)       ao_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, AO_IGNITER_DROGUE, v)
+
+#define AO_IGNITER_MAIN_PORT   (&stm_gpiob)
+#define AO_IGNITER_MAIN_PIN    6
+#define AO_IGNITER_SET_MAIN(v)         ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v)
+
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense_m)
+
+#define AO_ADC_DUMP(p) \
+       printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \
+              (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)
+
+/*
+ * 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
diff --git a/src/telemini-v3.0/ao_telemini.c b/src/telemini-v3.0/ao_telemini.c
new file mode 100644 (file)
index 0000000..82c1acd
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+void
+main(void)
+{
+       ao_clock_init();
+       ao_task_init();
+       ao_timer_init();
+
+       ao_dma_init();
+       ao_spi_init();
+       ao_exti_init();
+
+       ao_adc_init();
+
+#if HAS_BEEP
+       ao_beep_init();
+#endif
+#if HAS_SERIAL_1
+       ao_serial_init();
+#endif
+#if HAS_USB
+       ao_usb_init();
+#endif
+       ao_cmd_init();
+
+       ao_ms5607_init();
+
+       ao_storage_init();
+       ao_flight_init();
+       ao_log_init();
+       ao_report_init();
+       ao_telemetry_init();
+       ao_radio_init();
+       ao_packet_slave_init(TRUE);
+       ao_igniter_init();
+       ao_config_init();
+
+       ao_start_scheduler();
+}
diff --git a/src/telemini-v3.0/flash-loader/Makefile b/src/telemini-v3.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..8b62855
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telemini-v3.0
+include $(TOPDIR)/stmf0/Makefile-flash.defs
diff --git a/src/telemini-v3.0/flash-loader/ao_pins.h b/src/telemini-v3.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..fea9a64
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_
+
+#include <ao_flash_stm_pins.h>
+
+/* beeper to 3.3V for boot loader mode */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioa
+#define AO_BOOT_APPLICATION_PIN                3
+#define AO_BOOT_APPLICATION_VALUE      0
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_DOWN
+
+/* USB */
+#define HAS_USB                        1
+#define AO_USB_DIRECTIO                0
+#define AO_PA11_PA12_RMP       1
+
+#endif /* _AO_PINS_H_ */
index 02e1d22b6c1b502ff92c71a11498084b5ed8c518..a22abe463e1ea50940a3ddb35fb7b123eed91556 100644 (file)
@@ -1,16 +1,16 @@
-vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product
+vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product:../lisp
 
 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_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_ms5607_convert_test ao_quaternion_test ao_lisp_test
 
 INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h
 
 KALMAN=make-kalman 
 
-CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -O0 -g -Wall
+CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall -DAO_LISP_TEST -no-pie
 
 all: $(PROGS) ao_aprs_data.wav
 
@@ -88,3 +88,12 @@ 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 3852668af9014e133f05ffa1aefa5c69859a10ac..941bf95471d1c14abfa891cd434ba951127f136c 100644 (file)
@@ -60,6 +60,20 @@ ao_aprs_bit(uint8_t bit)
 void
 ao_radio_send_aprs(ao_radio_fill_func fill);
 
+static void
+aprs_bit_debug(uint8_t tx_bit)
+{
+       fprintf (stderr, "bit %d\n", tx_bit);
+}
+
+static void
+aprs_byte_debug(uint8_t tx_byte)
+{
+       fprintf(stderr, "byte %02x\n", tx_byte);
+}
+#define APRS_BIT_DEBUG(x) aprs_bit_debug(x)
+#define APRS_BYTE_DEBUG(y) aprs_byte_debug(y)
+
 #include <ao_aprs.c>
 
 /*
@@ -103,7 +117,7 @@ audio_gap(int secs)
 // This is where we go after reset.
 int main(int argc, char **argv)
 {
-    audio_gap(1);
+//    audio_gap(1);
 
     ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000;
     ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000;
index bd7f2ff8196c2759af7d9adc9790bf71e6f816ea..25ddb48fefb6f982a4558eac59c99089e463f1e3 100644 (file)
@@ -58,6 +58,7 @@ int ao_gps_new;
 #define HAS_HMC5883            1
 #define HAS_BEEP               1
 #define AO_CONFIG_MAX_SIZE     1024
+#define AO_MMA655X_INVERT      0
 
 struct ao_adc {
        int16_t                 sense[AO_ADC_NUM_SENSE];
@@ -71,6 +72,7 @@ struct ao_adc {
 #define AO_ADC_NUM_SENSE       2
 #define HAS_MS5607             1
 #define HAS_MMA655X            1
+#define AO_MMA655X_INVERT      1
 #define HAS_BEEP               1
 #define AO_CONFIG_MAX_SIZE     1024
 
@@ -373,6 +375,8 @@ uint16_t    prev_tick;
 #define AO_PYRO_2      2
 #define AO_PYRO_3      3
 
+#define PYRO_DBG       1
+
 static void
 ao_pyro_pin_set(uint8_t pin, uint8_t value)
 {
diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h
new file mode 100644 (file)
index 0000000..9ff2e1f
--- /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; 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
new file mode 100644 (file)
index 0000000..68e3a20
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..e2eb0fa
--- /dev/null
@@ -0,0 +1,155 @@
+;
+; 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
+  )